difftreelog
test restructure
in: master
570 files changed
js-packages/.gitignorediffbeforeafterboth--- a/js-packages/.gitignore
+++ b/js-packages/.gitignore
@@ -1,8 +1,11 @@
/node_modules/
/*/dist/
-/*/tsconfig.tsbuildinfo
+/**/tsconfig.tsbuildinfo
properties.csv
erc721.csv
erc20.csv
.yarn/cache
-.yarn/install-state.gz
\ No newline at end of file
+.yarn/install-state.gz
+/scripts/metadata.json
+/**/*.js
+/**/*.d.ts
js-packages/package.jsondiffbeforeafterboth--- a/js-packages/package.json
+++ b/js-packages/package.json
@@ -2,6 +2,9 @@
"name": "unique-tests",
"version": "1.0.0",
"description": "Unique Chain Tests",
+ "author": "",
+ "license": "SEE LICENSE IN ../LICENSE",
+ "homepage": "",
"main": "",
"private": true,
"dependencies": {
@@ -29,6 +32,7 @@
"chai-subset": "^1.6.0",
"eslint": "^8.53.0",
"eslint-plugin-mocha": "^10.2.0",
+ "ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"mocha": {
@@ -38,16 +42,13 @@
]
},
"scripts": {
- "lint": "eslint --ext .ts,.js src/",
+ "lint": "eslint --ext .ts .",
"fix": "yarn lint --fix",
- "polkadot-types-fetch-metadata": "yarn ts-node --esm scripts/src/fetchMetadata.ts",
- "polkadot-types-from-defs": "ts-node --esm ./node_modules/.bin/polkadot-types-from-defs --endpoint types/src/metadata.json --input types/src/ --package .",
- "polkadot-types-from-chain": "ts-node --esm ./node_modules/.bin/polkadot-types-from-chain --endpoint types/src/metadata.json --output types/src/ --package .",
- "polkadot-types": "echo \"export default {}\" > types/src/lookup.ts && yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"
+ "polkadot-types-fetch-metadata": "yarn ts-node --esm scripts/fetchMetadata.ts",
+ "polkadot-types-from-defs": "ts-node --esm ./node_modules/.bin/polkadot-types-from-defs --endpoint scripts/metadata.json --input types/ --package .",
+ "polkadot-types-from-chain": "ts-node --esm ./node_modules/.bin/polkadot-types-from-chain --endpoint scripts/metadata.json --output types/ --package .",
+ "polkadot-types": "echo \"export default {}\" > types/lookup.ts && yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain && rm types/registry.ts"
},
- "author": "",
- "license": "SEE LICENSE IN ../LICENSE",
- "homepage": "",
"resolutions": {
"decode-uri-component": "^0.2.1"
},
js-packages/playgrounds/src/index.tsdiffbeforeafterbothno changes
js-packages/playgrounds/src/types.tsdiffbeforeafterboth--- a/js-packages/playgrounds/src/types.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-import type {IKeyringPair} from '@polkadot/types/types';
-
-export const NON_EXISTENT_COLLECTION_ID = 4_294_967_295;
-
-export const MILLISECS_PER_BLOCK = 12000;
-export const MINUTES = 60_000 / MILLISECS_PER_BLOCK;
-export const HOURS = MINUTES * 60;
-export const DAYS = HOURS * 24;
-
-export interface IEvent {
- section: string;
- method: string;
- index: [number, number] | string;
- data: any[];
- phase: {applyExtrinsic: number} | 'Initialization',
-}
-
-export interface IPhasicEvent {
- phase: any, // {ApplyExtrinsic: number} | 'Initialization',
- event: IEvent;
-}
-
-export interface ITransactionResult {
- status: 'Fail' | 'Success';
- result: {
- dispatchError: any,
- events: IPhasicEvent[];
- },
- blockHash: string,
- moduleError?: string | object;
-}
-
-export interface ISubscribeBlockEventsData {
- number: number;
- hash: string;
- timestamp: number;
- events: IEvent[];
-}
-
-export interface ILogger {
- log: (msg: any, level?: string) => void;
- level: {
- ERROR: 'ERROR';
- WARNING: 'WARNING';
- INFO: 'INFO';
- [key: string]: string;
- }
-}
-
-export interface IUniqueHelperLog {
- executedAt: number;
- executionTime: number;
- type: 'extrinsic' | 'rpc';
- status: 'Fail' | 'Success';
- call: string;
- params: any[];
- moduleError?: string;
- dispatchError?: any;
- events?: any;
-}
-
-export interface IApiListeners {
- connected?: (...args: any[]) => any;
- disconnected?: (...args: any[]) => any;
- error?: (...args: any[]) => any;
- ready?: (...args: any[]) => any;
- decorated?: (...args: any[]) => any;
-}
-
-export type ICrossAccountId = {
- Substrate: TSubstrateAccount;
-} | {
- Ethereum: TEthereumAccount;
-}
-
-export type ICrossAccountIdLower = {
- substrate: TSubstrateAccount;
-} | {
- ethereum: TEthereumAccount;
-};
-
-export interface IEthCrossAccountId {
- 0: TEthereumAccount;
- 1: TSubstrateAccount;
- eth: TEthereumAccount;
- sub: TSubstrateAccount;
-}
-
-export interface ICollectionLimits {
- accountTokenOwnershipLimit?: number | null;
- sponsoredDataSize?: number | null;
- sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;
- tokenLimit?: number | null;
- sponsorTransferTimeout?: number | null;
- sponsorApproveTimeout?: number | null;
- ownerCanTransfer?: boolean | null;
- ownerCanDestroy?: boolean | null;
- transfersEnabled?: boolean | null;
-}
-
-export interface INestingPermissions {
- tokenOwner?: boolean;
- collectionAdmin?: boolean;
- restricted?: number[] | null;
-}
-
-export interface ICollectionPermissions {
- access?: 'Normal' | 'AllowList';
- mintMode?: boolean;
- nesting?: INestingPermissions;
-}
-
-export interface IProperty {
- key: string;
- value?: string;
-}
-
-export interface ITokenPropertyPermission {
- key: string;
- permission: {
- mutable?: boolean;
- tokenOwner?: boolean;
- collectionAdmin?: boolean;
- }
-}
-
-export interface IToken {
- collectionId: number;
- tokenId: number;
-}
-
-export interface IBlock {
- extrinsics: IExtrinsic[]
- header: {
- parentHash: string,
- number: number,
- };
-}
-
-export interface IExtrinsic {
- isSigned: boolean,
- method: {
- method: string,
- section: string,
- args: any[]
- }
-}
-
-export interface ICollectionFlags {
- foreign: boolean,
- erc721metadata: boolean,
-}
-
-export enum CollectionFlag {
- None = 0,
- /// External collections can't be managed using `unique` api
- External = 1,
- /// Supports ERC721Metadata
- Erc721metadata = 64,
- /// Tokens in foreign collections can be transferred, but not burnt
- Foreign = 128,
-}
-
-export interface ICollectionCreationOptions {
- name?: string | number[];
- description?: string | number[];
- tokenPrefix?: string | number[];
- mode?: {
- nft?: null;
- refungible?: null;
- fungible?: number;
- }
- permissions?: ICollectionPermissions;
- properties?: IProperty[];
- tokenPropertyPermissions?: ITokenPropertyPermission[];
- limits?: ICollectionLimits;
- pendingSponsor?: ICrossAccountId;
- adminList?: ICrossAccountId[];
- flags?: number[] | CollectionFlag[] ,
-}
-
-export interface IChainProperties {
- ss58Format: number;
- tokenDecimals: number[];
- tokenSymbol: string[]
-}
-
-export interface ISubstrateBalance {
- free: bigint,
- reserved: bigint,
- frozen: bigint,
-}
-
-export interface IStakingInfo {
- block: bigint,
- amount: bigint,
-}
-
-export interface IPovInfo {
- proofSize: number,
- compactProofSize: number,
- compressedProofSize: number,
- results: any[],
- kv: any,
-}
-
-export interface ISchedulerOptions {
- scheduledId?: string,
- priority?: number,
- periodic?: {
- period: number,
- repetitions: number,
- },
-}
-
-export interface DemocracySplitAccount {
- aye: bigint,
- nay: bigint,
-}
-
-export type TSubstrateAccount = string;
-export type TEthereumAccount = string;
-export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
-export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
-export type TSiblingNetworkds = 'moonbeam' | 'moonriver' | 'acala' | 'karura' | 'westmint';
-export type TRelayNetworks = 'rococo' | 'westend';
-export type TNetworks = TUniqueNetworks | TSiblingNetworkds | TRelayNetworks;
-export type TSigner = IKeyringPair; // | 'string'
-export type TCollectionMode = 'nft' | 'rft' | 'ft';
js-packages/playgrounds/src/types.xcm.tsdiffbeforeafterboth--- a/js-packages/playgrounds/src/types.xcm.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-export interface AcalaAssetMetadata {
- name: string,
- symbol: string,
- decimals: number,
- minimalBalance: bigint,
-}
-
-export interface MoonbeamAssetInfo {
- location: any,
- metadata: {
- name: string,
- symbol: string,
- decimals: number,
- isFrozen: boolean,
- minimalBalance: bigint,
- },
- existentialDeposit: bigint,
- isSufficient: boolean,
- unitsPerSecond: bigint,
- numAssetsWeightHint: number,
-}
-
-export interface DemocracyStandardAccountVote {
- balance: bigint,
- vote: {
- aye: boolean,
- conviction: number,
- },
-}
-
-export interface IForeignAssetMetadata {
- name?: number | Uint8Array,
- symbol?: string,
- decimals?: number,
- minimalBalance?: bigint,
-}
\ No newline at end of file
js-packages/playgrounds/src/unique.dev.tsdiffbeforeafterboth--- a/js-packages/playgrounds/src/unique.dev.ts
+++ /dev/null
@@ -1,1547 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-import '@unique/opal-types/src/augment-api.js';
-import '@unique/opal-types/src/augment-types.js';
-import '@unique/opal-types/src/types-lookup.js';
-
-import {stringToU8a} from '@polkadot/util';
-import {blake2AsHex, encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto';
-import type {ChainHelperBaseConstructor, UniqueHelperConstructor} from './unique.js';
-import {UniqueHelper, ChainHelperBase, HelperGroup} from './unique.js';
-import {ApiPromise, Keyring, WsProvider} from '@polkadot/api';
-import * as defs from '@unique/opal-types/src/definitions.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import type {EventRecord} from '@polkadot/types/interfaces';
-import type {ICrossAccountId, ILogger, IPovInfo, ISchedulerOptions, ITransactionResult, TSigner} from './types.js';
-import type {FrameSystemEventRecord, StagingXcmV2TraitsError, StagingXcmV3TraitsOutcome} from '@polkadot/types/lookup';
-import type {SignerOptions, VoidFn} from '@polkadot/api/types';
-import {spawnSync} from 'child_process';
-import {AcalaHelper, AstarHelper, MoonbeamHelper, PolkadexHelper, RelayHelper, WestmintHelper, ForeignAssetsGroup, XcmGroup, XTokensGroup, TokensGroup} from './unique.xcm.js';
-import {CollectiveGroup, CollectiveMembershipGroup, DemocracyGroup, RankedCollectiveGroup, ReferendaGroup} from './unique.governance.js';
-import type {ICollectiveGroup, IFellowshipGroup} from './unique.governance.js';
-
-export class SilentLogger {
- log(_msg: any, _level: any): void { }
- level = {
- ERROR: 'ERROR' as const,
- WARNING: 'WARNING' as const,
- INFO: 'INFO' as const,
- };
-}
-
-export class SilentConsole {
- // TODO: Remove, this is temporary: Filter unneeded API output
- // (Jaco promised it will be removed in the next version)
- consoleErr: any;
- consoleLog: any;
- consoleWarn: any;
-
- constructor() {
- this.consoleErr = console.error;
- this.consoleLog = console.log;
- this.consoleWarn = console.warn;
- }
-
- enable() {
- const outFn = (printer: any) => (...args: any[]) => {
- for(const arg of args) {
- if(typeof arg !== 'string')
- continue;
- const skippedWarnings = ['1000:: Normal connection closure', 'Not decorating unknown runtime apis:', 'RPC methods not decorated:', 'Not decorating runtime apis', 'Bad input data provided to validate_transaction', 'account balance too low', '1006:: Abnormal Closure'];
- const needToSkip = skippedWarnings.reduce((a, b) => a || arg.includes(b), false);
- if(needToSkip || arg === 'Normal connection closure')
- return;
- }
- printer(...args);
- };
-
- console.error = outFn(this.consoleErr.bind(console));
- console.log = outFn(this.consoleLog.bind(console));
- console.warn = outFn(this.consoleWarn.bind(console));
- }
-
- disable() {
- console.error = this.consoleErr;
- console.log = this.consoleLog;
- console.warn = this.consoleWarn;
- }
-}
-
-export interface IEventHelper {
- section(): string;
-
- method(): string;
-
- wrapEvent(data: any[]): any;
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-function EventHelper(section: string, method: string, wrapEvent: (data: any[]) => any) {
- const helperClass = class implements IEventHelper {
- wrapEvent: (data: any[]) => any;
- _section: string;
- _method: string;
-
- constructor() {
- this.wrapEvent = wrapEvent;
- this._section = section;
- this._method = method;
- }
-
- section(): string {
- return this._section;
- }
-
- method(): string {
- return this._method;
- }
-
- filter(txres: ITransactionResult) {
- return txres.result.events.filter(e => e.event.section === section && e.event.method === method)
- .map(e => this.wrapEvent(e.event.data));
- }
-
- find(txres: ITransactionResult) {
- const e = txres.result.events.find(e => e.event.section === section && e.event.method === method);
- return e ? this.wrapEvent(e.event.data) : null;
- }
-
- expect(txres: ITransactionResult) {
- const e = this.find(txres);
- if(e) {
- return e;
- } else {
- throw Error(`Expected event ${section}.${method}`);
- }
- }
- };
-
- return helperClass;
-}
-
-function eventJsonData<T = any>(data: any[], index: number) {
- return data[index].toJSON() as T;
-}
-
-function eventHumanData(data: any[], index: number) {
- return data[index].toHuman();
-}
-
-function eventData<T = any>(data: any[], index: number) {
- return data[index] as T;
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-function EventSection(section: string) {
- return class Section {
- static section = section;
-
- static Method(name: string, wrapEvent: (data: any[]) => any = () => {}) {
- const helperClass = EventHelper(Section.section, name, wrapEvent);
- return new helperClass();
- }
- };
-}
-
-function schedulerSection(schedulerInstance: string) {
- return class extends EventSection(schedulerInstance) {
- static Dispatched = this.Method('Dispatched', data => ({
- task: eventJsonData(data, 0),
- id: eventHumanData(data, 1),
- result: data[2],
- }));
-
- static PriorityChanged = this.Method('PriorityChanged', data => ({
- task: eventJsonData(data, 0),
- priority: eventJsonData(data, 1),
- }));
- };
-}
-
-export class Event {
- static Democracy = class extends EventSection('democracy') {
- static Proposed = this.Method('Proposed', data => ({
- proposalIndex: eventJsonData<number>(data, 0),
- }));
-
- static ExternalTabled = this.Method('ExternalTabled');
-
- static Started = this.Method('Started', data => ({
- referendumIndex: eventJsonData<number>(data, 0),
- threshold: eventHumanData(data, 1),
- }));
-
- static Voted = this.Method('Voted', data => ({
- voter: eventJsonData(data, 0),
- referendumIndex: eventJsonData<number>(data, 1),
- vote: eventJsonData(data, 2),
- }));
-
- static Passed = this.Method('Passed', data => ({
- referendumIndex: eventJsonData<number>(data, 0),
- }));
-
- static ProposalCanceled = this.Method('ProposalCanceled', data => ({
- propIndex: eventJsonData<number>(data, 0),
- }));
-
- static Cancelled = this.Method('Cancelled', data => ({
- propIndex: eventJsonData<number>(data, 0),
- }));
-
- static Vetoed = this.Method('Vetoed', data => ({
- who: eventHumanData(data, 0),
- proposalHash: eventHumanData(data, 1),
- until: eventJsonData<number>(data, 1),
- }));
- };
-
- static Council = class extends EventSection('council') {
- static Proposed = this.Method('Proposed', data => ({
- account: eventHumanData(data, 0),
- proposalIndex: eventJsonData<number>(data, 1),
- proposalHash: eventHumanData(data, 2),
- threshold: eventJsonData<number>(data, 3),
- }));
- static Closed = this.Method('Closed', data => ({
- proposalHash: eventHumanData(data, 0),
- yes: eventJsonData<number>(data, 1),
- no: eventJsonData<number>(data, 2),
- }));
- static Executed = this.Method('Executed', data => ({
- proposalHash: eventHumanData(data, 0),
- }));
- };
-
- static TechnicalCommittee = class extends EventSection('technicalCommittee') {
- static Proposed = this.Method('Proposed', data => ({
- account: eventHumanData(data, 0),
- proposalIndex: eventJsonData<number>(data, 1),
- proposalHash: eventHumanData(data, 2),
- threshold: eventJsonData<number>(data, 3),
- }));
- static Closed = this.Method('Closed', data => ({
- proposalHash: eventHumanData(data, 0),
- yes: eventJsonData<number>(data, 1),
- no: eventJsonData<number>(data, 2),
- }));
- static Approved = this.Method('Approved', data => ({
- proposalHash: eventHumanData(data, 0),
- }));
- static Executed = this.Method('Executed', data => ({
- proposalHash: eventHumanData(data, 0),
- result: eventHumanData(data, 1),
- }));
- };
-
- static FellowshipReferenda = class extends EventSection('fellowshipReferenda') {
- static Submitted = this.Method('Submitted', data => ({
- referendumIndex: eventJsonData<number>(data, 0),
- trackId: eventJsonData<number>(data, 1),
- proposal: eventJsonData(data, 2),
- }));
-
- static Cancelled = this.Method('Cancelled', data => ({
- index: eventJsonData<number>(data, 0),
- tally: eventJsonData(data, 1),
- }));
- };
-
- static UniqueScheduler = schedulerSection('uniqueScheduler');
- static Scheduler = schedulerSection('scheduler');
-
- static XcmpQueue = class extends EventSection('xcmpQueue') {
- static XcmpMessageSent = this.Method('XcmpMessageSent', data => ({
- messageHash: eventJsonData(data, 0),
- }));
-
- static Success = this.Method('Success', data => ({
- messageHash: eventJsonData(data, 0),
- }));
-
- static Fail = this.Method('Fail', data => ({
- messageHash: eventJsonData(data, 0),
- outcome: eventData<StagingXcmV2TraitsError>(data, 2),
- }));
- };
-
- static DmpQueue = class extends EventSection('dmpQueue') {
- static ExecutedDownward = this.Method('ExecutedDownward', data => ({
- outcome: eventData<StagingXcmV3TraitsOutcome>(data, 2),
- }));
- };
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {
- return class extends Base {
- constructor(...args: any[]) {
- super(...args);
- }
-
- override async executeExtrinsic(
- sender: IKeyringPair,
- extrinsic: string,
- params: any[],
- expectSuccess?: boolean,
- options: Partial<SignerOptions> | null = null,
- ): Promise<ITransactionResult> {
- const call = this.constructApiCall(extrinsic, params);
- const result = await super.executeExtrinsic(
- sender,
- 'api.tx.sudo.sudo',
- [call],
- expectSuccess,
- options,
- );
-
- if(result.status === 'Fail') return result;
-
- const data = (result.result.events.find(x => x.event.section == 'sudo' && x.event.method == 'Sudid')?.event.data as any).sudoResult;
- if(data.isErr) {
- if(data.asErr.isModule) {
- const error = (result.result.events[1].event.data as any).sudoResult.asErr.asModule;
- const metaError = super.getApi()?.registry.findMetaError(error);
- throw new Error(`${metaError.section}.${metaError.name}`);
- } else if(data.asErr.isToken) {
- throw new Error(`Token: ${data.asErr.asToken}`);
- }
- // May be [object Object] in case of unhandled non-unit enum
- throw new Error(`Misc: ${data.asErr.toHuman()}`);
- }
- return result;
- }
- override async executeExtrinsicUncheckedWeight(
- sender: IKeyringPair,
- extrinsic: string,
- params: any[],
- expectSuccess?: boolean,
- options: Partial<SignerOptions> | null = null,
- ): Promise<ITransactionResult> {
- const call = this.constructApiCall(extrinsic, params);
- const result = await super.executeExtrinsic(
- sender,
- 'api.tx.sudo.sudoUncheckedWeight',
- [call, {refTime: 0, proofSize: 0}],
- expectSuccess,
- options,
- );
-
- if(result.status === 'Fail') return result;
-
- const data = (result.result.events.find(x => x.event.section == 'sudo' && x.event.method == 'Sudid')?.event.data as any).sudoResult;
- if(data.isErr) {
- if(data.asErr.isModule) {
- const error = (result.result.events[1].event.data as any).sudoResult.asErr.asModule;
- const metaError = super.getApi()?.registry.findMetaError(error);
- throw new Error(`${metaError.section}.${metaError.name}`);
- } else if(data.asErr.isToken) {
- throw new Error(`Token: ${data.asErr.asToken}`);
- }
- // May be [object Object] in case of unhandled non-unit enum
- throw new Error(`Misc: ${data.asErr.toHuman()}`);
- }
- return result;
- }
- };
-}
-
-class SchedulerGroup extends HelperGroup<UniqueHelper> {
- constructor(helper: UniqueHelper) {
- super(helper);
- }
-
- cancelScheduled(signer: TSigner, scheduledId: string) {
- return this.helper.executeExtrinsic(
- signer,
- 'api.tx.scheduler.cancelNamed',
- [scheduledId],
- true,
- );
- }
-
- changePriority(signer: TSigner, scheduledId: string, priority: number) {
- return this.helper.executeExtrinsic(
- signer,
- 'api.tx.scheduler.changeNamedPriority',
- [scheduledId, priority],
- true,
- );
- }
-
- scheduleAt<T extends DevUniqueHelper>(
- executionBlockNumber: number,
- options: ISchedulerOptions = {},
- ) {
- return this.schedule<T>('schedule', executionBlockNumber, options);
- }
-
- scheduleAfter<T extends DevUniqueHelper>(
- blocksBeforeExecution: number,
- options: ISchedulerOptions = {},
- ) {
- return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);
- }
-
- schedule<T extends UniqueHelper>(
- scheduleFn: 'schedule' | 'scheduleAfter',
- blocksNum: number,
- options: ISchedulerOptions = {},
- ) {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);
- return this.helper.clone(ScheduledHelperType, {
- scheduleFn,
- blocksNum,
- options,
- }) as T;
- }
-}
-
-class CollatorSelectionGroup extends HelperGroup<UniqueHelper> {
- //todo:collator documentation
- addInvulnerable(signer: TSigner, address: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.addInvulnerable', [address]);
- }
-
- removeInvulnerable(signer: TSigner, address: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.removeInvulnerable', [address]);
- }
-
- async getInvulnerables(): Promise<string[]> {
- return (await this.helper.callRpc('api.query.collatorSelection.invulnerables')).map((x: any) => x.toHuman());
- }
-
- /** and also total max invulnerables */
- maxCollators(): number {
- return (this.helper.getApi().consts.configuration.defaultCollatorSelectionMaxCollators.toJSON() as number);
- }
-
- async getDesiredCollators(): Promise<number> {
- return (await this.helper.callRpc('api.query.configuration.collatorSelectionDesiredCollatorsOverride')).toNumber();
- }
-
- setLicenseBond(signer: TSigner, amount: bigint) {
- return this.helper.executeExtrinsic(signer, 'api.tx.configuration.setCollatorSelectionLicenseBond', [amount]);
- }
-
- async getLicenseBond(): Promise<bigint> {
- return (await this.helper.callRpc('api.query.configuration.collatorSelectionLicenseBondOverride')).toBigInt();
- }
-
- obtainLicense(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.getLicense', []);
- }
-
- releaseLicense(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.releaseLicense', []);
- }
-
- forceReleaseLicense(signer: TSigner, released: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.forceReleaseLicense', [released]);
- }
-
- async hasLicense(address: string): Promise<bigint> {
- return (await this.helper.callRpc('api.query.collatorSelection.licenseDepositOf', [address])).toBigInt();
- }
-
- onboard(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.onboard', []);
- }
-
- offboard(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.offboard', []);
- }
-
- async getCandidates(): Promise<string[]> {
- return (await this.helper.callRpc('api.query.collatorSelection.candidates')).map((x: any) => x.toHuman());
- }
-}
-
-export class DevUniqueHelper extends UniqueHelper {
- /**
- * Arrange methods for tests
- */
- arrange: ArrangeGroup;
- wait: WaitGroup;
- admin: AdminGroup;
- session: SessionGroup;
- testUtils: TestUtilGroup;
- foreignAssets: ForeignAssetsGroup;
- xcm: XcmGroup<DevUniqueHelper>;
- xTokens: XTokensGroup<DevUniqueHelper>;
- tokens: TokensGroup<DevUniqueHelper>;
- scheduler: SchedulerGroup;
- collatorSelection: CollatorSelectionGroup;
- council: ICollectiveGroup;
- technicalCommittee: ICollectiveGroup;
- fellowship: IFellowshipGroup;
- democracy: DemocracyGroup;
-
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? DevUniqueHelper;
-
- super(logger, options);
- this.arrange = new ArrangeGroup(this);
- this.wait = new WaitGroup(this);
- this.admin = new AdminGroup(this);
- this.testUtils = new TestUtilGroup(this);
- this.session = new SessionGroup(this);
- this.foreignAssets = new ForeignAssetsGroup(this);
- this.xcm = new XcmGroup(this, 'polkadotXcm');
- this.xTokens = new XTokensGroup(this);
- this.tokens = new TokensGroup(this);
- this.scheduler = new SchedulerGroup(this);
- this.collatorSelection = new CollatorSelectionGroup(this);
- this.council = {
- collective: new CollectiveGroup(this, 'council'),
- membership: new CollectiveMembershipGroup(this, 'councilMembership'),
- };
- this.technicalCommittee = {
- collective: new CollectiveGroup(this, 'technicalCommittee'),
- membership: new CollectiveMembershipGroup(this, 'technicalCommitteeMembership'),
- };
- this.fellowship = {
- collective: new RankedCollectiveGroup(this, 'fellowshipCollective'),
- referenda: new ReferendaGroup(this, 'fellowshipReferenda'),
- };
- this.democracy = new DemocracyGroup(this);
- }
-
- override async connect(wsEndpoint: string, _listeners?: any): Promise<void> {
- if(!wsEndpoint) throw new Error('wsEndpoint was not set');
- const wsProvider = new WsProvider(wsEndpoint);
- this.api = new ApiPromise({
- provider: wsProvider,
- signedExtensions: {
- ContractHelpers: {
- extrinsic: {},
- payload: {},
- },
- CheckMaintenance: {
- extrinsic: {},
- payload: {},
- },
- DisableIdentityCalls: {
- extrinsic: {},
- payload: {},
- },
- FakeTransactionFinalizer: {
- extrinsic: {},
- payload: {},
- },
- },
- rpc: {
- unique: defs.unique.rpc,
- appPromotion: defs.appPromotion.rpc,
- povinfo: defs.povinfo.rpc,
- eth: {
- feeHistory: {
- description: 'Dummy',
- params: [],
- type: 'u8',
- },
- maxPriorityFeePerGas: {
- description: 'Dummy',
- params: [],
- type: 'u8',
- },
- },
- },
- });
- await this.api.isReadyOrError;
- this.network = await UniqueHelper.detectNetwork(this.api);
- this.wsEndpoint = wsEndpoint;
- }
- getSudo<T extends DevUniqueHelper>() {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- const SudoHelperType = SudoHelper(this.helperBase);
- return this.clone(SudoHelperType) as T;
- }
-}
-
-export class DevRelayHelper extends RelayHelper {
- wait: WaitGroup;
-
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? DevRelayHelper;
-
- super(logger, options);
- this.wait = new WaitGroup(this);
- }
-
- getSudo() {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- const SudoHelperType = SudoHelper(this.helperBase);
- return this.clone(SudoHelperType) as DevRelayHelper;
- }
-}
-
-export class DevWestmintHelper extends WestmintHelper {
- wait: WaitGroup;
-
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? DevWestmintHelper;
-
- super(logger, options);
- this.wait = new WaitGroup(this);
- }
-}
-
-export class DevStatemineHelper extends DevWestmintHelper {}
-
-export class DevStatemintHelper extends DevWestmintHelper {}
-
-export class DevMoonbeamHelper extends MoonbeamHelper {
- account: MoonbeamAccountGroup;
- wait: WaitGroup;
- fastDemocracy: MoonbeamFastDemocracyGroup;
-
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? DevMoonbeamHelper;
- options.notePreimagePallet = options.notePreimagePallet ?? 'preimage';
-
- super(logger, options);
- this.account = new MoonbeamAccountGroup(this);
- this.wait = new WaitGroup(this);
- this.fastDemocracy = new MoonbeamFastDemocracyGroup(this);
- }
-}
-
-export class DevMoonriverHelper extends DevMoonbeamHelper {
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.notePreimagePallet = options.notePreimagePallet ?? 'preimage';
- super(logger, options);
- }
-}
-
-export class DevAstarHelper extends AstarHelper {
- wait: WaitGroup;
-
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? DevAstarHelper;
-
- super(logger, options);
- this.wait = new WaitGroup(this);
- }
-
- getSudo<T extends AstarHelper>() {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- const SudoHelperType = SudoHelper(this.helperBase);
- return this.clone(SudoHelperType) as T;
- }
-}
-
-export class DevShidenHelper extends DevAstarHelper { }
-
-export class DevAcalaHelper extends AcalaHelper {
- wait: WaitGroup;
-
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? DevAcalaHelper;
-
- super(logger, options);
- this.wait = new WaitGroup(this);
- }
- getSudo() {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- const SudoHelperType = SudoHelper(this.helperBase);
- return this.clone(SudoHelperType) as DevAcalaHelper;
- }
-}
-
-export class DevPolkadexHelper extends PolkadexHelper {
- wait: WaitGroup;
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
- options.helperBase = options.helperBase ?? PolkadexHelper;
-
- super(logger, options);
- this.wait = new WaitGroup(this);
- }
-
- getSudo() {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- const SudoHelperType = SudoHelper(this.helperBase);
- return this.clone(SudoHelperType) as DevPolkadexHelper;
- }
-}
-
-export class DevKaruraHelper extends DevAcalaHelper {}
-
-export class ArrangeGroup {
- helper: DevUniqueHelper;
-
- scheduledIdSlider = 0;
-
- constructor(helper: DevUniqueHelper) {
- this.helper = helper;
- }
-
- /**
- * Generates accounts with the specified UNQ token balance
- * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.
- * @param donor donor account for balances
- * @returns array of newly created accounts
- * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor);
- */
- createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {
- let nonce = await this.helper.chain.getNonce(donor.address);
- const wait = new WaitGroup(this.helper);
- const ss58Format = this.helper.chain.getChainProperties().ss58Format;
- const tokenNominal = this.helper.balance.getOneTokenNominal();
- const transactions = [];
- const accounts: IKeyringPair[] = [];
- for(const balance of balances) {
- const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
- accounts.push(recipient);
- if(balance !== 0n) {
- const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, balance * tokenNominal]);
- transactions.push(this.helper.signTransaction(donor, tx, {nonce}, 'account generation'));
- nonce++;
- }
- }
-
- await Promise.all(transactions).catch(_e => {});
-
- //#region TODO remove this region, when nonce problem will be solved
- const checkBalances = async () => {
- let isSuccess = true;
- for(let i = 0; i < balances.length; i++) {
- const balance = await this.helper.balance.getSubstrate(accounts[i].address);
- if(balance !== balances[i] * tokenNominal) {
- isSuccess = false;
- break;
- }
- }
- return isSuccess;
- };
-
- let accountsCreated = false;
- const maxBlocksChecked = await this.helper.arrange.isDevNode() ? 50 : 5;
- // checkBalances retry up to 5-50 blocks
- for(let index = 0; index < maxBlocksChecked; index++) {
- accountsCreated = await checkBalances();
- if(accountsCreated) break;
- await wait.newBlocks(1);
- }
-
- if(!accountsCreated) throw Error('Accounts generation failed');
- //#endregion
-
- return accounts;
- };
-
- // TODO combine this method and createAccounts into one
- createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {
- const createAsManyAsCan = async () => {
- let transactions: any = [];
- const accounts: IKeyringPair[] = [];
- let nonce = await this.helper.chain.getNonce(donor.address);
- const tokenNominal = this.helper.balance.getOneTokenNominal();
- const ss58Format = this.helper.chain.getChainProperties().ss58Format;
- for(let i = 0; i < accountsToCreate; i++) {
- if(i === 500) { // if there are too many accounts to create
- await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled
- transactions = []; //
- nonce = await this.helper.chain.getNonce(donor.address); // update nonce
- }
- const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
- accounts.push(recipient);
- if(withBalance !== 0n) {
- const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, withBalance * tokenNominal]);
- transactions.push(this.helper.signTransaction(donor, tx, {nonce}, 'account generation'));
- nonce++;
- }
- }
-
- const fullfilledAccounts = [];
- await Promise.allSettled(transactions);
- for(const account of accounts) {
- const accountBalance = await this.helper.balance.getSubstrate(account.address);
- if(accountBalance === withBalance * tokenNominal) {
- fullfilledAccounts.push(account);
- }
- }
- return fullfilledAccounts;
- };
-
-
- const crowd: IKeyringPair[] = [];
- // do up to 5 retries
- for(let index = 0; index < 5 && accountsToCreate !== 0; index++) {
- const asManyAsCan = await createAsManyAsCan();
- crowd.push(...asManyAsCan);
- accountsToCreate -= asManyAsCan.length;
- }
-
- if(accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);
-
- return crowd;
- };
-
- /**
- * Generates one account with zero balance
- * @returns the newly generated account
- * @example const account = await helper.arrange.createEmptyAccount();
- */
- createEmptyAccount = (): IKeyringPair => {
- const ss58Format = this.helper.chain.getChainProperties().ss58Format;
- return this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
- };
-
- isDevNode = async () => {
- let blockNumber = (await this.helper.callRpc('api.query.system.number')).toJSON();
- if(blockNumber == 0) {
- await this.helper.wait.newBlocks(1);
- blockNumber = (await this.helper.callRpc('api.query.system.number')).toJSON();
- }
- const block2 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])]);
- const block1 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber - 1])]);
- const findCreationDate = (block: any) => {
- const humanBlock = block.toHuman();
- let date;
- humanBlock.block.extrinsics.forEach((ext: any) => {
- if(ext.method.section === 'timestamp') {
- date = Number(ext.method.args.now.replaceAll(',', ''));
- }
- });
- return date;
- };
- const block1date = await findCreationDate(block1);
- const block2date = await findCreationDate(block2);
- if(block2date! - block1date! < 9000) return true;
- return false;
- };
-
- async calculcateFee(payer: ICrossAccountId, promise: () => Promise<any>): Promise<bigint> {
- const address = 'Substrate' in payer ? payer.Substrate : this.helper.address.ethToSubstrate(payer.Ethereum);
- let balance = await this.helper.balance.getSubstrate(address);
-
- await promise();
-
- balance -= await this.helper.balance.getSubstrate(address);
-
- return balance;
- }
-
- async calculatePoVInfo(txs: any[]): Promise<IPovInfo> {
- const rawPovInfo = await this.helper.callRpc('api.rpc.povinfo.estimateExtrinsicPoV', [txs]);
-
- const kvJson: {[key: string]: string} = {};
-
- for(const kv of rawPovInfo.keyValues) {
- kvJson[kv.key.toHex()] = kv.value.toHex();
- }
-
- const kvStr = JSON.stringify(kvJson);
-
- const chainql = spawnSync(
- 'chainql',
- [
- `--tla-code=data=${kvStr}`,
- '-e', `function(data) cql.dump(cql.chain("${this.helper.getEndpoint()}").latest._meta, data, {omit_empty:true})`,
- ],
- );
-
- if(!chainql.stdout) {
- throw Error('unable to get an output from the `chainql`');
- }
-
- return {
- proofSize: rawPovInfo.proofSize.toNumber(),
- compactProofSize: rawPovInfo.compactProofSize.toNumber(),
- compressedProofSize: rawPovInfo.compressedProofSize.toNumber(),
- results: rawPovInfo.results,
- kv: JSON.parse(chainql.stdout.toString()),
- };
- }
-
- calculatePalletAddress(palletId: any) {
- const address = stringToU8a(('modl' + palletId).padEnd(32, '\0'));
- return encodeAddress(address, this.helper.chain.getChainProperties().ss58Format);
- }
-
- makeScheduledIds(num: number): string[] {
- function makeId(slider: number) {
- const scheduledIdSize = 64;
- const hexId = slider.toString(16);
- const prefixSize = scheduledIdSize - hexId.length;
-
- const scheduledId = '0x' + '0'.repeat(prefixSize) + hexId;
-
- return scheduledId;
- }
-
- const ids = [];
- for(let i = 0; i < num; i++) {
- ids.push(makeId(this.scheduledIdSlider));
- this.scheduledIdSlider += 1;
- }
-
- return ids;
- }
-
- makeScheduledId(): string {
- return (this.makeScheduledIds(1))[0];
- }
-
- async captureEvents(eventSection: string, eventMethod: string): Promise<EventCapture> {
- const capture = new EventCapture(this.helper, eventSection, eventMethod);
- await capture.startCapture();
-
- return capture;
- }
-
- makeXcmProgramWithdrawDeposit(beneficiary: Uint8Array, id: any, amount: bigint) {
- return {
- V2: [
- {
- WithdrawAsset: [
- {
- id,
- fun: {
- Fungible: amount,
- },
- },
- ],
- },
- {
- BuyExecution: {
- fees: {
- id,
- fun: {
- Fungible: amount,
- },
- },
- weightLimit: 'Unlimited',
- },
- },
- {
- DepositAsset: {
- assets: {
- Wild: 'All',
- },
- maxAssets: 1,
- beneficiary: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: beneficiary,
- },
- },
- },
- },
- },
- },
- ],
- };
- }
-
- makeXcmProgramReserveAssetDeposited(beneficiary: Uint8Array, id: any, amount: bigint) {
- return {
- V2: [
- {
- ReserveAssetDeposited: [
- {
- id,
- fun: {
- Fungible: amount,
- },
- },
- ],
- },
- {
- BuyExecution: {
- fees: {
- id,
- fun: {
- Fungible: amount,
- },
- },
- weightLimit: 'Unlimited',
- },
- },
- {
- DepositAsset: {
- assets: {
- Wild: 'All',
- },
- maxAssets: 1,
- beneficiary: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: beneficiary,
- },
- },
- },
- },
- },
- },
- ],
- };
- }
-
- makeUnpaidSudoTransactProgram(info: {weightMultiplier: number, call: string}) {
- return {
- V3: [
- {
- UnpaidExecution: {
- weightLimit: 'Unlimited',
- checkOrigin: null,
- },
- },
- {
- Transact: {
- originKind: 'Superuser',
- requireWeightAtMost: {
- refTime: info.weightMultiplier * 200000000,
- proofSize: info.weightMultiplier * 3000,
- },
- call: {
- encoded: info.call,
- },
- },
- },
- ],
- };
- }
-}
-
-class MoonbeamAccountGroup {
- helper: MoonbeamHelper;
-
- keyring: Keyring;
- _alithAccount: IKeyringPair;
- _baltatharAccount: IKeyringPair;
- _dorothyAccount: IKeyringPair;
-
- constructor(helper: MoonbeamHelper) {
- this.helper = helper;
-
- this.keyring = new Keyring({type: 'ethereum'});
- const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';
- const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';
- const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';
-
- this._alithAccount = this.keyring.addFromUri(alithPrivateKey, undefined, 'ethereum');
- this._baltatharAccount = this.keyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');
- this._dorothyAccount = this.keyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');
- }
-
- alithAccount() {
- return this._alithAccount;
- }
-
- baltatharAccount() {
- return this._baltatharAccount;
- }
-
- dorothyAccount() {
- return this._dorothyAccount;
- }
-
- create() {
- return this.keyring.addFromUri(mnemonicGenerate());
- }
-}
-
-class MoonbeamFastDemocracyGroup {
- helper: DevMoonbeamHelper;
-
- constructor(helper: DevMoonbeamHelper) {
- this.helper = helper;
- }
-
- async executeProposal(proposalDesciption: string, encodedProposal: string) {
- const proposalHash = blake2AsHex(encodedProposal);
-
- const alithAccount = this.helper.account.alithAccount();
- const baltatharAccount = this.helper.account.baltatharAccount();
- const dorothyAccount = this.helper.account.dorothyAccount();
-
- const councilVotingThreshold = 2;
- const technicalCommitteeThreshold = 2;
- const fastTrackVotingPeriod = 3;
- const fastTrackDelayPeriod = 0;
-
- console.log(`[democracy] executing '${proposalDesciption}' proposal`);
-
- // >>> Propose external motion through council >>>
- console.log('\t* Propose external motion through council.......');
- const externalMotion = this.helper.democracy.externalProposeMajority({Inline: encodedProposal});
- const encodedMotion = externalMotion?.method.toHex() || '';
- const motionHash = blake2AsHex(encodedMotion);
- console.log('\t* Motion hash is %s', motionHash);
-
- await this.helper.collective.council.propose(
- baltatharAccount,
- councilVotingThreshold,
- externalMotion,
- externalMotion.encodedLength,
- );
-
- const councilProposalIdx = await this.helper.collective.council.proposalCount() - 1;
- await this.helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
- await this.helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
-
- await this.helper.collective.council.close(
- dorothyAccount,
- motionHash,
- councilProposalIdx,
- {
- refTime: 1_000_000_000,
- proofSize: 1_000_000,
- },
- externalMotion.encodedLength,
- );
- console.log('\t* Propose external motion through council.......DONE');
- // <<< Propose external motion through council <<<
-
- // >>> Fast track proposal through technical committee >>>
- console.log('\t* Fast track proposal through technical committee.......');
- const fastTrack = this.helper.democracy.fastTrack(proposalHash, fastTrackVotingPeriod, fastTrackDelayPeriod);
- const encodedFastTrack = fastTrack?.method.toHex() || '';
- const fastTrackHash = blake2AsHex(encodedFastTrack);
- console.log('\t* FastTrack hash is %s', fastTrackHash);
-
- await this.helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);
-
- const techProposalIdx = await this.helper.collective.techCommittee.proposalCount() - 1;
- await this.helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
- await this.helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
-
- await this.helper.collective.techCommittee.close(
- baltatharAccount,
- fastTrackHash,
- techProposalIdx,
- {
- refTime: 1_000_000_000,
- proofSize: 1_000_000,
- },
- fastTrack.encodedLength,
- );
- console.log('\t* Fast track proposal through technical committee.......DONE');
- // <<< Fast track proposal through technical committee <<<
-
- const democracyStarted = await this.helper.wait.expectEvent(3, Event.Democracy.Started);
- const referendumIndex = democracyStarted.referendumIndex;
-
- // >>> Referendum voting >>>
- console.log(`\t* Referendum #${referendumIndex} voting.......`);
- await this.helper.democracy.referendumVote(dorothyAccount, referendumIndex, {
- balance: 10_000_000_000_000_000_000n,
- vote: {aye: true, conviction: 1},
- });
- console.log(`\t* Referendum #${referendumIndex} voting.......DONE`);
- // <<< Referendum voting <<<
-
- // Wait the proposal to pass
- await this.helper.wait.expectEvent(3, Event.Democracy.Passed, event => event.referendumIndex == referendumIndex);
-
- await this.helper.wait.newBlocks(1);
-
- console.log(`[democracy] executing '${proposalDesciption}' proposal.......DONE`);
- }
-}
-
-class WaitGroup {
- helper: ChainHelperBase;
-
- constructor(helper: ChainHelperBase) {
- this.helper = helper;
- }
-
- sleep(milliseconds: number) {
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
- }
-
- private async waitWithTimeout(promise: Promise<any>, timeout: number) {
- let isBlock = false;
- promise.then(() => isBlock = true).catch(() => isBlock = true);
- let totalTime = 0;
- const step = 100;
- while(!isBlock) {
- await this.sleep(step);
- totalTime += step;
- if(totalTime >= timeout) throw Error('Blocks production failed');
- }
- return promise;
- }
-
- /**
- * Launch some async operation, or throw an error after some time. Note that it will still continue executing after the timeout.
- * @param promise async operation to race against the timeout
- * @param timeoutMS time after which to time out
- * @param timeoutError error message to throw
- * @returns promise of the same type the operation had
- */
- withTimeout<T>(
- promise: Promise<T>,
- timeoutMS = 30000,
- timeoutError = 'The operation has timed out!',
- ): Promise<T> {
- const timeout = new Promise<never>((_, reject) => {
- setTimeout(() => {
- reject(new Error(timeoutError));
- }, timeoutMS);
- });
-
- return Promise.race<T>([promise, timeout]).catch(e => {throw new Error(e);});
- }
-
- /**
- * Wait for specified number of blocks
- * @param blocksCount number of blocks to wait
- * @returns
- */
- async newBlocks(blocksCount = 1, timeout?: number): Promise<void> {
- timeout = timeout ?? blocksCount * 60_000;
- // eslint-disable-next-line no-async-promise-executor
- const promise = new Promise<void>(async (resolve) => {
- const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(() => {
- if(blocksCount > 0) {
- blocksCount--;
- } else {
- unsubscribe();
- resolve();
- }
- });
- });
- await this.waitWithTimeout(promise, timeout);
- return promise;
- }
-
- /**
- * Wait for the specified number of sessions to pass.
- * Only applicable if the Session pallet is turned on.
- * @param sessionCount number of sessions to wait
- * @param blockTimeout time in ms until panicking that the chain has stopped producing blocks
- * @returns
- */
- async newSessions(sessionCount = 1, blockTimeout = 60000): Promise<void> {
- console.log(`Waiting for ${sessionCount} new session${sessionCount > 1 ? 's' : ''}.`
- + ' This might take a while -- check SessionPeriod in pallet_session::Config for session time.');
-
- const expectedSessionIndex = await (this.helper as DevUniqueHelper).session.getIndex() + sessionCount;
- let currentSessionIndex = -1;
-
- while(currentSessionIndex < expectedSessionIndex) {
- // eslint-disable-next-line no-async-promise-executor
- currentSessionIndex = await this.withTimeout(new Promise(async (resolve) => {
- await this.newBlocks(1);
- const res = await (this.helper as DevUniqueHelper).session.getIndex();
- resolve(res);
- }), blockTimeout, 'The chain has stopped producing blocks!');
- }
- }
-
- async forParachainBlockNumber(blockNumber: bigint | number, timeout?: number) {
- timeout = timeout ?? 30 * 60 * 1000;
- // eslint-disable-next-line no-async-promise-executor
- const promise = new Promise<void>(async (resolve) => {
- const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads((data: any) => {
- if(data.number.toNumber() >= blockNumber) {
- unsubscribe();
- resolve();
- }
- });
- });
- await this.waitWithTimeout(promise, timeout);
- return promise;
- }
-
- async forRelayBlockNumber(blockNumber: bigint | number, timeout?: number) {
- timeout = timeout ?? 30 * 60 * 1000;
- // eslint-disable-next-line no-async-promise-executor
- const promise = new Promise<void>(async (resolve) => {
- const unsubscribe = await this.helper.getApi().query.parachainSystem.validationData((data: any) => {
- if(data.value.relayParentNumber.toNumber() >= blockNumber) {
- // @ts-ignore
- unsubscribe();
- resolve();
- }
- });
- });
- await this.waitWithTimeout(promise, timeout);
- return promise;
- }
-
- noScheduledTasks() {
- const api = this.helper.getApi();
-
- // eslint-disable-next-line no-async-promise-executor
- const promise = new Promise<void>(async resolve => {
- const unsubscribe = await api.rpc.chain.subscribeNewHeads(async () => {
- const areThereScheduledTasks = await api.query.scheduler.lookup.entries();
-
- if(areThereScheduledTasks.length == 0) {
- unsubscribe();
- resolve();
- }
- });
- });
-
- return promise;
- }
-
- parachainBlockMultiplesOf(val: bigint) {
- // eslint-disable-next-line no-async-promise-executor
- const promise = new Promise<void>(async resolve => {
- const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads((data: any) => {
- if(data.number.toBigInt() % val == 0n) {
- console.log(`from waiter: ${data.number.toBigInt()}`);
- unsubscribe();
- resolve();
- }
- });
- });
- return promise;
- }
-
- event<T extends IEventHelper>(
- maxBlocksToWait: number,
- eventHelper: T,
- filter: (_: any) => boolean = () => true,
- ): any {
- // eslint-disable-next-line no-async-promise-executor
- const promise = new Promise<T | null>(async (resolve) => {
- const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(async header => {
- const blockNumber = header.number.toJSON();
- const blockHash = header.hash;
- const eventIdStr = `${eventHelper.section()}.${eventHelper.method()}`;
- const waitLimitStr = `wait blocks remaining: ${maxBlocksToWait}`;
-
- this.helper.logger.log(`[Block #${blockNumber}] Waiting for event \`${eventIdStr}\` (${waitLimitStr})`);
-
- const apiAt = await this.helper.getApi().at(blockHash);
- const eventRecords = (await apiAt.query.system.events()) as any;
-
- const neededEvent = eventRecords.toArray()
- .filter((r: FrameSystemEventRecord) => r.event.section == eventHelper.section() && r.event.method == eventHelper.method())
- .map((r: FrameSystemEventRecord) => eventHelper.wrapEvent(r.event.data))
- .find(filter);
-
- if(neededEvent) {
- unsubscribe();
- resolve(neededEvent);
- } else if(maxBlocksToWait > 0) {
- maxBlocksToWait--;
- } else {
- this.helper.logger.log(`Eligible event \`${eventIdStr}\` is NOT found.
- The wait lasted until block ${blockNumber} inclusive`);
- unsubscribe();
- resolve(null);
- }
- });
- });
- return promise;
- }
-
- async expectEvent<T extends IEventHelper>(
- maxBlocksToWait: number,
- eventHelper: T,
- filter: (e: any) => boolean = () => true,
- ) {
- const e = await this.event(maxBlocksToWait, eventHelper, filter);
- if(e == null) {
- throw Error(`The event '${eventHelper.section()}.${eventHelper.method()}' is expected`);
- } else {
- return e;
- }
- }
-}
-
-class SessionGroup {
- helper: ChainHelperBase;
-
- constructor(helper: ChainHelperBase) {
- this.helper = helper;
- }
-
- //todo:collator documentation
- async getIndex(): Promise<number> {
- return (await this.helper.callRpc('api.query.session.currentIndex', [])).toNumber();
- }
-
- newSessions(sessionCount = 1, blockTimeout = 24000): Promise<void> {
- return (this.helper as DevUniqueHelper).wait.newSessions(sessionCount, blockTimeout);
- }
-
- setOwnKeys(signer: TSigner, key: string) {
- return this.helper.executeExtrinsic(
- signer,
- 'api.tx.session.setKeys',
- [key, '0x0'],
- true,
- );
- }
-
- setOwnKeysFromAddress(signer: TSigner) {
- return this.setOwnKeys(signer, '0x' + Buffer.from(signer.addressRaw).toString('hex'));
- }
-}
-
-class TestUtilGroup {
- helper: DevUniqueHelper;
-
- constructor(helper: DevUniqueHelper) {
- this.helper = helper;
- }
-
- async enable(testUtilsPalletName: string) {
- if(this.helper.fetchMissingPalletNames([testUtilsPalletName]).length != 0) {
- return;
- }
-
- const signer = this.helper.util.fromSeed('//Alice');
- await this.helper.getSudo<DevUniqueHelper>().executeExtrinsic(signer, 'api.tx.testUtils.enable', [], true);
- }
-
- async setTestValue(signer: TSigner, testVal: number) {
- await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValue', [testVal], true);
- }
-
- async incTestValue(signer: TSigner) {
- await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.incTestValue', [], true);
- }
-
- async setTestValueAndRollback(signer: TSigner, testVal: number) {
- await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValueAndRollback', [testVal], true);
- }
-
- async testValue(blockIdx?: number) {
- const api = blockIdx
- ? await this.helper.getApi().at(await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockIdx]))
- : this.helper.getApi();
-
- return (await api.query.testUtils.testValue()).toJSON();
- }
-
- async justTakeFee(signer: TSigner) {
- await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.justTakeFee', [], true);
- }
-
- async selfCancelingInc(signer: TSigner, scheduledId: string, maxTestVal: number) {
- await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.selfCancelingInc', [scheduledId, maxTestVal], true);
- }
-}
-
-class EventCapture {
- helper: DevUniqueHelper;
- eventSection: string;
- eventMethod: string;
- events: EventRecord[] = [];
- unsubscribe: VoidFn | null = null;
-
- constructor(
- helper: DevUniqueHelper,
- eventSection: string,
- eventMethod: string,
- ) {
- this.helper = helper;
- this.eventSection = eventSection;
- this.eventMethod = eventMethod;
- }
-
- async startCapture() {
- this.stopCapture();
- this.unsubscribe = (await this.helper.getApi().query.system.events((eventRecords: FrameSystemEventRecord[]) => {
- const newEvents = eventRecords.filter(r => r.event.section == this.eventSection && r.event.method == this.eventMethod);
-
- this.events.push(...newEvents);
- })) as any;
- }
-
- stopCapture() {
- if(this.unsubscribe !== null) {
- this.unsubscribe();
- }
- }
-
- extractCapturedEvents() {
- return this.events;
- }
-}
-
-class AdminGroup {
- helper: UniqueHelper;
-
- constructor(helper: UniqueHelper) {
- this.helper = helper;
- }
-
- async payoutStakers(signer: IKeyringPair, stakersToPayout: number): Promise<{staker: string, stake: bigint, payout: bigint}[]> {
- const payoutResult = await this.helper.executeExtrinsic(signer, 'api.tx.appPromotion.payoutStakers', [stakersToPayout], true);
- return payoutResult.result.events.filter(e => e.event.method === 'StakingRecalculation').map(e => ({
- staker: e.event.data[0].toString(),
- stake: e.event.data[1].toBigInt(),
- payout: e.event.data[2].toBigInt(),
- }));
- }
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {
- return class extends Base {
- scheduleFn: 'schedule' | 'scheduleAfter';
- blocksNum: number;
- options: ISchedulerOptions;
-
- constructor(...args: any[]) {
- const logger = args[0] as ILogger;
- const options = args[1] as {
- scheduleFn: 'schedule' | 'scheduleAfter',
- blocksNum: number,
- options: ISchedulerOptions
- };
-
- super(logger);
-
- this.scheduleFn = options.scheduleFn;
- this.blocksNum = options.blocksNum;
- this.options = options.options;
- }
-
- override executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {
- const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);
-
- const mandatorySchedArgs = [
- this.blocksNum,
- this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,
- this.options.priority ?? null,
- scheduledTx,
- ];
-
- let schedArgs;
- let scheduleFn;
-
- if(this.options.scheduledId) {
- schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];
-
- if(this.scheduleFn == 'schedule') {
- scheduleFn = 'scheduleNamed';
- } else if(this.scheduleFn == 'scheduleAfter') {
- scheduleFn = 'scheduleNamedAfter';
- }
- } else {
- schedArgs = mandatorySchedArgs;
- scheduleFn = this.scheduleFn;
- }
-
- const extrinsic = 'api.tx.scheduler.' + scheduleFn;
-
- return super.executeExtrinsic(
- sender,
- extrinsic as any,
- schedArgs,
- expectSuccess,
- );
- }
- };
-}
js-packages/playgrounds/src/unique.governance.tsdiffbeforeafterboth--- a/js-packages/playgrounds/src/unique.governance.ts
+++ /dev/null
@@ -1,531 +0,0 @@
-import {blake2AsHex} from '@polkadot/util-crypto';
-import type {PalletDemocracyConviction} from '@polkadot/types/lookup';
-import type {IPhasicEvent, TSigner} from './types.js';
-import {HelperGroup, UniqueHelper} from './unique.js';
-
-export class CollectiveGroup extends HelperGroup<UniqueHelper> {
- /**
- * Pallet name to make an API call to. Examples: 'council', 'technicalCommittee'
- */
- private collective: string;
-
- constructor(helper: UniqueHelper, collective: string) {
- super(helper);
- this.collective = collective;
- }
-
- /**
- * Check the result of a proposal execution for the success of the underlying proposed extrinsic.
- * @param events events of the proposal execution
- * @returns proposal hash
- */
- private checkExecutedEvent(events: IPhasicEvent[]): string {
- const executionEvents = events.filter(x =>
- x.event.section === this.collective && (x.event.method === 'Executed' || x.event.method === 'MemberExecuted'));
-
- if(executionEvents.length != 1) {
- if(events.filter(x => x.event.section === this.collective && x.event.method === 'Disapproved').length > 0)
- throw new Error(`Disapproved by ${this.collective}`);
- else
- throw new Error(`Expected one 'Executed' or 'MemberExecuted' event for ${this.collective}`);
- }
-
- const result = (executionEvents[0].event.data as any).result;
-
- if(result.isErr) {
- if(result.asErr.isModule) {
- const error = result.asErr.asModule;
- const metaError = this.helper.getApi()?.registry.findMetaError(error);
- throw new Error(`Proposal execution failed with ${metaError.section}.${metaError.name}`);
- } else {
- throw new Error('Proposal execution failed with ' + result.asErr.toHuman());
- }
- }
-
- return (executionEvents[0].event.data as any).proposalHash;
- }
-
- /**
- * Returns an array of members' addresses.
- */
- async getMembers() {
- return (await this.helper.callRpc(`api.query.${this.collective}.members`, [])).toHuman();
- }
-
- /**
- * Returns the optional address of the prime member of the collective.
- */
- async getPrimeMember() {
- return (await this.helper.callRpc(`api.query.${this.collective}.prime`, [])).toHuman();
- }
-
- /**
- * Returns an array of proposal hashes that are currently active for this collective.
- */
- async getProposals() {
- return (await this.helper.callRpc(`api.query.${this.collective}.proposals`, [])).toHuman();
- }
-
- /**
- * Returns the call originally encoded under the specified hash.
- * @param hash h256-encoded proposal
- * @returns the optional call that the proposal hash stands for.
- */
- async getProposalCallOf(hash: string) {
- return (await this.helper.callRpc(`api.query.${this.collective}.proposalOf`, [hash])).toHuman();
- }
-
- /**
- * Returns the total number of proposals so far.
- */
- async getTotalProposalsCount() {
- return (await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, [])).toNumber();
- }
-
- /**
- * Creates a new proposal up for voting. If the threshold is set to 1, the proposal will be executed immediately.
- * @param signer keyring of the proposer
- * @param proposal constructed call to be executed if the proposal is successful
- * @param voteThreshold minimal number of votes for the proposal to be verified and executed
- * @param lengthBound byte length of the encoded call
- * @returns promise of extrinsic execution and its result
- */
- async propose(signer: TSigner, proposal: any, voteThreshold: number, lengthBound = 10000) {
- return await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [voteThreshold, proposal, lengthBound]);
- }
-
- /**
- * Casts a vote to either approve or reject a proposal.
- * @param signer keyring of the voter
- * @param proposalHash hash of the proposal to be voted for
- * @param proposalIndex absolute index of the proposal used for absolutely nothing but throwing pointless errors
- * @param approve aye or nay
- * @returns promise of extrinsic execution and its result
- */
- vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve]);
- }
-
- /**
- * Executes a call immediately as a member of the collective. Needed for the Member origin.
- * @param signer keyring of the executor member
- * @param proposal constructed call to be executed by the member
- * @param lengthBound byte length of the encoded call
- * @returns promise of extrinsic execution
- */
- async execute(signer: TSigner, proposal: any, lengthBound = 10000) {
- const result = await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.execute`, [proposal, lengthBound]);
- this.checkExecutedEvent(result.result.events);
- return result;
- }
-
- /**
- * Attempt to close and execute a proposal. Note that there must already be enough votes to meet the threshold set when proposing.
- * @param signer keyring of the executor. Can be absolutely anyone.
- * @param proposalHash hash of the proposal to close
- * @param proposalIndex index of the proposal generated on its creation
- * @param weightBound weight of the proposed call. Can be obtained by calling `paymentInfo()` on the call.
- * @param lengthBound byte length of the encoded call
- * @returns promise of extrinsic execution and its result
- */
- async close(
- signer: TSigner,
- proposalHash: string,
- proposalIndex: number,
- weightBound: [number, number] | any = [20_000_000_000, 1000_000],
- lengthBound = 10_000,
- ) {
- const result = await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [
- proposalHash,
- proposalIndex,
- weightBound,
- lengthBound,
- ]);
- this.checkExecutedEvent(result.result.events);
- return result;
- }
-
- /**
- * Shut down a proposal, regardless of its current state.
- * @param signer keyring of the disapprover. Must be root
- * @param proposalHash hash of the proposal to close
- * @returns promise of extrinsic execution and its result
- */
- disapproveProposal(signer: TSigner, proposalHash: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.disapproveProposal`, [proposalHash]);
- }
-}
-
-export class CollectiveMembershipGroup extends HelperGroup<UniqueHelper> {
- /**
- * Pallet name to make an API call to. Examples: 'councilMembership', 'technicalCommitteeMembership'
- */
- private membership: string;
-
- constructor(helper: UniqueHelper, membership: string) {
- super(helper);
- this.membership = membership;
- }
-
- /**
- * Returns an array of members' addresses according to the membership pallet's perception.
- * Note that it does not recognize the original pallet's members set with `setMembers()`.
- */
- async getMembers() {
- return (await this.helper.callRpc(`api.query.${this.membership}.members`, [])).toHuman();
- }
-
- /**
- * Returns the optional address of the prime member of the collective.
- */
- async getPrimeMember() {
- return (await this.helper.callRpc(`api.query.${this.membership}.prime`, [])).toHuman();
- }
-
- /**
- * Add a member to the collective.
- * @param signer keyring of the setter. Must be root
- * @param member address of the member to add
- * @returns promise of extrinsic execution and its result
- */
- addMember(signer: TSigner, member: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.addMember`, [member]);
- }
-
- addMemberCall(member: string) {
- return this.helper.constructApiCall(`api.tx.${this.membership}.addMember`, [member]);
- }
-
- /**
- * Remove a member from the collective.
- * @param signer keyring of the setter. Must be root
- * @param member address of the member to remove
- * @returns promise of extrinsic execution and its result
- */
- removeMember(signer: TSigner, member: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.removeMember`, [member]);
- }
-
- removeMemberCall(member: string) {
- return this.helper.constructApiCall(`api.tx.${this.membership}.removeMember`, [member]);
- }
-
- /**
- * Set members of the collective to the given list of addresses.
- * @param signer keyring of the setter. Must be root (for the direct call, bypassing a public motion)
- * @param members addresses of the members to set
- * @returns promise of extrinsic execution and its result
- */
- resetMembers(signer: TSigner, members: string[]) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.resetMembers`, [members]);
- }
-
- /**
- * Set the collective's prime member to the given address.
- * @param signer keyring of the setter. Must be root (for the direct call, bypassing a public motion)
- * @param prime address of the prime member of the collective
- * @returns promise of extrinsic execution and its result
- */
- setPrime(signer: TSigner, prime: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.setPrime`, [prime]);
- }
-
- setPrimeCall(member: string) {
- return this.helper.constructApiCall(`api.tx.${this.membership}.setPrime`, [member]);
- }
-
- /**
- * Remove the collective's prime member.
- * @param signer keyring of the setter. Must be root (for the direct call, bypassing a public motion)
- * @returns promise of extrinsic execution and its result
- */
- clearPrime(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.clearPrime`, []);
- }
-
- clearPrimeCall() {
- return this.helper.constructApiCall(`api.tx.${this.membership}.clearPrime`, []);
- }
-}
-
-export class RankedCollectiveGroup extends HelperGroup<UniqueHelper> {
- /**
- * Pallet name to make an API call to. Examples: 'FellowshipCollective'
- */
- private collective: string;
-
- constructor(helper: UniqueHelper, collective: string) {
- super(helper);
- this.collective = collective;
- }
-
- addMember(signer: TSigner, newMember: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.addMember`, [newMember]);
- }
-
- addMemberCall(newMember: string) {
- return this.helper.constructApiCall(`api.tx.${this.collective}.addMember`, [newMember]);
- }
-
- removeMember(signer: TSigner, member: string, minRank: number) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.removeMember`, [member, minRank]);
- }
-
- removeMemberCall(newMember: string, minRank: number) {
- return this.helper.constructApiCall(`api.tx.${this.collective}.removeMember`, [newMember, minRank]);
- }
-
- promote(signer: TSigner, member: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.promoteMember`, [member]);
- }
-
- promoteCall(member: string) {
- return this.helper.constructApiCall(`api.tx.${this.collective}.promoteMember`, [member]);
- }
-
- demote(signer: TSigner, member: string) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.demoteMember`, [member]);
- }
-
- demoteCall(newMember: string) {
- return this.helper.constructApiCall(`api.tx.${this.collective}.demoteMember`, [newMember]);
- }
-
- vote(signer: TSigner, pollIndex: number, aye: boolean) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [pollIndex, aye]);
- }
-
- async getMembers() {
- return (await this.helper.getApi().query.fellowshipCollective.members.keys())
- .map((key) => key.args[0].toString());
- }
-
- async getMemberRank(member: string) {
- return (await this.helper.callRpc('api.query.fellowshipCollective.members', [member])).toJSON().rank;
- }
-}
-
-export class ReferendaGroup extends HelperGroup<UniqueHelper> {
- /**
- * Pallet name to make an API call to. Examples: 'FellowshipReferenda'
- */
- private referenda: string;
-
- constructor(helper: UniqueHelper, referenda: string) {
- super(helper);
- this.referenda = referenda;
- }
-
- submit(
- signer: TSigner,
- proposalOrigin: string,
- proposal: any,
- enactmentMoment: any,
- ) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.referenda}.submit`, [
- {Origins: proposalOrigin},
- proposal,
- enactmentMoment,
- ]);
- }
-
- placeDecisionDeposit(signer: TSigner, referendumIndex: number) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.referenda}.placeDecisionDeposit`, [referendumIndex]);
- }
-
- cancel(signer: TSigner, referendumIndex: number) {
- return this.helper.executeExtrinsic(signer, `api.tx.${this.referenda}.cancel`, [referendumIndex]);
- }
-
- cancelCall(referendumIndex: number) {
- return this.helper.constructApiCall(`api.tx.${this.referenda}.cancel`, [referendumIndex]);
- }
-
- async referendumInfo(referendumIndex: number) {
- return (await this.helper.callRpc(`api.query.${this.referenda}.referendumInfoFor`, [referendumIndex])).toJSON();
- }
-
- async enactmentEventId(referendumIndex: number) {
- const api = await this.helper.getApi();
-
- const bytes = api.createType('([u8;8], Text, u32)', ['assembly', 'enactment', referendumIndex]).toU8a();
- return blake2AsHex(bytes, 256);
- }
-}
-
-export interface IFellowshipGroup {
- collective: RankedCollectiveGroup;
- referenda: ReferendaGroup;
-}
-
-export interface ICollectiveGroup {
- collective: CollectiveGroup;
- membership: CollectiveMembershipGroup;
-}
-
-export class DemocracyGroup extends HelperGroup<UniqueHelper> {
- // todo displace proposal into types?
- propose(signer: TSigner, call: any, deposit: bigint) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.propose', [{Inline: call.method.toHex()}, deposit]);
- }
-
- proposeWithPreimage(signer: TSigner, preimage: string, deposit: bigint) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.propose', [{Legacy: preimage}, deposit]);
- }
-
- proposeCall(call: any, deposit: bigint) {
- return this.helper.constructApiCall('api.tx.democracy.propose', [{Inline: call.method.toHex()}, deposit]);
- }
-
- second(signer: TSigner, proposalIndex: number) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.second', [proposalIndex]);
- }
-
- externalPropose(signer: TSigner, proposalCall: any) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalPropose', [{Inline: proposalCall.method.toHex()}]);
- }
-
- externalProposeMajority(signer: TSigner, proposalCall: any) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalProposeMajority', [{Inline: proposalCall.method.toHex()}]);
- }
-
- externalProposeDefault(signer: TSigner, proposalCall: any) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalProposeDefault', [{Inline: proposalCall.method.toHex()}]);
- }
-
- externalProposeDefaultWithPreimage(signer: TSigner, preimage: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalProposeDefault', [{Legacy: preimage}]);
- }
-
- externalProposeCall(proposalCall: any) {
- return this.helper.constructApiCall('api.tx.democracy.externalPropose', [{Inline: proposalCall.method.toHex()}]);
- }
-
- externalProposeMajorityCall(proposalCall: any) {
- return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [{Inline: proposalCall.method.toHex()}]);
- }
-
- externalProposeDefaultCall(proposalCall: any) {
- return this.helper.constructApiCall('api.tx.democracy.externalProposeDefault', [{Inline: proposalCall.method.toHex()}]);
- }
-
- externalProposeDefaultWithPreimageCall(preimage: string) {
- return this.helper.constructApiCall('api.tx.democracy.externalProposeDefault', [{Legacy: preimage}]);
- }
-
- // ... and blacklist external proposal hash.
- vetoExternal(signer: TSigner, proposalHash: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.vetoExternal', [proposalHash]);
- }
-
- vetoExternalCall(proposalHash: string) {
- return this.helper.constructApiCall('api.tx.democracy.vetoExternal', [proposalHash]);
- }
-
- blacklist(signer: TSigner, proposalHash: string, referendumIndex: number | null = null) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.blacklist', [proposalHash, referendumIndex]);
- }
-
- blacklistCall(proposalHash: string, referendumIndex: number | null = null) {
- return this.helper.constructApiCall('api.tx.democracy.blacklist', [proposalHash, referendumIndex]);
- }
-
- // proposal. CancelProposalOrigin (root or all techcom)
- cancelProposal(signer: TSigner, proposalIndex: number) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.cancelProposal', [proposalIndex]);
- }
-
- cancelProposalCall(proposalIndex: number) {
- return this.helper.constructApiCall('api.tx.democracy.cancelProposal', [proposalIndex]);
- }
-
- clearPublicProposals(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.clearPublicProposals', []);
- }
-
- fastTrack(signer: TSigner, proposalHash: string, votingPeriod: number, delayPeriod: number) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);
- }
-
- fastTrackCall(proposalHash: string, votingPeriod: number, delayPeriod: number) {
- return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);
- }
-
- // referendum. CancellationOrigin (TechCom member)
- emergencyCancel(signer: TSigner, referendumIndex: number) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.emergencyCancel', [referendumIndex]);
- }
-
- emergencyCancelCall(referendumIndex: number) {
- return this.helper.constructApiCall('api.tx.democracy.emergencyCancel', [referendumIndex]);
- }
-
- vote(signer: TSigner, referendumIndex: number, vote: any) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, vote]);
- }
-
- removeVote(signer: TSigner, referendumIndex: number, targetAccount?: string) {
- if(targetAccount) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.removeOtherVote', [targetAccount, referendumIndex]);
- } else {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.removeVote', [referendumIndex]);
- }
- }
-
- unlock(signer: TSigner, targetAccount: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.unlock', [targetAccount]);
- }
-
- delegate(signer: TSigner, toAccount: string, conviction: PalletDemocracyConviction, balance: bigint) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.delegate', [toAccount, conviction, balance]);
- }
-
- undelegate(signer: TSigner) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.undelegate', []);
- }
-
- async referendumInfo(referendumIndex: number) {
- return (await this.helper.callRpc('api.query.democracy.referendumInfoOf', [referendumIndex])).toJSON();
- }
-
- async publicProposals() {
- return (await this.helper.callRpc('api.query.democracy.publicProps', [])).toJSON();
- }
-
- async findPublicProposal(proposalIndex: number) {
- const proposalInfo = (await this.publicProposals()).find((proposalInfo: any[]) => proposalInfo[0] == proposalIndex);
-
- return proposalInfo ? proposalInfo[1] : null;
- }
-
- async expectPublicProposal(proposalIndex: number) {
- const proposal = await this.findPublicProposal(proposalIndex);
-
- if(proposal) {
- return proposal;
- } else {
- throw Error(`Proposal #${proposalIndex} is expected to exist`);
- }
- }
-
- async getExternalProposal() {
- return (await this.helper.callRpc('api.query.democracy.nextExternal', []));
- }
-
- async expectExternalProposal() {
- const proposal = await this.getExternalProposal();
-
- if(proposal) {
- return proposal;
- } else {
- throw Error('An external proposal is expected to exist');
- }
- }
-
- /* setMetadata? */
-
- /* todo?
- referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {
- return this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);
- }*/
-}
js-packages/playgrounds/src/unique.tsdiffbeforeafterboth--- a/js-packages/playgrounds/src/unique.ts
+++ /dev/null
@@ -1,3498 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-/* eslint-disable @typescript-eslint/no-var-requires */
-/* eslint-disable function-call-argument-newline */
-/* eslint-disable no-prototype-builtins */
-
-import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';
-import type {SignerOptions} from '@polkadot/api/types';
-import type {AugmentedSubmittables} from '@polkadot/api-base/types/submittable';
-import type {ApiInterfaceEvents} from '@polkadot/api/types';
-import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {hexToU8a} from '@polkadot/util/hex';
-import {u8aConcat} from '@polkadot/util/u8a';
-import type {
- IApiListeners,
- IBlock,
- IEvent,
- IChainProperties,
- ICollectionCreationOptions,
- ICollectionLimits,
- ICollectionPermissions,
- ICrossAccountId,
- ICrossAccountIdLower,
- ILogger,
- INestingPermissions,
- IProperty,
- IStakingInfo,
- ISubstrateBalance,
- IToken,
- ITokenPropertyPermission,
- ITransactionResult,
- IUniqueHelperLog,
- TApiAllowedListeners,
- TEthereumAccount,
- TSigner,
- TSubstrateAccount,
- TNetworks,
- IEthCrossAccountId,
-} from './types.js';
-import type {RuntimeDispatchInfo} from '@polkadot/types/interfaces';
-
-export class CrossAccountId {
- account: ICrossAccountId;
-
- constructor(account: ICrossAccountId) {
- this.account = account;
- }
-
- static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {
- switch (domain) {
- case 'Substrate': return new CrossAccountId({Substrate: account.address});
- case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();
- }
- }
-
- static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {
- if('substrate' in address) return new CrossAccountId({Substrate: address.substrate});
- else return new CrossAccountId({Ethereum: address.ethereum});
- }
-
- static normalizeSubstrateAddress(address: {Substrate: TSubstrateAccount}, ss58Format = 42): TSubstrateAccount {
- return encodeAddress(decodeAddress(address.Substrate), ss58Format);
- }
-
- static withNormalizedSubstrate(address: ICrossAccountId, ss58Format = 42): ICrossAccountId {
- if('Substrate' in address) return {Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)};
- return address;
- }
-
- withNormalizedSubstrate(ss58Format = 42): CrossAccountId {
- if('Substrate' in this.account) this.account = CrossAccountId.withNormalizedSubstrate(this.account, ss58Format);
- return this;
- }
-
- static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {
- return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));
- }
-
- toEthereum(): CrossAccountId {
- this.account = CrossAccountId.toEthereum(this.account);
- return this;
- }
-
- static toEthereum(account: ICrossAccountId): ICrossAccountId {
- if('Substrate' in account) return {Ethereum: CrossAccountId.translateSubToEth(account.Substrate)};
- return account;
- }
-
- static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {
- return evmToAddress(address, ss58Format);
- }
-
- toSubstrate(ss58Format?: number): CrossAccountId {
- this.account = CrossAccountId.toSubstrate(this.account, ss58Format);
- return this;
- }
-
- static toSubstrate(account: ICrossAccountId, ss58Format?: number): ICrossAccountId {
- if('Ethereum' in account) return {Substrate: CrossAccountId.translateEthToSub(account.Ethereum, ss58Format)};
- return account;
- }
-
- toLowerCase(): CrossAccountId {
- this.account = CrossAccountId.toLowerCase(this.account);
- return this;
- }
-
- static toLowerCase(account: ICrossAccountId) {
- if('Substrate' in account) return {Substrate: account.Substrate.toLowerCase()};
- if('Ethereum' in account) return {Ethereum: account.Ethereum.toLowerCase()};
- return account;
- }
-
- toICrossAccountId(): ICrossAccountId {
- return this.account;
- }
-}
-
-const nesting = {
- toChecksumAddress(address: string): string {
- if(typeof address === 'undefined') return '';
-
- if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);
-
- address = address.toLowerCase().replace(/^0x/i, '');
- const addressHash = keccakAsHex(address).replace(/^0x/i, '');
- const checksumAddress = ['0x'];
-
- for(let i = 0; i < address.length; i++) {
- // If ith character is 8 to f then make it uppercase
- if(parseInt(addressHash[i], 16) > 7) {
- checksumAddress.push(address[i].toUpperCase());
- } else {
- checksumAddress.push(address[i]);
- }
- }
- return checksumAddress.join('');
- },
- tokenIdToAddress(collectionId: number, tokenId: number) {
- return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8, '0')}${tokenId.toString(16).padStart(8, '0')}`);
- },
-};
-
-class UniqueUtil {
- static transactionStatus = {
- NOT_READY: 'NotReady',
- FAIL: 'Fail',
- SUCCESS: 'Success',
- };
-
- static chainLogType = {
- EXTRINSIC: 'extrinsic',
- RPC: 'rpc',
- };
-
- static getTokenAccount(token: IToken): ICrossAccountId {
- return {Ethereum: this.getTokenAddress(token)};
- }
-
- static getTokenAddress(token: IToken): string {
- return nesting.tokenIdToAddress(token.collectionId, token.tokenId);
- }
-
- static getDefaultLogger(): ILogger {
- return {
- log(msg: any, level = 'INFO') {
- console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));
- },
- level: {
- ERROR: 'ERROR',
- WARNING: 'WARNING',
- INFO: 'INFO',
- },
- };
- }
-
- static vec2str(arr: string[] | number[]) {
- return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');
- }
-
- static str2vec(string: string) {
- if(typeof string !== 'string') return string;
- return Array.from(string).map(x => x.charCodeAt(0));
- }
-
- static fromSeed(seed: string, ss58Format = 42) {
- const keyring = new Keyring({type: 'sr25519', ss58Format});
- return keyring.addFromUri(seed);
- }
-
- static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {
- if(creationResult.status !== this.transactionStatus.SUCCESS) {
- throw Error('Unable to create collection!');
- }
-
- let collectionId = null;
- creationResult.result.events.forEach(({event: {data, method, section}}) => {
- if((section === 'common') && (method === 'CollectionCreated')) {
- collectionId = parseInt(data[0].toString(), 10);
- }
- });
-
- if(collectionId === null) {
- throw Error('No CollectionCreated event was found!');
- }
-
- return collectionId;
- }
-
- static extractTokensFromCreationResult(creationResult: ITransactionResult): {
- success: boolean,
- tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],
- } {
- if(creationResult.status !== this.transactionStatus.SUCCESS) {
- throw Error('Unable to create tokens!');
- }
- let success = false;
- const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];
- creationResult.result.events.forEach(({event: {data, method, section}}) => {
- if(method === 'ExtrinsicSuccess') {
- success = true;
- } else if((section === 'common') && (method === 'ItemCreated')) {
- tokens.push({
- collectionId: parseInt(data[0].toString(), 10),
- tokenId: parseInt(data[1].toString(), 10),
- owner: data[2].toHuman(),
- amount: data[3].toBigInt(),
- });
- }
- });
- return {success, tokens};
- }
-
- static extractTokensFromBurnResult(burnResult: ITransactionResult): {
- success: boolean,
- tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],
- } {
- if(burnResult.status !== this.transactionStatus.SUCCESS) {
- throw Error('Unable to burn tokens!');
- }
- let success = false;
- const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];
- burnResult.result.events.forEach(({event: {data, method, section}}: any) => {
- if(method === 'ExtrinsicSuccess') {
- success = true;
- } else if((section === 'common') && (method === 'ItemDestroyed')) {
- tokens.push({
- collectionId: parseInt(data[0].toString(), 10),
- tokenId: parseInt(data[1].toString(), 10),
- owner: data[2].toHuman(),
- amount: data[3].toBigInt(),
- });
- }
- });
- return {success, tokens};
- }
-
- static findCollectionInEvents(events: { event: IEvent }[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {
- let eventId = null;
- events.forEach(({event: {data, method, section}}) => {
- if((section === expectedSection) && (method === expectedMethod)) {
- eventId = parseInt(data[0].toString(), 10);
- }
- });
-
- if(eventId === null) {
- throw Error(`No ${expectedMethod} event was found!`);
- }
- return eventId === collectionId;
- }
-
- static isTokenTransferSuccess(events: { event: IEvent }[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
- const normalizeAddress = (address: string | ICrossAccountId) => {
- if(typeof address === 'string') return address;
- if('Substrate' in address) return CrossAccountId.withNormalizedSubstrate(address);
- if('Ethereum' in address) return CrossAccountId.toLowerCase(address);
- return address;
- };
- let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;
- events.forEach(({event: {data, method, section}}) => {
- if((section === 'common') && (method === 'Transfer')) {
- transfer = {
- collectionId: data[0].toJSON(),
- tokenId: data[1].toJSON(),
- from: normalizeAddress(data[2].toHuman()),
- to: normalizeAddress(data[3].toHuman()),
- amount: BigInt(data[4].toJSON()),
- };
- }
- });
- let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;
- isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);
- isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);
- isSuccess = isSuccess && amount === transfer.amount;
- return isSuccess;
- }
-
- static bigIntToDecimals(number: bigint, decimals = 18) {
- const numberStr = number.toString();
- const dotPos = numberStr.length - decimals;
-
- if(dotPos <= 0) {
- return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;
- } else {
- const intPart = numberStr.substring(0, dotPos);
- const fractPart = numberStr.substring(dotPos);
- return intPart + '.' + fractPart;
- }
- }
-}
-
-class UniqueEventHelper {
- static extractIndex(index: any): [number, number] | string {
- if(index.toRawType() === '[u8;2]') return [index[0], index[1]];
- return index.toJSON();
- }
-
- static extractSub(data: any, subTypes: any): { [key: string]: any } {
- let obj: any = {};
- let index = 0;
-
- if(data.entries) {
- for(const [key, value] of data.entries()) {
- obj[key] = this.extractData(value, subTypes[index]);
- index++;
- }
- } else obj = data.toJSON();
-
- return obj;
- }
-
- static toHuman(data: any) {
- return data && data.toHuman ? data.toHuman() : `${data}`;
- }
-
- static extractData(data: any, type: any): any {
- if(!type) return this.toHuman(data);
- if(['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();
- if(['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();
- if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);
- return this.toHuman(data);
- }
-
- public static extractEvents(events: { event: any, phase: any }[]): IEvent[] {
- const parsedEvents: IEvent[] = [];
-
- events.forEach((record) => {
- const {event, phase} = record;
- const types = event.typeDef;
-
- const eventData: IEvent = {
- section: event.section.toString(),
- method: event.method.toString(),
- index: this.extractIndex(event.index),
- data: [],
- phase: phase.toJSON(),
- };
-
- event.data.forEach((val: any, index: number) => {
- eventData.data.push(this.extractData(val, types[index]));
- });
-
- parsedEvents.push(eventData);
- });
-
- return parsedEvents;
- }
-}
-const InvalidTypeSymbol = Symbol('Invalid type');
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export type Invalid =
- | ((
- invalidType: typeof InvalidTypeSymbol,
- ..._: typeof InvalidTypeSymbol[]
- ) => typeof InvalidTypeSymbol)
- | null
- | undefined;
-// Has slightly better error messages than Get
-type Get2<T, P extends string, E> =
- P extends `${infer Key}.${infer Key2}` ? Key extends keyof T ? Key2 extends keyof T[Key] ? T[Key][Key2] : E : E : E;
-type ForceFunction<T> = T extends (...args: any) => any ? T : (...args: any) => Invalid;
-
-export class ChainHelperBase {
- helperBase: any;
-
- transactionStatus = UniqueUtil.transactionStatus;
- chainLogType = UniqueUtil.chainLogType;
- util: typeof UniqueUtil;
- eventHelper: typeof UniqueEventHelper;
- logger: ILogger;
- api: ApiPromise | null;
- forcedNetwork: TNetworks | null;
- network: TNetworks | null;
- wsEndpoint: string | null;
- chainLog: IUniqueHelperLog[];
- children: ChainHelperBase[];
- address: AddressGroup;
- chain: ChainGroup;
-
- constructor(logger?: ILogger, helperBase?: any) {
- this.helperBase = helperBase;
-
- this.util = UniqueUtil;
- this.eventHelper = UniqueEventHelper;
- if(typeof logger == 'undefined') logger = this.util.getDefaultLogger();
- this.logger = logger;
- this.api = null;
- this.forcedNetwork = null;
- this.network = null;
- this.wsEndpoint = null;
- this.chainLog = [];
- this.children = [];
- this.address = new AddressGroup(this);
- this.chain = new ChainGroup(this);
- }
-
- clone(helperCls: ChainHelperBaseConstructor, options: { [key: string]: any } = {}) {
- Object.setPrototypeOf(helperCls.prototype, this);
- const newHelper = new helperCls(this.logger, options);
-
- newHelper.api = this.api;
- newHelper.network = this.network;
- newHelper.forceNetwork = this.forceNetwork;
-
- this.children.push(newHelper);
-
- return newHelper;
- }
-
- getEndpoint(): string {
- if(this.wsEndpoint === null) throw Error('No connection was established');
- return this.wsEndpoint;
- }
-
- getApi(): ApiPromise {
- if(this.api === null) throw Error('API not initialized');
- return this.api;
- }
-
- async subscribeEvents(expectedEvents: { section: string, names: string[] }[]) {
- const collectedEvents: IEvent[] = [];
- const unsubscribe = await this.getApi().query.system.events((events: any) => {
- const ievents = this.eventHelper.extractEvents(events);
- ievents.forEach((event) => {
- expectedEvents.forEach((e => {
- if(event.section === e.section && e.names.includes(event.method)) {
- collectedEvents.push(event);
- }
- }));
- });
- });
- return {unsubscribe: unsubscribe as any, collectedEvents};
- }
-
- clearChainLog(): void {
- this.chainLog = [];
- }
-
- forceNetwork(value: TNetworks): void {
- this.forcedNetwork = value;
- }
-
- async connect(wsEndpoint: string, listeners?: IApiListeners) {
- if(this.api !== null) throw Error('Already connected');
- const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);
- this.wsEndpoint = wsEndpoint;
- this.api = api;
- this.network = network;
- }
-
- async disconnect() {
- for(const child of this.children) {
- child.clearApi();
- }
-
- if(this.api === null) return;
- await this.api.disconnect();
- this.clearApi();
- }
-
- clearApi() {
- this.api = null;
- this.network = null;
- }
-
- static async detectNetwork(api: ApiPromise): Promise<TNetworks> {
- const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;
- const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];
-
- if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;
-
- if(['quartz', 'unique', 'sapphire'].indexOf(spec.specName) > -1) return spec.specName;
- return 'opal';
- }
-
- static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {
- if(!wsEndpoint) throw new Error('wsEndpoint was not set');
- const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});
- await api.isReady;
-
- const network = await this.detectNetwork(api);
-
- await api.disconnect();
-
- return network;
- }
-
- static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{
- api: ApiPromise;
- network: TNetworks;
- }> {
- if(typeof network === 'undefined' || network === null) network = 'opal';
- if(!wsEndpoint) throw new Error('wsEndpoint was not set');
- const supportedRPC = {
- opal: {
- unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,
- },
- quartz: {
- unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,
- },
- unique: {
- unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,
- },
- rococo: {},
- westend: {},
- moonbeam: {},
- moonriver: {},
- acala: {},
- karura: {},
- westmint: {},
- };
- if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);
- const rpc = supportedRPC[network] as any;
-
- // TODO: investigate how to replace rpc in runtime
- // api._rpcCore.addUserInterfaces(rpc);
-
- const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});
-
- await api.isReadyOrError;
-
- if(typeof listeners === 'undefined') listeners = {};
- for(const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {
- if(!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;
- api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);
- }
-
- return {api, network};
- }
-
- getTransactionStatus(data: { events: { event: IEvent }[], status: any }) {
- const {events, status} = data;
- if(status.isReady) {
- return this.transactionStatus.NOT_READY;
- }
- if(status.isBroadcast) {
- return this.transactionStatus.NOT_READY;
- }
- if(status.isInBlock || status.isFinalized) {
- const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');
- if(errors.length > 0) {
- return this.transactionStatus.FAIL;
- }
- if(events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {
- return this.transactionStatus.SUCCESS;
- }
- }
-
- return this.transactionStatus.FAIL;
- }
-
- signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {
- const sign = (callback: any) => {
- if(options !== null) return transaction.signAndSend(sender, options, callback);
- return transaction.signAndSend(sender, callback);
- };
- // eslint-disable-next-line no-async-promise-executor
- return new Promise(async (resolve, reject) => {
- try {
- const unsub = await sign((result: any) => {
- const status = this.getTransactionStatus(result);
-
- if(status === this.transactionStatus.SUCCESS) {
- this.logger.log(`${label} successful`);
- unsub();
- resolve({result, status, blockHash: result.status.asInBlock.toHuman()});
- } else if(status === this.transactionStatus.FAIL) {
- let moduleError = null;
-
- if(result.hasOwnProperty('dispatchError')) {
- const dispatchError = result['dispatchError'];
-
- if(dispatchError) {
- if(dispatchError.isModule) {
- const modErr = dispatchError.asModule;
- const errorMeta = dispatchError.registry.findMetaError(modErr);
-
- moduleError = `${errorMeta.section}.${errorMeta.name}`;
- } else if(dispatchError.isToken) {
- moduleError = `Token: ${dispatchError.asToken}`;
- } else {
- // May be [object Object] in case of unhandled non-unit enum
- moduleError = `Misc: ${dispatchError.toHuman()}`;
- }
- } else {
- this.logger.log(result, this.logger.level.ERROR);
- }
- }
-
- this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);
- unsub();
- reject({status, moduleError, result});
- }
- });
- } catch (e) {
- this.logger.log(e, this.logger.level.ERROR);
- reject(e);
- }
- });
- }
-
- async signTransactionWithoutSending(signer: TSigner, tx: any) {
- const api = this.getApi();
- const signingInfo = await api.derive.tx.signingInfo(signer.address);
-
- tx.sign(signer, {
- blockHash: api.genesisHash,
- genesisHash: api.genesisHash,
- runtimeVersion: api.runtimeVersion,
- nonce: signingInfo.nonce,
- });
-
- return tx.toHex();
- }
-
- async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {
- const api = this.getApi();
- const signingInfo = await api.derive.tx.signingInfo(signer.address);
-
- // We need to sign the tx because
- // unsigned transactions does not have an inclusion fee
- tx.sign(signer, {
- blockHash: api.genesisHash,
- genesisHash: api.genesisHash,
- runtimeVersion: api.runtimeVersion,
- nonce: signingInfo.nonce,
- });
-
- if(len === null) {
- return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;
- } else {
- return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;
- }
- }
-
- constructApiCall(apiCall: string, params: any[]) {
- if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);
- let call = this.getApi() as any;
- for(const part of apiCall.slice(4).split('.')) {
- call = call[part];
- if(!call) {
- const advice = part.includes('_') ? ' Looks like it needs to be converted to camel case.' : '';
- throw Error(`Function ${part} of api call ${apiCall} not found.${advice}`);
- }
- }
- return call(...params);
- }
-
- encodeApiCall(apiCall: string, params: any[]) {
- return this.constructApiCall(apiCall, params).method.toHex();
- }
-
- async executeExtrinsic<
- E extends string,
- V extends (
- ...args: any) => any = ForceFunction<
- Get2<
- AugmentedSubmittables<'promise'>,
- E, (...args: any) => Invalid
- >
- >
- >(
- sender: TSigner,
- extrinsic: `api.tx.${E}`,
- params: Parameters<V>,
- expectSuccess = true,
- options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/
- ): Promise<ITransactionResult> {
- if(this.api === null) throw Error('API not initialized');
-
- const startTime = (new Date()).getTime();
- let result: ITransactionResult;
- let events: IEvent[] = [];
- try {
- result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;
- events = this.eventHelper.extractEvents(result.result.events);
- const errorEvent = events.find((event) => event.method == 'ExecutedFailed' || event.method == 'CreatedFailed');
- if(errorEvent)
- throw Error(errorEvent.method + ': ' + extrinsic);
- }
- catch (e) {
- if(!(e as object).hasOwnProperty('status')) throw e;
- result = e as ITransactionResult;
- }
-
- const endTime = (new Date()).getTime();
-
- const log = {
- executedAt: endTime,
- executionTime: endTime - startTime,
- type: this.chainLogType.EXTRINSIC,
- status: result.status,
- call: extrinsic,
- signer: this.getSignerAddress(sender),
- params,
- } as IUniqueHelperLog;
-
- let errorMessage = '';
-
- if(result.status !== this.transactionStatus.SUCCESS) {
- if(result.moduleError) {
- errorMessage = typeof result.moduleError === 'string'
- ? result.moduleError
- : `${Object.keys(result.moduleError)[0]}: ${Object.values(result.moduleError)[0]}`;
- log.moduleError = errorMessage;
- }
- else if(result.result.dispatchError) log.dispatchError = result.result.dispatchError;
- }
- if(events.length > 0) log.events = events;
-
- this.chainLog.push(log);
-
- if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {
- if(result.moduleError) throw Error(`${errorMessage}`);
- else if(result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));
- }
- return result as any;
- }
- executeExtrinsicUncheckedWeight<
- E extends string,
- V extends (
- ...args: any) => any = ForceFunction<
- Get2<
- AugmentedSubmittables<'promise'>,
- E, (...args: any) => Invalid
- >
- >
- >(
- _sender: TSigner,
- _extrinsic: `api.tx.${E}`,
- _params: Parameters<V>,
- _expectSuccess = true,
- _options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/
- ): Promise<ITransactionResult> {
- throw new Error('executeExtrinsicUncheckedWeight only supported in sudo');
- }
-
- async callRpc
- // TODO: make it strongly typed, or use api.query/api.rpc directly
- // <
- // K extends 'rpc' | 'query',
- // E extends string,
- // V extends (...args: any) => any = ForceFunction<
- // Get2<
- // K extends 'rpc' ? DecoratedRpc<'promise', RpcInterface> : QueryableStorage<'promise'>,
- // E, (...args: any) => Invalid<'not found'>
- // >
- // >,
- // P = Parameters<V>,
- // >
- (rpc: string, params?: any[]): Promise<any> {
-
- if(typeof params === 'undefined') params = [] as any;
- if(this.api === null) throw Error('API not initialized');
- if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);
-
- const startTime = (new Date()).getTime();
- let result;
- let error = null;
- const log = {
- type: this.chainLogType.RPC,
- call: rpc,
- params,
- } as any as IUniqueHelperLog;
-
- try {
- result = await this.constructApiCall(rpc, params as any);
- }
- catch (e) {
- error = e;
- }
-
- const endTime = (new Date()).getTime();
-
- log.executedAt = endTime;
- log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';
- log.executionTime = endTime - startTime;
-
- this.chainLog.push(log);
-
- if(error !== null) throw error;
-
- return result;
- }
-
- getSignerAddress(signer: IKeyringPair | string): string {
- if(typeof signer === 'string') return signer;
- return signer.address;
- }
-
- fetchAllPalletNames(): string[] {
- if(this.api === null) throw Error('API not initialized');
- return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()).sort();
- }
-
- fetchMissingPalletNames(requiredPallets: readonly string[]): string[] {
- const palletNames = this.fetchAllPalletNames();
- return requiredPallets.filter(p => !palletNames.includes(p));
- }
-}
-
-
-export class HelperGroup<T extends ChainHelperBase> {
- helper: T;
-
- constructor(uniqueHelper: T) {
- this.helper = uniqueHelper;
- }
-}
-
-
-class CollectionGroup extends HelperGroup<UniqueHelper> {
- /**
- * Get number of blocks when sponsored transaction is available.
- *
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param addressObj address for which the sponsorship is checked
- * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});
- * @returns number of blocks or null if sponsorship hasn't been set
- */
- async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {
- return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();
- }
-
- /**
- * Get the number of created collections.
- *
- * @returns number of created collections
- */
- async getTotalCount(): Promise<number> {
- return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();
- }
-
- /**
- * Get information about the collection with additional data,
- * including the number of tokens it contains, its administrators,
- * the normalized address of the collection's owner, and decoded name and description.
- *
- * @param collectionId ID of collection
- * @example await getData(2)
- * @returns collection information object
- */
- async getData(collectionId: number): Promise<{
- id: number;
- name: string;
- description: string;
- tokensCount: number;
- admins: CrossAccountId[];
- normalizedOwner: TSubstrateAccount;
- raw: any
- } | null> {
- const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);
- const humanCollection = collection.toHuman(), collectionData = {
- id: collectionId, name: null, description: null, tokensCount: 0, admins: [],
- raw: humanCollection,
- } as any, jsonCollection = collection.toJSON();
- if(humanCollection === null) return null;
- collectionData.raw.limits = jsonCollection.limits;
- collectionData.raw.permissions = jsonCollection.permissions;
- collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);
- for(const key of ['name', 'description']) {
- collectionData[key] = this.helper.util.vec2str(humanCollection[key]);
- }
-
- collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))
- ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)
- : 0;
- collectionData.admins = await this.getAdmins(collectionId);
-
- return collectionData;
- }
-
- /**
- * Get the addresses of the collection's administrators, optionally normalized.
- *
- * @param collectionId ID of collection
- * @param normalize whether to normalize the addresses to the default ss58 format
- * @example await getAdmins(1)
- * @returns array of administrators
- */
- async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
- const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman() as ICrossAccountId[];
-
- return normalize
- ? admins.map(address => CrossAccountId.withNormalizedSubstrate(address))
- : admins;
- }
-
- /**
- * Get the addresses added to the collection allow-list, optionally normalized.
- * @param collectionId ID of collection
- * @param normalize whether to normalize the addresses to the default ss58 format
- * @example await getAllowList(1)
- * @returns array of allow-listed addresses
- */
- async getAllowList(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
- const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman() as ICrossAccountId[];
- return normalize
- ? allowListed.map(address => CrossAccountId.withNormalizedSubstrate(address))
- : allowListed;
- }
-
- /**
- * Get the effective limits of the collection instead of null for default values
- *
- * @param collectionId ID of collection
- * @example await getEffectiveLimits(2)
- * @returns object of collection limits
- */
- async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {
- return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();
- }
-
- /**
- * Burns the collection if the signer has sufficient permissions and collection is empty.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @example await helper.collection.burn(aliceKeyring, 3);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async burn(signer: TSigner, collectionId: number): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.destroyCollection', [collectionId],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');
- }
-
- /**
- * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param sponsorAddress Sponsor substrate address
- * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');
- }
-
- /**
- * Confirms consent to sponsor the collection on behalf of the signer.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @example confirmSponsorship(aliceKeyring, 10)
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.confirmSponsorship', [collectionId],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');
- }
-
- /**
- * Removes the sponsor of a collection, regardless if it consented or not.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @example removeSponsor(aliceKeyring, 10)
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.removeCollectionSponsor', [collectionId],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');
- }
-
- /**
- * Sets the limits of the collection. At least one limit must be specified for a correct call.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param limits collection limits object
- * @example
- * await setLimits(
- * aliceKeyring,
- * 10,
- * {
- * sponsorTransferTimeout: 0,
- * ownerCanDestroy: false
- * }
- * )
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setCollectionLimits', [collectionId, limits],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');
- }
-
- /**
- * Changes the owner of the collection to the new Substrate address.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param ownerAddress substrate address of new owner
- * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');
- }
-
- /**
- * Adds a collection administrator.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param adminAddressObj Administrator address (substrate or ethereum)
- * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');
- }
-
- /**
- * Removes a collection administrator.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param adminAddressObj Administrator address (substrate or ethereum)
- * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');
- }
-
- /**
- * Check if user is in allow list.
- *
- * @param collectionId ID of collection
- * @param user Account to check
- * @example await getAdmins(1)
- * @returns is user in allow list
- */
- async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {
- return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();
- }
-
- /**
- * Adds an address to allow list
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param addressObj address to add to the allow list
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.addToAllowList', [collectionId, addressObj],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');
- }
-
- /**
- * Removes an address from allow list
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param addressObj address to remove from the allow list
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');
- }
-
- /**
- * Sets onchain permissions for selected collection.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param permissions collection permissions object
- * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setCollectionPermissions', [collectionId, permissions],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');
- }
-
- /**
- * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param permissions nesting permissions object
- * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {
- return await this.setPermissions(signer, collectionId, {nesting: permissions});
- }
-
- /**
- * Disables nesting for selected collection.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @example disableNesting(aliceKeyring, 10);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {
- return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});
- }
-
- /**
- * Sets onchain properties to the collection.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param properties array of property objects
- * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setCollectionProperties', [collectionId, properties],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');
- }
-
- /**
- * Get collection properties.
- *
- * @param collectionId ID of collection
- * @param propertyKeys optionally filter the returned properties to only these keys
- * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);
- * @returns array of key-value pairs
- */
- async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {
- return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();
- }
-
- async getPropertiesConsumedSpace(collectionId: number): Promise<number> {
- const api = this.helper.getApi();
- const props = (await api.query.common.collectionProperties(collectionId)).toJSON();
-
- return (props! as any).consumedSpace;
- }
-
- async getCollectionOptions(collectionId: number) {
- return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();
- }
-
- /**
- * Deletes onchain properties from the collection.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param propertyKeys array of property keys to delete
- * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');
- }
-
- /**
- * Changes the owner of the token.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param addressObj address of a new owner
- * @param amount amount of tokens to be transfered. For NFT must be set to 1n
- * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
- * @returns true if the token success, otherwise false
- */
- async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],
- true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,
- );
-
- return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);
- }
-
- /**
- *
- * Change ownership of a token(s) on behalf of the owner.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param fromAddressObj address on behalf of which the token will be sent
- * @param toAddressObj new token owner
- * @param amount amount of tokens to be transfered. For NFT must be set to 1n
- * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})
- * @returns true if the token success, otherwise false
- */
- async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],
- true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,
- );
- return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
- }
-
- /**
- *
- * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param amount amount of tokens to be burned. For NFT must be set to 1n
- * @example burnToken(aliceKeyring, 10, 5);
- * @returns ```true``` if the extrinsic is successful, otherwise ```false```
- */
- async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {
- const burnResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.burnItem', [collectionId, tokenId, amount],
- true, // `Unable to burn token for ${label}`,
- );
- const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);
- if(burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');
- return burnedTokens.success;
- }
-
- /**
- * Destroys a concrete instance of NFT on behalf of the owner
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param fromAddressObj address on behalf of which the token will be burnt
- * @param amount amount of tokens to be burned. For NFT must be set to 1n
- * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- const burnResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],
- true, // `Unable to burn token from for ${label}`,
- );
- const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);
- return burnedTokens.success && burnedTokens.tokens.length > 0;
- }
-
- /**
- * Set, change, or remove approved address to transfer the ownership of the NFT.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
- * @param amount amount of token to be approved. For NFT must be set to 1n
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- const approveResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],
- true, // `Unable to approve token for ${label}`,
- );
-
- return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');
- }
-
- /**
- * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param fromAddressObj Signer's Ethereum address containing her tokens
- * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
- * @param amount amount of token to be approved. For NFT must be set to 1n
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async approveTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
- const approveResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.approveFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],
- true, // `Unable to approve token for ${label}`,
- );
-
- return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');
- }
-
- /**
- * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
- * @param amount amount of token to be approved. For NFT must be set to 1n
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async approveTokenFromEth(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- const ethMirror = CrossAccountId.fromKeyring(signer).toEthereum().toICrossAccountId();
- return await this.approveTokenFrom(signer, collectionId, tokenId, ethMirror, toAddressObj, amount);
- }
-
- /**
- * Get the amount of token pieces approved to transfer or burn. Normally 0.
- *
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param toAccountObj address which is approved to use token pieces
- * @param fromAccountObj address which may have allowed the use of its owned tokens
- * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})
- * @returns number of approved to transfer pieces
- */
- async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();
- }
-
- /**
- * Get the last created token ID in a collection
- *
- * @param collectionId ID of collection
- * @example getLastTokenId(10);
- * @returns id of the last created token
- */
- async getLastTokenId(collectionId: number): Promise<number> {
- return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();
- }
-
- /**
- * Check if token exists
- *
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @example doesTokenExist(10, 20);
- * @returns true if the token exists, otherwise false
- */
- async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {
- return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();
- }
-}
-
-class NFTnRFT extends CollectionGroup {
- /**
- * Get tokens owned by account
- *
- * @param collectionId ID of collection
- * @param addressObj tokens owner
- * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})
- * @returns array of token ids owned by account
- */
- async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {
- return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();
- }
-
- /**
- * Get token data
- *
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param propertyKeys optionally filter the token properties to only these keys
- * @param blockHashAt optionally query the data at some block with this hash
- * @example getToken(10, 5);
- * @returns human readable token data
- */
- async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{
- properties: IProperty[];
- owner: ICrossAccountId;
- normalizedOwner: ICrossAccountId;
- } | null> {
- let args;
- if(typeof blockHashAt === 'undefined') {
- args = [collectionId, tokenId];
- }
- else {
- if(propertyKeys.length == 0) {
- const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();
- if(!collection) return null;
- propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);
- }
- args = [collectionId, tokenId, propertyKeys, blockHashAt];
- }
- const tokenData = (await this.helper.callRpc('api.rpc.unique.tokenData', args)).toHuman();
- if(tokenData === null || tokenData.owner === null) return null;
- tokenData.normalizedOwner = CrossAccountId.withNormalizedSubstrate(tokenData.owner);
- return tokenData;
- }
-
- /**
- * Get token's owner
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param blockHashAt optionally query the data at the block with this hash
- * @example getTokenOwner(10, 5);
- * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}
- */
- async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId> {
- let owner;
- if(typeof blockHashAt === 'undefined') {
- owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);
- } else {
- owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);
- }
- return CrossAccountId.fromLowerCaseKeys(owner.toJSON()).toICrossAccountId();
- }
-
- /**
- * Recursively find the address that owns the token
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param blockHashAt
- * @example getTokenTopmostOwner(10, 5);
- * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}
- */
- async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId | null> {
- let owner;
- if(typeof blockHashAt === 'undefined') {
- owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);
- } else {
- owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);
- }
-
- if(owner === null) return null;
-
- return owner.toHuman();
- }
-
- /**
- * Nest one token into another
- * @param signer keyring of signer
- * @param tokenObj token to be nested
- * @param rootTokenObj token to be parent
- * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {
- const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
- const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);
- if(!result) {
- throw Error('Unable to nest token!');
- }
- return result;
- }
-
- /**
- * Remove token from nested state
- * @param signer keyring of signer
- * @param tokenObj token to unnest
- * @param rootTokenObj parent of a token
- * @param toAddressObj address of a new token owner
- * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {
- const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
- const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);
- if(!result) {
- throw Error('Unable to unnest token!');
- }
- return result;
- }
-
- /**
- * Set permissions to change token properties
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param permissions permissions to change a property by the collection admin or token owner
- * @example setTokenPropertyPermissions(
- * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]
- * )
- * @returns true if extrinsic success otherwise false
- */
- async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');
- }
-
- /**
- * Get token property permissions.
- *
- * @param collectionId ID of collection
- * @param propertyKeys optionally filter the returned property permissions to only these keys
- * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);
- * @returns array of key-permission pairs
- */
- async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {
- return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();
- }
-
- /**
- * Set token properties
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection
- * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');
- }
-
- /**
- * Get properties, metadata assigned to a token.
- *
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param propertyKeys optionally filter the returned properties to only these keys
- * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);
- * @returns array of key-value pairs
- */
- async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {
- return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();
- }
-
- /**
- * Delete the provided properties of a token
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param propertyKeys property keys to be deleted
- * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],
- true,
- );
-
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');
- }
-
- /**
- * Mint new collection
- *
- * @param signer keyring of signer
- * @param collectionOptions basic collection options and properties
- * @param mode NFT or RFT type of a collection
- * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")
- * @returns object of the created collection
- */
- async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {
- collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
- collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};
- for(const key of ['name', 'description', 'tokenPrefix']) {
- if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);
- }
-
- let flags = 0;
- // convert CollectionFlags to number and join them in one number
- if(collectionOptions.flags) {
- for(let i = 0; i < collectionOptions.flags.length; i++){
- const flag = collectionOptions.flags[i];
- flags = flags | flag;
- }
- }
- collectionOptions.flags = [flags];
-
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createCollectionEx', [collectionOptions],
- true, // errorLabel,
- );
- return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
- }
-
- getCollectionObject(_collectionId: number): any {
- return null;
- }
-
- getTokenObject(_collectionId: number, _tokenId: number): any {
- return null;
- }
-
- /**
- * Tells whether the given `owner` approves the `operator`.
- * @param collectionId ID of collection
- * @param owner owner address
- * @param operator operator addrees
- * @returns true if operator is enabled
- */
- async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {
- return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();
- }
-
- /** Sets or unsets the approval of a given operator.
- * The `operator` is allowed to transfer all tokens of the `caller` on their behalf.
- * @param operator Operator
- * @param approved Should operator status be granted or revoked?
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],
- true,
- );
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');
- }
-}
-
-
-class NFTGroup extends NFTnRFT {
- /**
- * Get collection object
- * @param collectionId ID of collection
- * @example getCollectionObject(2);
- * @returns instance of UniqueNFTCollection
- */
- override getCollectionObject(collectionId: number): UniqueNFTCollection {
- return new UniqueNFTCollection(collectionId, this.helper);
- }
-
- /**
- * Get token object
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @example getTokenObject(10, 5);
- * @returns instance of UniqueNFTToken
- */
- override getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {
- return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));
- }
-
- /**
- * Is token approved to transfer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param toAccountObj address to be approved
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {
- return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, (await this.getTokenOwner(collectionId, tokenId)))) === 1n;
- }
-
- /**
- * Changes the owner of the token.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param addressObj address of a new owner
- * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {
- return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);
- }
-
- /**
- *
- * Change ownership of a NFT on behalf of the owner.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param fromAddressObj address on behalf of which the token will be sent
- * @param toAddressObj new token owner
- * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {
- return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);
- }
-
- /**
- * Get tokens nested in the provided token
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param blockHashAt optionally query the data at the block with this hash
- * @example getTokenChildren(10, 5);
- * @returns tokens whose depth of nesting is <= 5
- */
- async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {
- let children;
- if(typeof blockHashAt === 'undefined') {
- children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);
- } else {
- children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);
- }
-
- return children.toJSON().map((x: any) => ({collectionId: x.collection, tokenId: x.token}));
- }
-
- /**
- * Mint new collection
- * @param signer keyring of signer
- * @param collectionOptions Collection options
- * @example
- * mintCollection(aliceKeyring, {
- * name: 'New',
- * description: 'New collection',
- * tokenPrefix: 'NEW',
- * })
- * @returns object of the created collection
- */
- override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {
- return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;
- }
-
- /**
- * Mint new token
- * @param signer keyring of signer
- * @param data token data
- * @returns created token object
- */
- async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
- NFT: {
- properties: data.properties,
- },
- }],
- true,
- );
- const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);
- if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');
- if(createdTokens.tokens.length < 1) throw Error('No tokens minted');
- return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
- }
-
- /**
- * Mint multiple NFT tokens
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokens array of tokens with owner and properties
- * @example
- * mintMultipleTokens(aliceKeyring, 10, [{
- * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},
- * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],
- * },{
- * owner: {Ethereum: "0x9F0583DbB855d..."},
- * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],
- * }]);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],
- true,
- );
- const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
- }
-
- /**
- * Mint multiple NFT tokens with one owner
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param owner tokens owner
- * @param tokens array of tokens with owner and properties
- * @example
- * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{
- * properties: [{
- * key: "gender",
- * value: "female",
- * },{
- * key: "age",
- * value: "33",
- * }],
- * }]);
- * @returns array of newly created tokens
- */
- async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {
- const rawTokens = [];
- for(const token of tokens) {
- const raw = {NFT: {properties: token.properties}};
- rawTokens.push(raw);
- }
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
- true,
- );
- const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
- }
-
- /**
- * Set, change, or remove approved address to transfer the ownership of the NFT.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param toAddressObj address to approve
- * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);
- }
-}
-
-
-class RFTGroup extends NFTnRFT {
- /**
- * Get collection object
- * @param collectionId ID of collection
- * @example getCollectionObject(2);
- * @returns instance of UniqueRFTCollection
- */
- override getCollectionObject(collectionId: number): UniqueRFTCollection {
- return new UniqueRFTCollection(collectionId, this.helper);
- }
-
- /**
- * Get token object
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @example getTokenObject(10, 5);
- * @returns instance of UniqueNFTToken
- */
- override getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {
- return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));
- }
-
- /**
- * Get top 10 token owners with the largest number of pieces
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @example getTokenTop10Owners(10, 5);
- * @returns array of top 10 owners
- */
- async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<ICrossAccountId[]> {
- return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map(a => a.toICrossAccountId());
- }
-
- /**
- * Get number of pieces owned by address
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param addressObj address token owner
- * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});
- * @returns number of pieces ownerd by address
- */
- async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();
- }
-
- /**
- * Transfer pieces of token to another address
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param addressObj address of a new owner
- * @param amount number of pieces to be transfered
- * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);
- }
-
- /**
- * Change ownership of some pieces of RFT on behalf of the owner.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param fromAddressObj address on behalf of which the token will be sent
- * @param toAddressObj new token owner
- * @param amount number of pieces to be transfered
- * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
- }
-
- /**
- * Mint new collection
- * @param signer keyring of signer
- * @param collectionOptions Collection options
- * @example
- * mintCollection(aliceKeyring, {
- * name: 'New',
- * description: 'New collection',
- * tokenPrefix: 'NEW',
- * })
- * @returns object of the created collection
- */
- override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {
- return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;
- }
-
- /**
- * Mint new token
- * @param signer keyring of signer
- * @param data token data
- * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});
- * @returns created token object
- */
- async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
- ReFungible: {
- pieces: data.pieces,
- properties: data.properties,
- },
- }],
- true,
- );
- const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);
- if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');
- if(createdTokens.tokens.length < 1) throw Error('No tokens minted');
- return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
- }
-
- mintMultipleTokens(_signer: TSigner, _collectionId: number, _tokens: { owner: ICrossAccountId, pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {
- throw Error('Not implemented');
- // const creationResult = await this.helper.executeExtrinsic(
- // signer,
- // 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],
- // true, // `Unable to mint RFT tokens for ${label}`,
- // );
- // const collection = this.getCollectionObject(collectionId);
- // return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
- }
-
- /**
- * Mint multiple RFT tokens with one owner
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param owner tokens owner
- * @param tokens array of tokens with properties and pieces
- * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);
- * @returns array of newly created RFT tokens
- */
- async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {
- const rawTokens = [];
- for(const token of tokens) {
- const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};
- rawTokens.push(raw);
- }
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
- true,
- );
- const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
- }
-
- /**
- * Destroys a concrete instance of RFT.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param amount number of pieces to be burnt
- * @example burnToken(aliceKeyring, 10, 5);
- * @returns ```true``` if the extrinsic is successful, otherwise ```false```
- */
- override async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {
- return await super.burnToken(signer, collectionId, tokenId, amount);
- }
-
- /**
- * Destroys a concrete instance of RFT on behalf of the owner.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param fromAddressObj address on behalf of which the token will be burnt
- * @param amount number of pieces to be burnt
- * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- override async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);
- }
-
- /**
- * Set, change, or remove approved address to transfer the ownership of the RFT.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param toAddressObj address to approve
- * @param amount number of pieces to be approved
- * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);
- * @returns true if the token success, otherwise false
- */
- override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);
- }
-
- /**
- * Get total number of pieces
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @example getTokenTotalPieces(10, 5);
- * @returns number of pieces
- */
- async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();
- }
-
- /**
- * Change number of token pieces. Signer must be the owner of all token pieces.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param amount new number of pieces
- * @example repartitionToken(aliceKeyring, 10, 5, 12345n);
- * @returns true if the repartion was success, otherwise false
- */
- async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {
- const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);
- const repartitionResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.repartition', [collectionId, tokenId, amount],
- true,
- );
- if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');
- return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');
- }
-}
-
-
-class FTGroup extends CollectionGroup {
- /**
- * Get collection object
- * @param collectionId ID of collection
- * @example getCollectionObject(2);
- * @returns instance of UniqueFTCollection
- */
- getCollectionObject(collectionId: number): UniqueFTCollection {
- return new UniqueFTCollection(collectionId, this.helper);
- }
-
- /**
- * Mint new fungible collection
- * @param signer keyring of signer
- * @param collectionOptions Collection options
- * @param decimalPoints number of token decimals
- * @example
- * mintCollection(aliceKeyring, {
- * name: 'New',
- * description: 'New collection',
- * tokenPrefix: 'NEW',
- * }, 18)
- * @returns newly created fungible collection
- */
- async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {
- collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
- if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');
- collectionOptions.mode = {fungible: decimalPoints};
- for(const key of ['name', 'description', 'tokenPrefix']) {
- if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);
- }
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createCollectionEx', [collectionOptions],
- true,
- );
- return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
- }
-
- /**
- * Mint tokens
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param owner address owner of new tokens
- * @param amount amount of tokens to be meanted
- * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {
- Fungible: {
- value: amount,
- },
- }],
- true, // `Unable to mint fungible tokens for ${label}`,
- );
- return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
- }
-
- /**
- * Mint multiple Fungible tokens with one owner
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param owner tokens owner
- * @param tokens array of tokens with properties and pieces
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: { value: bigint }[], owner: ICrossAccountId): Promise<boolean> {
- const rawTokens = [];
- for(const token of tokens) {
- const raw = {Fungible: {Value: token.value}};
- rawTokens.push(raw);
- }
- const creationResult = await this.helper.executeExtrinsic(
- signer,
- 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
- true,
- );
- return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
- }
-
- /**
- * Get the top 10 owners with the largest balance for the Fungible collection
- * @param collectionId ID of collection
- * @example getTop10Owners(10);
- * @returns array of ```ICrossAccountId```
- */
- async getTop10Owners(collectionId: number): Promise<ICrossAccountId[]> {
- return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map(a => a.toICrossAccountId());
- }
-
- /**
- * Get account balance
- * @param collectionId ID of collection
- * @param addressObj address of owner
- * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})
- * @returns amount of fungible tokens owned by address
- */
- async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();
- }
-
- /**
- * Transfer tokens to address
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param toAddressObj address recipient
- * @param amount amount of tokens to be sent
- * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);
- }
-
- /**
- * Transfer some tokens on behalf of the owner.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param fromAddressObj address on behalf of which tokens will be sent
- * @param toAddressObj address where token to be sent
- * @param amount number of tokens to be sent
- * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
- return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);
- }
-
- /**
- * Destroy some amount of tokens
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param amount amount of tokens to be destroyed
- * @example burnTokens(aliceKeyring, 10, 1000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async burnTokens(signer: IKeyringPair, collectionId: number, amount = 1n): Promise<boolean> {
- return await super.burnToken(signer, collectionId, 0, amount);
- }
-
- /**
- * Burn some tokens on behalf of the owner.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param fromAddressObj address on behalf of which tokens will be burnt
- * @param amount amount of tokens to be burnt
- * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
- return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);
- }
-
- /**
- * Get total collection supply
- * @param collectionId
- * @returns
- */
- async getTotalPieces(collectionId: number): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();
- }
-
- /**
- * Set, change, or remove approved address to transfer tokens.
- *
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param toAddressObj address to be approved
- * @param amount amount of tokens to be approved
- * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- return super.approveToken(signer, collectionId, 0, toAddressObj, amount);
- }
-
- /**
- * Get amount of fungible tokens approved to transfer
- * @param collectionId ID of collection
- * @param fromAddressObj owner of tokens
- * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner
- * @returns number of tokens approved for the transfer
- */
- getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
- return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);
- }
-}
-
-
-class ChainGroup extends HelperGroup<ChainHelperBase> {
- /**
- * Get system properties of a chain
- * @example getChainProperties();
- * @returns ss58Format, token decimals, and token symbol
- */
- getChainProperties(): IChainProperties {
- const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();
- return {
- ss58Format: properties.ss58Format.toJSON(),
- tokenDecimals: properties.tokenDecimals.toJSON(),
- tokenSymbol: properties.tokenSymbol.toJSON(),
- };
- }
-
- /**
- * Get chain header
- * @example getLatestBlockNumber();
- * @returns the number of the last block
- */
- async getLatestBlockNumber(): Promise<number> {
- return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();
- }
-
- /**
- * Get block hash by block number
- * @param blockNumber number of block
- * @example getBlockHashByNumber(12345);
- * @returns hash of a block
- */
- async getBlockHashByNumber(blockNumber: number): Promise<string | null> {
- const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();
- if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;
- return blockHash;
- }
-
- // TODO add docs
- async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {
- const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);
- if(!blockHash) return null;
- return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;
- }
-
- /**
- * Get latest relay block
- * @returns {number} relay block
- */
- async getRelayBlockNumber(): Promise<bigint> {
- const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;
- return BigInt(blockNumber);
- }
-
- /**
- * Get account nonce
- * @param address substrate address
- * @example getNonce("5GrwvaEF5zXb26Fz...");
- * @returns number, account's nonce
- */
- async getNonce(address: TSubstrateAccount): Promise<number> {
- return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();
- }
-}
-
-export class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- /**
- * Get substrate address balance
- * @param address substrate address
- * @example getSubstrate("5GrwvaEF5zXb26Fz...")
- * @returns amount of tokens on address
- */
- async getSubstrate(address: TSubstrateAccount): Promise<bigint> {
- return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();
- }
-
- /**
- * Transfer tokens to substrate address
- * @param signer keyring of signer
- * @param address substrate address of a recipient
- * @param amount amount of tokens to be transfered
- * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);
-
- let transfer = {from: null, to: null, amount: 0n} as any;
- result.result.events.forEach(({event: {data, method, section}}: any) => {
- if((section === 'balances') && (method === 'Transfer')) {
- transfer = {
- from: this.helper.address.normalizeSubstrate(data[0]),
- to: this.helper.address.normalizeSubstrate(data[1]),
- amount: BigInt(data[2]),
- };
- }
- });
- const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from
- && this.helper.address.normalizeSubstrate(address) === transfer.to
- && BigInt(amount) === transfer.amount;
- return isSuccess;
- }
-
- /**
- * Get full substrate balance including free, frozen, and reserved
- * @param address substrate address
- * @returns
- */
- async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {
- const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;
- return {free: accountInfo.free.toBigInt(), frozen: accountInfo.frozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};
- }
-
- /**
- * Get total issuance
- * @returns
- */
- async getTotalIssuance(): Promise<bigint> {
- const total = (await this.helper.callRpc('api.query.balances.totalIssuance', []));
- return total.toBigInt();
- }
-
- async getLocked(address: TSubstrateAccount): Promise<{ id: string, amount: bigint, reason: string }[]> {
- const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();
- return locks.map((lock: any) => ({id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons}));
- }
- async getFrozen(address: TSubstrateAccount): Promise<{ id: string, amount: bigint }[]> {
- const locks = (await this.helper.api!.query.balances.freezes(address)) as unknown as Array<any>;
- return locks.map(lock => ({id: lock.id.toUtf8(), amount: lock.amount.toBigInt()}));
- }
-}
-
-export class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- /**
- * Get ethereum address balance
- * @param address ethereum address
- * @example getEthereum("0x9F0583DbB855d...")
- * @returns amount of tokens on address
- */
- async getEthereum(address: TEthereumAccount): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();
- }
-
- /**
- * Transfer tokens to address
- * @param signer keyring of signer
- * @param address Ethereum address of a recipient
- * @param amount amount of tokens to be transfered
- * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);
-
- let transfer = {from: null, to: null, amount: 0n} as any;
- result.result.events.forEach(({event: {data, method, section}}: any) => {
- if((section === 'balances') && (method === 'Transfer')) {
- transfer = {
- from: data[0].toString(),
- to: data[1].toString(),
- amount: BigInt(data[2]),
- };
- }
- });
- const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from
- && address === transfer.to
- && BigInt(amount) === transfer.amount;
- return isSuccess;
- }
-}
-
-class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- subBalanceGroup: SubstrateBalanceGroup<T>;
- ethBalanceGroup: EthereumBalanceGroup<T>;
-
- constructor(helper: T) {
- super(helper);
- this.subBalanceGroup = new SubstrateBalanceGroup(helper);
- this.ethBalanceGroup = new EthereumBalanceGroup(helper);
- }
-
- getCollectionCreationPrice(): bigint {
- return 2n * this.getOneTokenNominal();
- }
- /**
- * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).
- * @example getOneTokenNominal()
- * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.
- */
- getOneTokenNominal(): bigint {
- const chainProperties = this.helper.chain.getChainProperties();
- return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);
- }
-
- /**
- * Get substrate address balance
- * @param address substrate address
- * @example getSubstrate("5GrwvaEF5zXb26Fz...")
- * @returns amount of tokens on address
- */
- getSubstrate(address: TSubstrateAccount): Promise<bigint> {
- return this.subBalanceGroup.getSubstrate(address);
- }
-
- /**
- * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved
- * @param address substrate address
- * @returns
- */
- getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {
- return this.subBalanceGroup.getSubstrateFull(address);
- }
-
- /**
- * Get total issuance
- * @returns
- */
- getTotalIssuance(): Promise<bigint> {
- return this.subBalanceGroup.getTotalIssuance();
- }
-
- /**
- * Get locked balances
- * @param address substrate address
- * @returns locked balances with reason via api.query.balances.locks
- * @deprecated all the methods should switch to getFrozen
- */
- getLocked(address: TSubstrateAccount) {
- return this.subBalanceGroup.getLocked(address);
- }
-
- /**
- * Get frozen balances
- * @param address substrate address
- * @returns frozen balances with id via api.query.balances.freezes
- */
- getFrozen(address: TSubstrateAccount) {
- return this.subBalanceGroup.getFrozen(address);
- }
-
- /**
- * Get ethereum address balance
- * @param address ethereum address
- * @example getEthereum("0x9F0583DbB855d...")
- * @returns amount of tokens on address
- */
- getEthereum(address: TEthereumAccount): Promise<bigint> {
- return this.ethBalanceGroup.getEthereum(address);
- }
-
- async setBalanceSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint) {
- await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceSetBalance', [address, amount], true);
- }
-
- /**
- * Transfer tokens to substrate address
- * @param signer keyring of signer
- * @param address substrate address of a recipient
- * @param amount amount of tokens to be transfered
- * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);
- * @returns ```true``` if extrinsic success, otherwise ```false```
- */
- transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
- return this.subBalanceGroup.transferToSubstrate(signer, address, amount);
- }
-
- async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);
-
- let transfer = {from: null, to: null, amount: 0n} as any;
- result.result.events.forEach(({event: {data, method, section}}: any) => {
- if((section === 'balances') && (method === 'Transfer')) {
- transfer = {
- from: this.helper.address.normalizeSubstrate(data[0]),
- to: this.helper.address.normalizeSubstrate(data[1]),
- amount: BigInt(data[2]),
- };
- }
- });
- let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;
- isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;
- isSuccess = isSuccess && BigInt(amount) === transfer.amount;
- return isSuccess;
- }
-
- /**
- * Transfer tokens with the unlock period
- * @param signer signers Keyring
- * @param address Substrate address of recipient
- * @param schedule Schedule params
- * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 5000
- */
- async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: { start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }): Promise<void> {
- const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);
- const event = result.result.events
- .find((e: any) => e.event.section === 'vesting' &&
- e.event.method === 'VestingScheduleAdded' &&
- e.event.data[0].toHuman() === signer.address);
- if(!event) throw Error('Cannot find transfer in events');
- }
-
- /**
- * Get schedule for recepient of vested transfer
- * @param address Substrate address of recipient
- * @returns
- */
- async getVestingSchedules(address: TSubstrateAccount): Promise<{ start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }[]> {
- const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();
- return schedule.map((schedule: any) => ({
- start: BigInt(schedule.start),
- period: BigInt(schedule.period),
- periodCount: BigInt(schedule.periodCount),
- perPeriod: BigInt(schedule.perPeriod),
- }));
- }
-
- /**
- * Claim vested tokens
- * @param signer signers Keyring
- */
- async claim(signer: TSigner) {
- const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);
- const event = result.result.events
- .find((e: any) => e.event.section === 'vesting' &&
- e.event.method === 'Claimed' &&
- e.event.data[0].toHuman() === signer.address);
- if(!event) throw Error('Cannot find claim in events');
- }
-}
-
-class AddressGroup extends HelperGroup<ChainHelperBase> {
- /**
- * Normalizes the address to the specified ss58 format, by default ```42```.
- * @param address substrate address
- * @param ss58Format format for address conversion, by default ```42```
- * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
- * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation
- */
- normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {
- return CrossAccountId.normalizeSubstrateAddress({Substrate: address}, ss58Format);
- }
-
- /**
- * Get address in the connected chain format
- * @param address substrate address
- * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network
- * @returns address in chain format
- */
- normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {
- return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);
- }
-
- /**
- * Get substrate mirror of an ethereum address
- * @param ethAddress ethereum address
- * @param toChainFormat false for normalized account
- * @example ethToSubstrate('0x9F0583DbB855d...')
- * @returns substrate mirror of a provided ethereum address
- */
- ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat = false): TSubstrateAccount {
- return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);
- }
-
- /**
- * Get ethereum mirror of a substrate address
- * @param subAddress substrate account
- * @example substrateToEth("5DnSF6RRjwteE3BrC...")
- * @returns ethereum mirror of a provided substrate address
- */
- substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {
- return CrossAccountId.translateSubToEth(subAddress);
- }
-
- /**
- * Encode key to substrate address
- * @param key key for encoding address
- * @param ss58Format prefix for encoding to the address of the corresponding network
- * @returns encoded substrate address
- */
- encodeSubstrateAddress(key: Uint8Array | string | bigint, ss58Format = 42): string {
- const u8a: Uint8Array = typeof key === 'string'
- ? hexToU8a(key)
- : typeof key === 'bigint'
- ? hexToU8a(key.toString(16))
- : key;
-
- if(ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {
- throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);
- }
-
- const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];
- if(!allowedDecodedLengths.includes(u8a.length)) {
- throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);
- }
-
- const u8aPrefix = ss58Format < 64
- ? new Uint8Array([ss58Format])
- : new Uint8Array([
- ((ss58Format & 0xfc) >> 2) | 0x40,
- (ss58Format >> 8) | ((ss58Format & 0x03) << 6),
- ]);
-
- const input = u8aConcat(u8aPrefix, u8a);
-
- return base58Encode(u8aConcat(
- input,
- blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),
- ));
- }
-
- /**
- * Restore substrate address from bigint representation
- * @param number decimal representation of substrate address
- * @returns substrate address
- */
- restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {
- if(this.helper.api === null) {
- throw 'Not connected';
- }
- const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();
- if(res === undefined || res === null) {
- throw 'Restore address error';
- }
- return res.toString();
- }
-
- /**
- * Convert etherium cross account id to substrate cross account id
- * @param ethCrossAccount etherium cross account
- * @returns substrate cross account id
- */
- convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {
- if(ethCrossAccount.sub === '0') {
- return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};
- }
-
- const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));
- return {Substrate: ss58};
- }
-
- paraSiblingSovereignAccount(paraid: number) {
- // We are getting a *sibling* parachain sovereign account,
- // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c
- const siblingPrefix = '0x7369626c';
-
- const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);
- const suffix = '000000000000000000000000000000000000000000000000';
-
- return siblingPrefix + encodedParaId + suffix;
- }
-}
-
-
-class StakingGroup extends HelperGroup<UniqueHelper> {
- /**
- * Stake tokens for App Promotion
- * @param signer keyring of signer
- * @param amountToStake amount of tokens to stake
- * @param label extra label for log
- * @returns
- */
- async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;
- await this.helper.executeExtrinsic(
- signer, 'api.tx.appPromotion.stake',
- [amountToStake], true,
- );
- // TODO extract info from stakeResult
- return true;
- }
-
- /**
- * Unstake all staked tokens
- * @param signer keyring of signer
- * @param amountToUnstake amount of tokens to unstake
- * @param label extra label for log
- * @returns block hash where unstake happened
- */
- async unstakeAll(signer: TSigner, label?: string): Promise<string> {
- if(typeof label === 'undefined') label = `${signer.address}`;
- const unstakeResult = await this.helper.executeExtrinsic(
- signer, 'api.tx.appPromotion.unstakeAll',
- [], true,
- );
- return unstakeResult.blockHash;
- }
-
- /**
- * Unstake the part of a staked tokens
- * @param signer keyring of signer
- * @param amount amount of tokens to unstake
- * @param label extra label for log
- * @returns block hash where unstake happened
- */
- async unstakePartial(signer: TSigner, amount: bigint, label?: string): Promise<string> {
- if(typeof label === 'undefined') label = `${signer.address}`;
- const unstakeResult = await this.helper.executeExtrinsic(
- signer, 'api.tx.appPromotion.unstakePartial',
- [amount], true,
- );
- return unstakeResult.blockHash;
- }
-
- /**
- * Get total number of active stakes
- * @param address substrate address
- * @returns {number}
- */
- async getStakesNumber(address: ICrossAccountId): Promise<number> {
- if('Ethereum' in address) throw Error('only substrate address');
- return (await this.helper.callRpc('api.query.appPromotion.stakesPerAccount', [address.Substrate])).toNumber();
- }
-
- /**
- * Get total staked amount for address
- * @param address substrate or ethereum address
- * @returns total staked amount
- */
- async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {
- if(address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();
- return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();
- }
-
- /**
- * Get total staked per block
- * @param address substrate or ethereum address
- * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block
- */
- async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
- const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);
- return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => ({
- block: block.toBigInt(),
- amount: amount.toBigInt(),
- }));
- }
-
- /**
- * Get total pending unstake amount for address
- * @param address substrate or ethereum address
- * @returns total pending unstake amount
- */
- async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {
- return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();
- }
-
- /**
- * Get pending unstake amount per block for address
- * @param address substrate or ethereum address
- * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block
- */
- async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
- const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);
- const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => ({
- block: block.toBigInt(),
- amount: amount.toBigInt(),
- }));
- return result;
- }
-}
-
-
-class PreimageGroup extends HelperGroup<UniqueHelper> {
- async getPreimageInfo(h256: string) {
- return (await this.helper.callRpc('api.query.preimage.statusFor', [h256])).toJSON();
- }
-
- /**
- * Create a preimage from an API call.
- * @param signer keyring of the signer.
- * @param call an extrinsic call
- * @example await notePreimageFromCall(preimageMaker,
- * helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd])
- * );
- * @returns promise of extrinsic execution.
- */
- notePreimageFromCall(signer: TSigner, call: any, returnPreimageHash = false) {
- return this.notePreimage(signer, call.method.toHex(), returnPreimageHash);
- }
-
- /**
- * Create a preimage with a hex or a byte array.
- * @param signer keyring of the signer.
- * @param bytes preimage encoded in hex or a byte array, e.g. an extrinsic call.
- * @example await notePreimage(preimageMaker,
- * helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex()
- * );
- * @returns promise of extrinsic execution.
- */
- async notePreimage(signer: TSigner, bytes: string | Uint8Array, returnPreimageHash = false) {
- const promise = this.helper.executeExtrinsic(signer, 'api.tx.preimage.notePreimage', [bytes]);
- if(returnPreimageHash) {
- const result = await promise;
- const events = result.result.events.filter((x: any) => x.event.method === 'Noted' && x.event.section === 'preimage');
- const preimageHash = events[0].event.data[0].toHuman();
- return preimageHash;
- }
- return promise;
- }
-
- /**
- * Delete an existing preimage and return the deposit.
- * @param signer keyring of the signer - either the owner or the preimage manager (sudo).
- * @param h256 hash of the preimage.
- * @returns promise of extrinsic execution.
- */
- unnotePreimage(signer: TSigner, h256: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unnotePreimage', [h256]);
- }
-
- /**
- * Request a preimage be uploaded to the chain without paying any fees or deposits.
- * @param signer keyring of the signer - either the owner or the preimage manager (sudo).
- * @param h256 hash of the preimage.
- * @returns promise of extrinsic execution.
- */
- requestPreimage(signer: TSigner, h256: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.preimage.requestPreimage', [h256]);
- }
-
- /**
- * Clear a previously made request for a preimage.
- * @param signer keyring of the signer - either the owner or the preimage manager (sudo).
- * @param h256 hash of the preimage.
- * @returns promise of extrinsic execution.
- */
- unrequestPreimage(signer: TSigner, h256: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unrequestPreimage', [h256]);
- }
-}
-
-class UtilityGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- async batch(signer: TSigner, txs: any[]) {
- return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batch', [txs]);
- }
-
- async batchAll(signer: TSigner, txs: any[]) {
- return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batchAll', [txs]);
- }
-
- batchAllCall(txs: any[]) {
- return this.helper.constructApiCall('api.tx.utility.batchAll', [txs]);
- }
-}
-
-export type ChainHelperBaseConstructor = new (...args: any[]) => ChainHelperBase;
-export type UniqueHelperConstructor = new (...args: any[]) => UniqueHelper;
-
-export class UniqueHelper extends ChainHelperBase {
- balance: BalanceGroup<UniqueHelper>;
- collection: CollectionGroup;
- nft: NFTGroup;
- rft: RFTGroup;
- ft: FTGroup;
- staking: StakingGroup;
- preimage: PreimageGroup;
- utility: UtilityGroup<UniqueHelper>;
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? UniqueHelper);
-
- this.balance = new BalanceGroup(this);
- this.collection = new CollectionGroup(this);
- this.nft = new NFTGroup(this);
- this.rft = new RFTGroup(this);
- this.ft = new FTGroup(this);
- this.staking = new StakingGroup(this);
- this.preimage = new PreimageGroup(this);
- this.utility = new UtilityGroup(this);
- }
-}
-
-export class UniqueBaseCollection {
- helper: UniqueHelper;
- collectionId: number;
-
- constructor(collectionId: number, uniqueHelper: UniqueHelper) {
- this.collectionId = collectionId;
- this.helper = uniqueHelper;
- }
-
- async getData() {
- return await this.helper.collection.getData(this.collectionId);
- }
-
- async getLastTokenId() {
- return await this.helper.collection.getLastTokenId(this.collectionId);
- }
-
- async doesTokenExist(tokenId: number) {
- return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);
- }
-
- async getAdmins() {
- return await this.helper.collection.getAdmins(this.collectionId);
- }
-
- async getAllowList() {
- return await this.helper.collection.getAllowList(this.collectionId);
- }
-
- async getEffectiveLimits() {
- return await this.helper.collection.getEffectiveLimits(this.collectionId);
- }
-
- async getProperties(propertyKeys?: string[] | null) {
- return await this.helper.collection.getProperties(this.collectionId, propertyKeys);
- }
-
- async getPropertiesConsumedSpace() {
- return await this.helper.collection.getPropertiesConsumedSpace(this.collectionId);
- }
-
- async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {
- return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);
- }
-
- async getOptions() {
- return await this.helper.collection.getCollectionOptions(this.collectionId);
- }
-
- async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {
- return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);
- }
-
- async confirmSponsorship(signer: TSigner) {
- return await this.helper.collection.confirmSponsorship(signer, this.collectionId);
- }
-
- async removeSponsor(signer: TSigner) {
- return await this.helper.collection.removeSponsor(signer, this.collectionId);
- }
-
- async setLimits(signer: TSigner, limits: ICollectionLimits) {
- return await this.helper.collection.setLimits(signer, this.collectionId, limits);
- }
-
- async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {
- return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);
- }
-
- async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {
- return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);
- }
-
- async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {
- return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);
- }
-
- async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {
- return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);
- }
-
- async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {
- return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);
- }
-
- async setProperties(signer: TSigner, properties: IProperty[]) {
- return await this.helper.collection.setProperties(signer, this.collectionId, properties);
- }
-
- async deleteProperties(signer: TSigner, propertyKeys: string[]) {
- return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);
- }
-
- async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {
- return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);
- }
-
- async enableNesting(signer: TSigner, permissions: INestingPermissions) {
- return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);
- }
-
- async disableNesting(signer: TSigner) {
- return await this.helper.collection.disableNesting(signer, this.collectionId);
- }
-
- async burn(signer: TSigner) {
- return await this.helper.collection.burn(signer, this.collectionId);
- }
-}
-
-export class UniqueNFTCollection extends UniqueBaseCollection {
- getTokenObject(tokenId: number) {
- return new UniqueNFToken(tokenId, this);
- }
-
- async getTokensByAddress(addressObj: ICrossAccountId) {
- return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);
- }
-
- async getToken(tokenId: number, blockHashAt?: string) {
- return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);
- }
-
- async getTokenOwner(tokenId: number, blockHashAt?: string) {
- return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);
- }
-
- async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {
- return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);
- }
-
- async getTokenChildren(tokenId: number, blockHashAt?: string) {
- return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);
- }
-
- async getPropertyPermissions(propertyKeys: string[] | null = null) {
- return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);
- }
-
- async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {
- return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);
- }
-
- async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {
- const api = this.helper.getApi();
- const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;
-
- return props?.consumedSpace ?? 0;
- }
-
- async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {
- return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);
- }
-
- async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
- return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);
- }
-
- async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {
- return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);
- }
-
- async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {
- return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);
- }
-
- async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {
- return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});
- }
-
- async mintMultipleTokens(signer: TSigner, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]) {
- return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);
- }
-
- async burnToken(signer: TSigner, tokenId: number) {
- return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);
- }
-
- async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {
- return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);
- }
-
- async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {
- return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);
- }
-
- async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {
- return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);
- }
-
- async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {
- return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
- }
-
- async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
- return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
- }
-
- async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
- return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
- }
-}
-
-export class UniqueRFTCollection extends UniqueBaseCollection {
- getTokenObject(tokenId: number) {
- return new UniqueRFToken(tokenId, this);
- }
-
- async getToken(tokenId: number, blockHashAt?: string) {
- return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);
- }
-
- async getTokenOwner(tokenId: number, blockHashAt?: string) {
- return await this.helper.rft.getTokenOwner(this.collectionId, tokenId, blockHashAt);
- }
-
- async getTokensByAddress(addressObj: ICrossAccountId) {
- return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);
- }
-
- async getTop10TokenOwners(tokenId: number) {
- return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);
- }
-
- async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {
- return await this.helper.rft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);
- }
-
- async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {
- return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);
- }
-
- async getTokenTotalPieces(tokenId: number) {
- return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);
- }
-
- async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
- return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);
- }
-
- async getPropertyPermissions(propertyKeys: string[] | null = null) {
- return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);
- }
-
- async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {
- return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);
- }
-
- async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {
- const api = this.helper.getApi();
- const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;
-
- return props?.consumedSpace ?? 0;
- }
-
- async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);
- }
-
- async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);
- }
-
- async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);
- }
-
- async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {
- return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);
- }
-
- async mintToken(signer: TSigner, pieces = 1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {
- return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});
- }
-
- async mintMultipleTokens(signer: TSigner, tokens: { pieces: bigint, owner: ICrossAccountId, properties?: IProperty[] }[]) {
- return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);
- }
-
- async burnToken(signer: TSigner, tokenId: number, amount = 1n) {
- return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);
- }
-
- async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);
- }
-
- async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {
- return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);
- }
-
- async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {
- return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);
- }
-
- async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {
- return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
- }
-
- async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
- return await this.helper.rft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
- }
-
- async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
- return await this.helper.rft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
- }
-}
-
-export class UniqueFTCollection extends UniqueBaseCollection {
- async getBalance(addressObj: ICrossAccountId) {
- return await this.helper.ft.getBalance(this.collectionId, addressObj);
- }
-
- async getTotalPieces() {
- return await this.helper.ft.getTotalPieces(this.collectionId);
- }
-
- async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
- return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);
- }
-
- async getTop10Owners() {
- return await this.helper.ft.getTop10Owners(this.collectionId);
- }
-
- async mint(signer: TSigner, amount = 1n, owner: ICrossAccountId = {Substrate: signer.address}) {
- return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);
- }
-
- async mintWithOneOwner(signer: TSigner, tokens: { value: bigint }[], owner: ICrossAccountId = {Substrate: signer.address}) {
- return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);
- }
-
- async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);
- }
-
- async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);
- }
-
- async burnTokens(signer: TSigner, amount = 1n) {
- return await this.helper.ft.burnTokens(signer, this.collectionId, amount);
- }
-
- async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);
- }
-
- async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);
- }
-}
-
-export class UniqueBaseToken {
- collection: UniqueNFTCollection | UniqueRFTCollection;
- collectionId: number;
- tokenId: number;
-
- constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {
- this.collection = collection;
- this.collectionId = collection.collectionId;
- this.tokenId = tokenId;
- }
-
- async getNextSponsored(addressObj: ICrossAccountId) {
- return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);
- }
-
- async getProperties(propertyKeys?: string[] | null) {
- return await this.collection.getTokenProperties(this.tokenId, propertyKeys);
- }
-
- async getTokenPropertiesConsumedSpace() {
- return await this.collection.getTokenPropertiesConsumedSpace(this.tokenId);
- }
-
- async setProperties(signer: TSigner, properties: IProperty[]) {
- return await this.collection.setTokenProperties(signer, this.tokenId, properties);
- }
-
- async deleteProperties(signer: TSigner, propertyKeys: string[]) {
- return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);
- }
-
- async doesExist() {
- return await this.collection.doesTokenExist(this.tokenId);
- }
-
- nestingAccount(): ICrossAccountId {
- return this.collection.helper.util.getTokenAccount(this);
- }
-}
-
-export class UniqueNFToken extends UniqueBaseToken {
- declare collection: UniqueNFTCollection;
-
- constructor(tokenId: number, collection: UniqueNFTCollection) {
- super(tokenId, collection);
- this.collection = collection;
- }
-
- async getData(blockHashAt?: string) {
- return await this.collection.getToken(this.tokenId, blockHashAt);
- }
-
- async getOwner(blockHashAt?: string) {
- return await this.collection.getTokenOwner(this.tokenId, blockHashAt);
- }
-
- async getTopmostOwner(blockHashAt?: string) {
- return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);
- }
-
- async getChildren(blockHashAt?: string) {
- return await this.collection.getTokenChildren(this.tokenId, blockHashAt);
- }
-
- async nest(signer: TSigner, toTokenObj: IToken) {
- return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
- }
-
- async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
- return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
- }
-
- async transfer(signer: TSigner, addressObj: ICrossAccountId) {
- return await this.collection.transferToken(signer, this.tokenId, addressObj);
- }
-
- async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
- return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);
- }
-
- async approve(signer: TSigner, toAddressObj: ICrossAccountId) {
- return await this.collection.approveToken(signer, this.tokenId, toAddressObj);
- }
-
- async isApproved(toAddressObj: ICrossAccountId) {
- return await this.collection.isTokenApproved(this.tokenId, toAddressObj);
- }
-
- async burn(signer: TSigner) {
- return await this.collection.burnToken(signer, this.tokenId);
- }
-
- async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {
- return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);
- }
-}
-
-export class UniqueRFToken extends UniqueBaseToken {
- declare collection: UniqueRFTCollection;
-
- constructor(tokenId: number, collection: UniqueRFTCollection) {
- super(tokenId, collection);
- this.collection = collection;
- }
-
- async getData(blockHashAt?: string) {
- return await this.collection.getToken(this.tokenId, blockHashAt);
- }
-
- async getOwner(blockHashAt?: string) {
- return await this.collection.getTokenOwner(this.tokenId, blockHashAt);
- }
-
- async getTop10Owners() {
- return await this.collection.getTop10TokenOwners(this.tokenId);
- }
-
- async getTopmostOwner(blockHashAt?: string) {
- return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);
- }
-
- async nest(signer: TSigner, toTokenObj: IToken) {
- return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
- }
-
- async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
- return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
- }
-
- async getBalance(addressObj: ICrossAccountId) {
- return await this.collection.getTokenBalance(this.tokenId, addressObj);
- }
-
- async getTotalPieces() {
- return await this.collection.getTokenTotalPieces(this.tokenId);
- }
-
- async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {
- return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);
- }
-
- async transfer(signer: TSigner, addressObj: ICrossAccountId, amount = 1n) {
- return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);
- }
-
- async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);
- }
-
- async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {
- return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);
- }
-
- async repartition(signer: TSigner, amount: bigint) {
- return await this.collection.repartitionToken(signer, this.tokenId, amount);
- }
-
- async burn(signer: TSigner, amount = 1n) {
- return await this.collection.burnToken(signer, this.tokenId, amount);
- }
-
- async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {
- return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);
- }
-}
js-packages/playgrounds/src/unique.xcm.tsdiffbeforeafterboth--- a/js-packages/playgrounds/src/unique.xcm.ts
+++ /dev/null
@@ -1,375 +0,0 @@
-import {ApiPromise, WsProvider} from '@polkadot/api';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {ChainHelperBase, EthereumBalanceGroup, HelperGroup, SubstrateBalanceGroup, UniqueHelper} from './unique.js';
-import type {ILogger, TSigner, TSubstrateAccount} from './types.js';
-import type {AcalaAssetMetadata, DemocracyStandardAccountVote, IForeignAssetMetadata, MoonbeamAssetInfo} from './types.xcm.js';
-
-
-export class XcmChainHelper extends ChainHelperBase {
- override async connect(wsEndpoint: string, _listeners?: any): Promise<void> {
- const wsProvider = new WsProvider(wsEndpoint);
- this.api = new ApiPromise({
- provider: wsProvider,
- });
- await this.api.isReadyOrError;
- this.network = await UniqueHelper.detectNetwork(this.api);
- }
-}
-
-class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {
- async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {
- await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);
- }
-}
-
-class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {
- makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {
- const apiPrefix = 'api.tx.assetManager.';
-
- const registerTx = this.helper.constructApiCall(
- apiPrefix + 'registerForeignAsset',
- [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],
- );
-
- const setUnitsTx = this.helper.constructApiCall(
- apiPrefix + 'setAssetUnitsPerSecond',
- [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],
- );
-
- const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);
- const encodedProposal = batchCall?.method.toHex() || '';
- return encodedProposal;
- }
-
- async assetTypeId(location: any) {
- return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);
- }
-}
-
-class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {
- notePreimagePallet: string;
-
- constructor(helper: MoonbeamHelper, options: { [key: string]: any } = {}) {
- super(helper);
- this.notePreimagePallet = options.notePreimagePallet;
- }
-
- async notePreimage(signer: TSigner, encodedProposal: string) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);
- }
-
- externalProposeMajority(proposal: any) {
- return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);
- }
-
- fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {
- return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);
- }
-
- async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {
- await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);
- }
-}
-
-class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {
- collective: string;
-
- constructor(helper: MoonbeamHelper, collective: string) {
- super(helper);
-
- this.collective = collective;
- }
-
- async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);
- }
-
- async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);
- }
-
- async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);
- }
-
- async proposalCount() {
- return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));
- }
-}
-
-class PolkadexXcmHelperGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- async whitelistToken(signer: TSigner, assetId: any) {
- await this.helper.executeExtrinsic(signer, 'api.tx.xcmHelper.whitelistToken', [assetId], true);
- }
-}
-
-export class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {
- async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {
- await this.helper.executeExtrinsic(
- signer,
- 'api.tx.foreignAssets.registerForeignAsset',
- [ownerAddress, location, metadata],
- true,
- );
- }
-
- async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {
- await this.helper.executeExtrinsic(
- signer,
- 'api.tx.foreignAssets.updateForeignAsset',
- [foreignAssetId, location, metadata],
- true,
- );
- }
-}
-
-export class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- palletName: string;
-
- constructor(helper: T, palletName: string) {
- super(helper);
-
- this.palletName = palletName;
- }
-
- async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);
- }
-
- async setSafeXcmVersion(signer: TSigner, version: number) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.forceDefaultXcmVersion`, [version], true);
- }
-
- async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {
- await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);
- }
-
- async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint, xcmVersion = 3) {
- const destinationContent = {
- parents: 0,
- interior: {
- X1: {
- Parachain: destinationParaId,
- },
- },
- };
-
- const beneficiaryContent = {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: targetAccount,
- },
- },
- },
- };
-
- const assetsContent = [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: amount,
- },
- },
- ];
-
- let destination;
- let beneficiary;
- let assets;
-
- if(xcmVersion == 2) {
- destination = {V1: destinationContent};
- beneficiary = {V1: beneficiaryContent};
- assets = {V1: assetsContent};
-
- } else if(xcmVersion == 3) {
- destination = {V2: destinationContent};
- beneficiary = {V2: beneficiaryContent};
- assets = {V2: assetsContent};
-
- } else {
- throw Error('Unknown XCM version: ' + xcmVersion);
- }
-
- const feeAssetItem = 0;
-
- await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem);
- }
-
- async send(signer: IKeyringPair, destination: any, message: any) {
- await this.helper.executeExtrinsic(
- signer,
- `api.tx.${this.palletName}.send`,
- [
- destination,
- message,
- ],
- true,
- );
- }
-}
-
-export class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) {
- await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);
- }
-
- async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) {
- await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);
- }
-
- async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) {
- await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);
- }
-}
-
-
-
-export class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- async accounts(address: string, currencyId: any) {
- const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;
- return BigInt(free);
- }
-}
-
-export class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {
- async create(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint) {
- await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);
- }
-
- async forceCreate(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint, isSufficient = true) {
- await this.helper.executeExtrinsic(signer, 'api.tx.assets.forceCreate', [assetId, admin, isSufficient, minimalBalance], true);
- }
-
- async setMetadata(signer: TSigner, assetId: number | bigint, name: string, symbol: string, decimals: number) {
- await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);
- }
-
- async mint(signer: TSigner, assetId: number | bigint, beneficiary: string, amount: bigint) {
- await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);
- }
-
- async account(assetId: string | number | bigint, address: string) {
- const accountAsset = (
- await this.helper.callRpc('api.query.assets.account', [assetId, address])
- ).toJSON()! as any;
-
- if(accountAsset !== null) {
- return BigInt(accountAsset['balance']);
- } else {
- return null;
- }
- }
-}
-
-export class RelayHelper extends XcmChainHelper {
- balance: SubstrateBalanceGroup<RelayHelper>;
- xcm: XcmGroup<RelayHelper>;
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? RelayHelper);
-
- this.balance = new SubstrateBalanceGroup(this);
- this.xcm = new XcmGroup(this, 'xcmPallet');
- }
-}
-
-export class WestmintHelper extends XcmChainHelper {
- balance: SubstrateBalanceGroup<WestmintHelper>;
- xcm: XcmGroup<WestmintHelper>;
- assets: AssetsGroup<WestmintHelper>;
- xTokens: XTokensGroup<WestmintHelper>;
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? WestmintHelper);
-
- this.balance = new SubstrateBalanceGroup(this);
- this.xcm = new XcmGroup(this, 'polkadotXcm');
- this.assets = new AssetsGroup(this);
- this.xTokens = new XTokensGroup(this);
- }
-}
-
-export class MoonbeamHelper extends XcmChainHelper {
- balance: EthereumBalanceGroup<MoonbeamHelper>;
- assetManager: MoonbeamAssetManagerGroup;
- assets: AssetsGroup<MoonbeamHelper>;
- xTokens: XTokensGroup<MoonbeamHelper>;
- democracy: MoonbeamDemocracyGroup;
- collective: {
- council: MoonbeamCollectiveGroup,
- techCommittee: MoonbeamCollectiveGroup,
- };
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? MoonbeamHelper);
-
- this.balance = new EthereumBalanceGroup(this);
- this.assetManager = new MoonbeamAssetManagerGroup(this);
- this.assets = new AssetsGroup(this);
- this.xTokens = new XTokensGroup(this);
- this.democracy = new MoonbeamDemocracyGroup(this, options);
- this.collective = {
- council: new MoonbeamCollectiveGroup(this, 'councilCollective'),
- techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),
- };
- }
-}
-
-export class AstarHelper extends XcmChainHelper {
- balance: SubstrateBalanceGroup<AstarHelper>;
- assets: AssetsGroup<AstarHelper>;
- xcm: XcmGroup<AstarHelper>;
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? AstarHelper);
-
- this.balance = new SubstrateBalanceGroup(this);
- this.assets = new AssetsGroup(this);
- this.xcm = new XcmGroup(this, 'polkadotXcm');
- }
-}
-
-export class AcalaHelper extends XcmChainHelper {
- balance: SubstrateBalanceGroup<AcalaHelper>;
- assetRegistry: AcalaAssetRegistryGroup;
- xTokens: XTokensGroup<AcalaHelper>;
- tokens: TokensGroup<AcalaHelper>;
- xcm: XcmGroup<AcalaHelper>;
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? AcalaHelper);
-
- this.balance = new SubstrateBalanceGroup(this);
- this.assetRegistry = new AcalaAssetRegistryGroup(this);
- this.xTokens = new XTokensGroup(this);
- this.tokens = new TokensGroup(this);
- this.xcm = new XcmGroup(this, 'polkadotXcm');
- }
-}
-
-export class PolkadexHelper extends XcmChainHelper {
- assets: AssetsGroup<PolkadexHelper>;
- balance: SubstrateBalanceGroup<PolkadexHelper>;
- xTokens: XTokensGroup<PolkadexHelper>;
- xcm: XcmGroup<PolkadexHelper>;
- xcmHelper: PolkadexXcmHelperGroup<PolkadexHelper>;
-
- constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
- super(logger, options.helperBase ?? PolkadexHelper);
-
- this.assets = new AssetsGroup(this);
- this.balance = new SubstrateBalanceGroup(this);
- this.xTokens = new XTokensGroup(this);
- this.xcm = new XcmGroup(this, 'polkadotXcm');
- this.xcmHelper = new PolkadexXcmHelperGroup(this);
- }
-}
-
js-packages/playgrounds/tsconfig.jsondiffbeforeafterboth--- a/js-packages/playgrounds/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "../tsconfig.packages.json",
- "compilerOptions": {
- "rootDir": "./src",
- "outDir": "dist"
- },
- "references": [
- { "path": "../types/tsconfig.json" },
- ]
-}
\ No newline at end of file
js-packages/playgrounds/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/playgrounds/types.ts
@@ -0,0 +1,232 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import type {IKeyringPair} from '@polkadot/types/types';
+
+export const NON_EXISTENT_COLLECTION_ID = 4_294_967_295;
+
+export const MILLISECS_PER_BLOCK = 12000;
+export const MINUTES = 60_000 / MILLISECS_PER_BLOCK;
+export const HOURS = MINUTES * 60;
+export const DAYS = HOURS * 24;
+
+export interface IEvent {
+ section: string;
+ method: string;
+ index: [number, number] | string;
+ data: any[];
+ phase: {applyExtrinsic: number} | 'Initialization',
+}
+
+export interface IPhasicEvent {
+ phase: any, // {ApplyExtrinsic: number} | 'Initialization',
+ event: IEvent;
+}
+
+export interface ITransactionResult {
+ status: 'Fail' | 'Success';
+ result: {
+ dispatchError: any,
+ events: IPhasicEvent[];
+ },
+ blockHash: string,
+ moduleError?: string | object;
+}
+
+export interface ISubscribeBlockEventsData {
+ number: number;
+ hash: string;
+ timestamp: number;
+ events: IEvent[];
+}
+
+export interface ILogger {
+ log: (msg: any, level?: string) => void;
+ level: {
+ ERROR: 'ERROR';
+ WARNING: 'WARNING';
+ INFO: 'INFO';
+ [key: string]: string;
+ }
+}
+
+export interface IUniqueHelperLog {
+ executedAt: number;
+ executionTime: number;
+ type: 'extrinsic' | 'rpc';
+ status: 'Fail' | 'Success';
+ call: string;
+ params: any[];
+ moduleError?: string;
+ dispatchError?: any;
+ events?: any;
+}
+
+export interface IApiListeners {
+ connected?: (...args: any[]) => any;
+ disconnected?: (...args: any[]) => any;
+ error?: (...args: any[]) => any;
+ ready?: (...args: any[]) => any;
+ decorated?: (...args: any[]) => any;
+}
+
+export type ICrossAccountId = {
+ Substrate: TSubstrateAccount;
+} | {
+ Ethereum: TEthereumAccount;
+}
+
+export type ICrossAccountIdLower = {
+ substrate: TSubstrateAccount;
+} | {
+ ethereum: TEthereumAccount;
+};
+
+export interface IEthCrossAccountId {
+ 0: TEthereumAccount;
+ 1: TSubstrateAccount;
+ eth: TEthereumAccount;
+ sub: TSubstrateAccount;
+}
+
+export interface ICollectionLimits {
+ accountTokenOwnershipLimit?: number | null;
+ sponsoredDataSize?: number | null;
+ sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;
+ tokenLimit?: number | null;
+ sponsorTransferTimeout?: number | null;
+ sponsorApproveTimeout?: number | null;
+ ownerCanTransfer?: boolean | null;
+ ownerCanDestroy?: boolean | null;
+ transfersEnabled?: boolean | null;
+}
+
+export interface INestingPermissions {
+ tokenOwner?: boolean;
+ collectionAdmin?: boolean;
+ restricted?: number[] | null;
+}
+
+export interface ICollectionPermissions {
+ access?: 'Normal' | 'AllowList';
+ mintMode?: boolean;
+ nesting?: INestingPermissions;
+}
+
+export interface IProperty {
+ key: string;
+ value?: string;
+}
+
+export interface ITokenPropertyPermission {
+ key: string;
+ permission: {
+ mutable?: boolean;
+ tokenOwner?: boolean;
+ collectionAdmin?: boolean;
+ }
+}
+
+export interface IToken {
+ collectionId: number;
+ tokenId: number;
+}
+
+export interface IBlock {
+ extrinsics: IExtrinsic[]
+ header: {
+ parentHash: string,
+ number: number,
+ };
+}
+
+export interface IExtrinsic {
+ isSigned: boolean,
+ method: {
+ method: string,
+ section: string,
+ args: any[]
+ }
+}
+
+export interface ICollectionFlags {
+ foreign: boolean,
+ erc721metadata: boolean,
+}
+
+export enum CollectionFlag {
+ None = 0,
+ /// External collections can't be managed using `unique` api
+ External = 1,
+ /// Supports ERC721Metadata
+ Erc721metadata = 64,
+ /// Tokens in foreign collections can be transferred, but not burnt
+ Foreign = 128,
+}
+
+export interface ICollectionCreationOptions {
+ name?: string | number[];
+ description?: string | number[];
+ tokenPrefix?: string | number[];
+ mode?: {
+ nft?: null;
+ refungible?: null;
+ fungible?: number;
+ }
+ permissions?: ICollectionPermissions;
+ properties?: IProperty[];
+ tokenPropertyPermissions?: ITokenPropertyPermission[];
+ limits?: ICollectionLimits;
+ pendingSponsor?: ICrossAccountId;
+ adminList?: ICrossAccountId[];
+ flags?: number[] | CollectionFlag[] ,
+}
+
+export interface IChainProperties {
+ ss58Format: number;
+ tokenDecimals: number[];
+ tokenSymbol: string[]
+}
+
+export interface ISubstrateBalance {
+ free: bigint,
+ reserved: bigint,
+ frozen: bigint,
+}
+
+export interface IStakingInfo {
+ block: bigint,
+ amount: bigint,
+}
+
+export interface IPovInfo {
+ proofSize: number,
+ compactProofSize: number,
+ compressedProofSize: number,
+ results: any[],
+ kv: any,
+}
+
+export interface ISchedulerOptions {
+ scheduledId?: string,
+ priority?: number,
+ periodic?: {
+ period: number,
+ repetitions: number,
+ },
+}
+
+export interface DemocracySplitAccount {
+ aye: bigint,
+ nay: bigint,
+}
+
+export type TSubstrateAccount = string;
+export type TEthereumAccount = string;
+export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
+export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
+export type TSiblingNetworkds = 'moonbeam' | 'moonriver' | 'acala' | 'karura' | 'westmint';
+export type TRelayNetworks = 'rococo' | 'westend';
+export type TNetworks = TUniqueNetworks | TSiblingNetworkds | TRelayNetworks;
+export type TSigner = IKeyringPair; // | 'string'
+export type TCollectionMode = 'nft' | 'rft' | 'ft';
js-packages/playgrounds/types.xcm.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/playgrounds/types.xcm.ts
@@ -0,0 +1,36 @@
+export interface AcalaAssetMetadata {
+ name: string,
+ symbol: string,
+ decimals: number,
+ minimalBalance: bigint,
+}
+
+export interface MoonbeamAssetInfo {
+ location: any,
+ metadata: {
+ name: string,
+ symbol: string,
+ decimals: number,
+ isFrozen: boolean,
+ minimalBalance: bigint,
+ },
+ existentialDeposit: bigint,
+ isSufficient: boolean,
+ unitsPerSecond: bigint,
+ numAssetsWeightHint: number,
+}
+
+export interface DemocracyStandardAccountVote {
+ balance: bigint,
+ vote: {
+ aye: boolean,
+ conviction: number,
+ },
+}
+
+export interface IForeignAssetMetadata {
+ name?: number | Uint8Array,
+ symbol?: string,
+ decimals?: number,
+ minimalBalance?: bigint,
+}
\ No newline at end of file
js-packages/playgrounds/unique.dev.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/playgrounds/unique.dev.ts
@@ -0,0 +1,1547 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import '@unique/opal-types/augment-api.js';
+import '@unique/opal-types/augment-types.js';
+import '@unique/opal-types/types-lookup.js';
+
+import {stringToU8a} from '@polkadot/util';
+import {blake2AsHex, encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto';
+import type {ChainHelperBaseConstructor, UniqueHelperConstructor} from './unique.js';
+import {UniqueHelper, ChainHelperBase, HelperGroup} from './unique.js';
+import {ApiPromise, Keyring, WsProvider} from '@polkadot/api';
+import * as defs from '@unique/opal-types/definitions.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import type {EventRecord} from '@polkadot/types/interfaces';
+import type {ICrossAccountId, ILogger, IPovInfo, ISchedulerOptions, ITransactionResult, TSigner} from './types.js';
+import type {FrameSystemEventRecord, StagingXcmV2TraitsError, StagingXcmV3TraitsOutcome} from '@polkadot/types/lookup';
+import type {SignerOptions, VoidFn} from '@polkadot/api/types';
+import {spawnSync} from 'child_process';
+import {AcalaHelper, AstarHelper, MoonbeamHelper, PolkadexHelper, RelayHelper, WestmintHelper, ForeignAssetsGroup, XcmGroup, XTokensGroup, TokensGroup} from './unique.xcm.js';
+import {CollectiveGroup, CollectiveMembershipGroup, DemocracyGroup, RankedCollectiveGroup, ReferendaGroup} from './unique.governance.js';
+import type {ICollectiveGroup, IFellowshipGroup} from './unique.governance.js';
+
+export class SilentLogger {
+ log(_msg: any, _level: any): void { }
+ level = {
+ ERROR: 'ERROR' as const,
+ WARNING: 'WARNING' as const,
+ INFO: 'INFO' as const,
+ };
+}
+
+export class SilentConsole {
+ // TODO: Remove, this is temporary: Filter unneeded API output
+ // (Jaco promised it will be removed in the next version)
+ consoleErr: any;
+ consoleLog: any;
+ consoleWarn: any;
+
+ constructor() {
+ this.consoleErr = console.error;
+ this.consoleLog = console.log;
+ this.consoleWarn = console.warn;
+ }
+
+ enable() {
+ const outFn = (printer: any) => (...args: any[]) => {
+ for(const arg of args) {
+ if(typeof arg !== 'string')
+ continue;
+ const skippedWarnings = ['1000:: Normal connection closure', 'Not decorating unknown runtime apis:', 'RPC methods not decorated:', 'Not decorating runtime apis', 'Bad input data provided to validate_transaction', 'account balance too low', '1006:: Abnormal Closure'];
+ const needToSkip = skippedWarnings.reduce((a, b) => a || arg.includes(b), false);
+ if(needToSkip || arg === 'Normal connection closure')
+ return;
+ }
+ printer(...args);
+ };
+
+ console.error = outFn(this.consoleErr.bind(console));
+ console.log = outFn(this.consoleLog.bind(console));
+ console.warn = outFn(this.consoleWarn.bind(console));
+ }
+
+ disable() {
+ console.error = this.consoleErr;
+ console.log = this.consoleLog;
+ console.warn = this.consoleWarn;
+ }
+}
+
+export interface IEventHelper {
+ section(): string;
+
+ method(): string;
+
+ wrapEvent(data: any[]): any;
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function EventHelper(section: string, method: string, wrapEvent: (data: any[]) => any) {
+ const helperClass = class implements IEventHelper {
+ wrapEvent: (data: any[]) => any;
+ _section: string;
+ _method: string;
+
+ constructor() {
+ this.wrapEvent = wrapEvent;
+ this._section = section;
+ this._method = method;
+ }
+
+ section(): string {
+ return this._section;
+ }
+
+ method(): string {
+ return this._method;
+ }
+
+ filter(txres: ITransactionResult) {
+ return txres.result.events.filter(e => e.event.section === section && e.event.method === method)
+ .map(e => this.wrapEvent(e.event.data));
+ }
+
+ find(txres: ITransactionResult) {
+ const e = txres.result.events.find(e => e.event.section === section && e.event.method === method);
+ return e ? this.wrapEvent(e.event.data) : null;
+ }
+
+ expect(txres: ITransactionResult) {
+ const e = this.find(txres);
+ if(e) {
+ return e;
+ } else {
+ throw Error(`Expected event ${section}.${method}`);
+ }
+ }
+ };
+
+ return helperClass;
+}
+
+function eventJsonData<T = any>(data: any[], index: number) {
+ return data[index].toJSON() as T;
+}
+
+function eventHumanData(data: any[], index: number) {
+ return data[index].toHuman();
+}
+
+function eventData<T = any>(data: any[], index: number) {
+ return data[index] as T;
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function EventSection(section: string) {
+ return class Section {
+ static section = section;
+
+ static Method(name: string, wrapEvent: (data: any[]) => any = () => {}) {
+ const helperClass = EventHelper(Section.section, name, wrapEvent);
+ return new helperClass();
+ }
+ };
+}
+
+function schedulerSection(schedulerInstance: string) {
+ return class extends EventSection(schedulerInstance) {
+ static Dispatched = this.Method('Dispatched', data => ({
+ task: eventJsonData(data, 0),
+ id: eventHumanData(data, 1),
+ result: data[2],
+ }));
+
+ static PriorityChanged = this.Method('PriorityChanged', data => ({
+ task: eventJsonData(data, 0),
+ priority: eventJsonData(data, 1),
+ }));
+ };
+}
+
+export class Event {
+ static Democracy = class extends EventSection('democracy') {
+ static Proposed = this.Method('Proposed', data => ({
+ proposalIndex: eventJsonData<number>(data, 0),
+ }));
+
+ static ExternalTabled = this.Method('ExternalTabled');
+
+ static Started = this.Method('Started', data => ({
+ referendumIndex: eventJsonData<number>(data, 0),
+ threshold: eventHumanData(data, 1),
+ }));
+
+ static Voted = this.Method('Voted', data => ({
+ voter: eventJsonData(data, 0),
+ referendumIndex: eventJsonData<number>(data, 1),
+ vote: eventJsonData(data, 2),
+ }));
+
+ static Passed = this.Method('Passed', data => ({
+ referendumIndex: eventJsonData<number>(data, 0),
+ }));
+
+ static ProposalCanceled = this.Method('ProposalCanceled', data => ({
+ propIndex: eventJsonData<number>(data, 0),
+ }));
+
+ static Cancelled = this.Method('Cancelled', data => ({
+ propIndex: eventJsonData<number>(data, 0),
+ }));
+
+ static Vetoed = this.Method('Vetoed', data => ({
+ who: eventHumanData(data, 0),
+ proposalHash: eventHumanData(data, 1),
+ until: eventJsonData<number>(data, 1),
+ }));
+ };
+
+ static Council = class extends EventSection('council') {
+ static Proposed = this.Method('Proposed', data => ({
+ account: eventHumanData(data, 0),
+ proposalIndex: eventJsonData<number>(data, 1),
+ proposalHash: eventHumanData(data, 2),
+ threshold: eventJsonData<number>(data, 3),
+ }));
+ static Closed = this.Method('Closed', data => ({
+ proposalHash: eventHumanData(data, 0),
+ yes: eventJsonData<number>(data, 1),
+ no: eventJsonData<number>(data, 2),
+ }));
+ static Executed = this.Method('Executed', data => ({
+ proposalHash: eventHumanData(data, 0),
+ }));
+ };
+
+ static TechnicalCommittee = class extends EventSection('technicalCommittee') {
+ static Proposed = this.Method('Proposed', data => ({
+ account: eventHumanData(data, 0),
+ proposalIndex: eventJsonData<number>(data, 1),
+ proposalHash: eventHumanData(data, 2),
+ threshold: eventJsonData<number>(data, 3),
+ }));
+ static Closed = this.Method('Closed', data => ({
+ proposalHash: eventHumanData(data, 0),
+ yes: eventJsonData<number>(data, 1),
+ no: eventJsonData<number>(data, 2),
+ }));
+ static Approved = this.Method('Approved', data => ({
+ proposalHash: eventHumanData(data, 0),
+ }));
+ static Executed = this.Method('Executed', data => ({
+ proposalHash: eventHumanData(data, 0),
+ result: eventHumanData(data, 1),
+ }));
+ };
+
+ static FellowshipReferenda = class extends EventSection('fellowshipReferenda') {
+ static Submitted = this.Method('Submitted', data => ({
+ referendumIndex: eventJsonData<number>(data, 0),
+ trackId: eventJsonData<number>(data, 1),
+ proposal: eventJsonData(data, 2),
+ }));
+
+ static Cancelled = this.Method('Cancelled', data => ({
+ index: eventJsonData<number>(data, 0),
+ tally: eventJsonData(data, 1),
+ }));
+ };
+
+ static UniqueScheduler = schedulerSection('uniqueScheduler');
+ static Scheduler = schedulerSection('scheduler');
+
+ static XcmpQueue = class extends EventSection('xcmpQueue') {
+ static XcmpMessageSent = this.Method('XcmpMessageSent', data => ({
+ messageHash: eventJsonData(data, 0),
+ }));
+
+ static Success = this.Method('Success', data => ({
+ messageHash: eventJsonData(data, 0),
+ }));
+
+ static Fail = this.Method('Fail', data => ({
+ messageHash: eventJsonData(data, 0),
+ outcome: eventData<StagingXcmV2TraitsError>(data, 2),
+ }));
+ };
+
+ static DmpQueue = class extends EventSection('dmpQueue') {
+ static ExecutedDownward = this.Method('ExecutedDownward', data => ({
+ outcome: eventData<StagingXcmV3TraitsOutcome>(data, 2),
+ }));
+ };
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {
+ return class extends Base {
+ constructor(...args: any[]) {
+ super(...args);
+ }
+
+ override async executeExtrinsic(
+ sender: IKeyringPair,
+ extrinsic: string,
+ params: any[],
+ expectSuccess?: boolean,
+ options: Partial<SignerOptions> | null = null,
+ ): Promise<ITransactionResult> {
+ const call = this.constructApiCall(extrinsic, params);
+ const result = await super.executeExtrinsic(
+ sender,
+ 'api.tx.sudo.sudo',
+ [call],
+ expectSuccess,
+ options,
+ );
+
+ if(result.status === 'Fail') return result;
+
+ const data = (result.result.events.find(x => x.event.section == 'sudo' && x.event.method == 'Sudid')?.event.data as any).sudoResult;
+ if(data.isErr) {
+ if(data.asErr.isModule) {
+ const error = (result.result.events[1].event.data as any).sudoResult.asErr.asModule;
+ const metaError = super.getApi()?.registry.findMetaError(error);
+ throw new Error(`${metaError.section}.${metaError.name}`);
+ } else if(data.asErr.isToken) {
+ throw new Error(`Token: ${data.asErr.asToken}`);
+ }
+ // May be [object Object] in case of unhandled non-unit enum
+ throw new Error(`Misc: ${data.asErr.toHuman()}`);
+ }
+ return result;
+ }
+ override async executeExtrinsicUncheckedWeight(
+ sender: IKeyringPair,
+ extrinsic: string,
+ params: any[],
+ expectSuccess?: boolean,
+ options: Partial<SignerOptions> | null = null,
+ ): Promise<ITransactionResult> {
+ const call = this.constructApiCall(extrinsic, params);
+ const result = await super.executeExtrinsic(
+ sender,
+ 'api.tx.sudo.sudoUncheckedWeight',
+ [call, {refTime: 0, proofSize: 0}],
+ expectSuccess,
+ options,
+ );
+
+ if(result.status === 'Fail') return result;
+
+ const data = (result.result.events.find(x => x.event.section == 'sudo' && x.event.method == 'Sudid')?.event.data as any).sudoResult;
+ if(data.isErr) {
+ if(data.asErr.isModule) {
+ const error = (result.result.events[1].event.data as any).sudoResult.asErr.asModule;
+ const metaError = super.getApi()?.registry.findMetaError(error);
+ throw new Error(`${metaError.section}.${metaError.name}`);
+ } else if(data.asErr.isToken) {
+ throw new Error(`Token: ${data.asErr.asToken}`);
+ }
+ // May be [object Object] in case of unhandled non-unit enum
+ throw new Error(`Misc: ${data.asErr.toHuman()}`);
+ }
+ return result;
+ }
+ };
+}
+
+class SchedulerGroup extends HelperGroup<UniqueHelper> {
+ constructor(helper: UniqueHelper) {
+ super(helper);
+ }
+
+ cancelScheduled(signer: TSigner, scheduledId: string) {
+ return this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.scheduler.cancelNamed',
+ [scheduledId],
+ true,
+ );
+ }
+
+ changePriority(signer: TSigner, scheduledId: string, priority: number) {
+ return this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.scheduler.changeNamedPriority',
+ [scheduledId, priority],
+ true,
+ );
+ }
+
+ scheduleAt<T extends DevUniqueHelper>(
+ executionBlockNumber: number,
+ options: ISchedulerOptions = {},
+ ) {
+ return this.schedule<T>('schedule', executionBlockNumber, options);
+ }
+
+ scheduleAfter<T extends DevUniqueHelper>(
+ blocksBeforeExecution: number,
+ options: ISchedulerOptions = {},
+ ) {
+ return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);
+ }
+
+ schedule<T extends UniqueHelper>(
+ scheduleFn: 'schedule' | 'scheduleAfter',
+ blocksNum: number,
+ options: ISchedulerOptions = {},
+ ) {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);
+ return this.helper.clone(ScheduledHelperType, {
+ scheduleFn,
+ blocksNum,
+ options,
+ }) as T;
+ }
+}
+
+class CollatorSelectionGroup extends HelperGroup<UniqueHelper> {
+ //todo:collator documentation
+ addInvulnerable(signer: TSigner, address: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.addInvulnerable', [address]);
+ }
+
+ removeInvulnerable(signer: TSigner, address: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.removeInvulnerable', [address]);
+ }
+
+ async getInvulnerables(): Promise<string[]> {
+ return (await this.helper.callRpc('api.query.collatorSelection.invulnerables')).map((x: any) => x.toHuman());
+ }
+
+ /** and also total max invulnerables */
+ maxCollators(): number {
+ return (this.helper.getApi().consts.configuration.defaultCollatorSelectionMaxCollators.toJSON() as number);
+ }
+
+ async getDesiredCollators(): Promise<number> {
+ return (await this.helper.callRpc('api.query.configuration.collatorSelectionDesiredCollatorsOverride')).toNumber();
+ }
+
+ setLicenseBond(signer: TSigner, amount: bigint) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.configuration.setCollatorSelectionLicenseBond', [amount]);
+ }
+
+ async getLicenseBond(): Promise<bigint> {
+ return (await this.helper.callRpc('api.query.configuration.collatorSelectionLicenseBondOverride')).toBigInt();
+ }
+
+ obtainLicense(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.getLicense', []);
+ }
+
+ releaseLicense(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.releaseLicense', []);
+ }
+
+ forceReleaseLicense(signer: TSigner, released: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.forceReleaseLicense', [released]);
+ }
+
+ async hasLicense(address: string): Promise<bigint> {
+ return (await this.helper.callRpc('api.query.collatorSelection.licenseDepositOf', [address])).toBigInt();
+ }
+
+ onboard(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.onboard', []);
+ }
+
+ offboard(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.offboard', []);
+ }
+
+ async getCandidates(): Promise<string[]> {
+ return (await this.helper.callRpc('api.query.collatorSelection.candidates')).map((x: any) => x.toHuman());
+ }
+}
+
+export class DevUniqueHelper extends UniqueHelper {
+ /**
+ * Arrange methods for tests
+ */
+ arrange: ArrangeGroup;
+ wait: WaitGroup;
+ admin: AdminGroup;
+ session: SessionGroup;
+ testUtils: TestUtilGroup;
+ foreignAssets: ForeignAssetsGroup;
+ xcm: XcmGroup<DevUniqueHelper>;
+ xTokens: XTokensGroup<DevUniqueHelper>;
+ tokens: TokensGroup<DevUniqueHelper>;
+ scheduler: SchedulerGroup;
+ collatorSelection: CollatorSelectionGroup;
+ council: ICollectiveGroup;
+ technicalCommittee: ICollectiveGroup;
+ fellowship: IFellowshipGroup;
+ democracy: DemocracyGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? DevUniqueHelper;
+
+ super(logger, options);
+ this.arrange = new ArrangeGroup(this);
+ this.wait = new WaitGroup(this);
+ this.admin = new AdminGroup(this);
+ this.testUtils = new TestUtilGroup(this);
+ this.session = new SessionGroup(this);
+ this.foreignAssets = new ForeignAssetsGroup(this);
+ this.xcm = new XcmGroup(this, 'polkadotXcm');
+ this.xTokens = new XTokensGroup(this);
+ this.tokens = new TokensGroup(this);
+ this.scheduler = new SchedulerGroup(this);
+ this.collatorSelection = new CollatorSelectionGroup(this);
+ this.council = {
+ collective: new CollectiveGroup(this, 'council'),
+ membership: new CollectiveMembershipGroup(this, 'councilMembership'),
+ };
+ this.technicalCommittee = {
+ collective: new CollectiveGroup(this, 'technicalCommittee'),
+ membership: new CollectiveMembershipGroup(this, 'technicalCommitteeMembership'),
+ };
+ this.fellowship = {
+ collective: new RankedCollectiveGroup(this, 'fellowshipCollective'),
+ referenda: new ReferendaGroup(this, 'fellowshipReferenda'),
+ };
+ this.democracy = new DemocracyGroup(this);
+ }
+
+ override async connect(wsEndpoint: string, _listeners?: any): Promise<void> {
+ if(!wsEndpoint) throw new Error('wsEndpoint was not set');
+ const wsProvider = new WsProvider(wsEndpoint);
+ this.api = new ApiPromise({
+ provider: wsProvider,
+ signedExtensions: {
+ ContractHelpers: {
+ extrinsic: {},
+ payload: {},
+ },
+ CheckMaintenance: {
+ extrinsic: {},
+ payload: {},
+ },
+ DisableIdentityCalls: {
+ extrinsic: {},
+ payload: {},
+ },
+ FakeTransactionFinalizer: {
+ extrinsic: {},
+ payload: {},
+ },
+ },
+ rpc: {
+ unique: defs.unique.rpc,
+ appPromotion: defs.appPromotion.rpc,
+ povinfo: defs.povinfo.rpc,
+ eth: {
+ feeHistory: {
+ description: 'Dummy',
+ params: [],
+ type: 'u8',
+ },
+ maxPriorityFeePerGas: {
+ description: 'Dummy',
+ params: [],
+ type: 'u8',
+ },
+ },
+ },
+ });
+ await this.api.isReadyOrError;
+ this.network = await UniqueHelper.detectNetwork(this.api);
+ this.wsEndpoint = wsEndpoint;
+ }
+ getSudo<T extends DevUniqueHelper>() {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const SudoHelperType = SudoHelper(this.helperBase);
+ return this.clone(SudoHelperType) as T;
+ }
+}
+
+export class DevRelayHelper extends RelayHelper {
+ wait: WaitGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? DevRelayHelper;
+
+ super(logger, options);
+ this.wait = new WaitGroup(this);
+ }
+
+ getSudo() {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const SudoHelperType = SudoHelper(this.helperBase);
+ return this.clone(SudoHelperType) as DevRelayHelper;
+ }
+}
+
+export class DevWestmintHelper extends WestmintHelper {
+ wait: WaitGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? DevWestmintHelper;
+
+ super(logger, options);
+ this.wait = new WaitGroup(this);
+ }
+}
+
+export class DevStatemineHelper extends DevWestmintHelper {}
+
+export class DevStatemintHelper extends DevWestmintHelper {}
+
+export class DevMoonbeamHelper extends MoonbeamHelper {
+ account: MoonbeamAccountGroup;
+ wait: WaitGroup;
+ fastDemocracy: MoonbeamFastDemocracyGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? DevMoonbeamHelper;
+ options.notePreimagePallet = options.notePreimagePallet ?? 'preimage';
+
+ super(logger, options);
+ this.account = new MoonbeamAccountGroup(this);
+ this.wait = new WaitGroup(this);
+ this.fastDemocracy = new MoonbeamFastDemocracyGroup(this);
+ }
+}
+
+export class DevMoonriverHelper extends DevMoonbeamHelper {
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.notePreimagePallet = options.notePreimagePallet ?? 'preimage';
+ super(logger, options);
+ }
+}
+
+export class DevAstarHelper extends AstarHelper {
+ wait: WaitGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? DevAstarHelper;
+
+ super(logger, options);
+ this.wait = new WaitGroup(this);
+ }
+
+ getSudo<T extends AstarHelper>() {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const SudoHelperType = SudoHelper(this.helperBase);
+ return this.clone(SudoHelperType) as T;
+ }
+}
+
+export class DevShidenHelper extends DevAstarHelper { }
+
+export class DevAcalaHelper extends AcalaHelper {
+ wait: WaitGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? DevAcalaHelper;
+
+ super(logger, options);
+ this.wait = new WaitGroup(this);
+ }
+ getSudo() {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const SudoHelperType = SudoHelper(this.helperBase);
+ return this.clone(SudoHelperType) as DevAcalaHelper;
+ }
+}
+
+export class DevPolkadexHelper extends PolkadexHelper {
+ wait: WaitGroup;
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
+ options.helperBase = options.helperBase ?? PolkadexHelper;
+
+ super(logger, options);
+ this.wait = new WaitGroup(this);
+ }
+
+ getSudo() {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const SudoHelperType = SudoHelper(this.helperBase);
+ return this.clone(SudoHelperType) as DevPolkadexHelper;
+ }
+}
+
+export class DevKaruraHelper extends DevAcalaHelper {}
+
+export class ArrangeGroup {
+ helper: DevUniqueHelper;
+
+ scheduledIdSlider = 0;
+
+ constructor(helper: DevUniqueHelper) {
+ this.helper = helper;
+ }
+
+ /**
+ * Generates accounts with the specified UNQ token balance
+ * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.
+ * @param donor donor account for balances
+ * @returns array of newly created accounts
+ * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor);
+ */
+ createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {
+ let nonce = await this.helper.chain.getNonce(donor.address);
+ const wait = new WaitGroup(this.helper);
+ const ss58Format = this.helper.chain.getChainProperties().ss58Format;
+ const tokenNominal = this.helper.balance.getOneTokenNominal();
+ const transactions = [];
+ const accounts: IKeyringPair[] = [];
+ for(const balance of balances) {
+ const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
+ accounts.push(recipient);
+ if(balance !== 0n) {
+ const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, balance * tokenNominal]);
+ transactions.push(this.helper.signTransaction(donor, tx, {nonce}, 'account generation'));
+ nonce++;
+ }
+ }
+
+ await Promise.all(transactions).catch(_e => {});
+
+ //#region TODO remove this region, when nonce problem will be solved
+ const checkBalances = async () => {
+ let isSuccess = true;
+ for(let i = 0; i < balances.length; i++) {
+ const balance = await this.helper.balance.getSubstrate(accounts[i].address);
+ if(balance !== balances[i] * tokenNominal) {
+ isSuccess = false;
+ break;
+ }
+ }
+ return isSuccess;
+ };
+
+ let accountsCreated = false;
+ const maxBlocksChecked = await this.helper.arrange.isDevNode() ? 50 : 5;
+ // checkBalances retry up to 5-50 blocks
+ for(let index = 0; index < maxBlocksChecked; index++) {
+ accountsCreated = await checkBalances();
+ if(accountsCreated) break;
+ await wait.newBlocks(1);
+ }
+
+ if(!accountsCreated) throw Error('Accounts generation failed');
+ //#endregion
+
+ return accounts;
+ };
+
+ // TODO combine this method and createAccounts into one
+ createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {
+ const createAsManyAsCan = async () => {
+ let transactions: any = [];
+ const accounts: IKeyringPair[] = [];
+ let nonce = await this.helper.chain.getNonce(donor.address);
+ const tokenNominal = this.helper.balance.getOneTokenNominal();
+ const ss58Format = this.helper.chain.getChainProperties().ss58Format;
+ for(let i = 0; i < accountsToCreate; i++) {
+ if(i === 500) { // if there are too many accounts to create
+ await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled
+ transactions = []; //
+ nonce = await this.helper.chain.getNonce(donor.address); // update nonce
+ }
+ const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
+ accounts.push(recipient);
+ if(withBalance !== 0n) {
+ const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, withBalance * tokenNominal]);
+ transactions.push(this.helper.signTransaction(donor, tx, {nonce}, 'account generation'));
+ nonce++;
+ }
+ }
+
+ const fullfilledAccounts = [];
+ await Promise.allSettled(transactions);
+ for(const account of accounts) {
+ const accountBalance = await this.helper.balance.getSubstrate(account.address);
+ if(accountBalance === withBalance * tokenNominal) {
+ fullfilledAccounts.push(account);
+ }
+ }
+ return fullfilledAccounts;
+ };
+
+
+ const crowd: IKeyringPair[] = [];
+ // do up to 5 retries
+ for(let index = 0; index < 5 && accountsToCreate !== 0; index++) {
+ const asManyAsCan = await createAsManyAsCan();
+ crowd.push(...asManyAsCan);
+ accountsToCreate -= asManyAsCan.length;
+ }
+
+ if(accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);
+
+ return crowd;
+ };
+
+ /**
+ * Generates one account with zero balance
+ * @returns the newly generated account
+ * @example const account = await helper.arrange.createEmptyAccount();
+ */
+ createEmptyAccount = (): IKeyringPair => {
+ const ss58Format = this.helper.chain.getChainProperties().ss58Format;
+ return this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
+ };
+
+ isDevNode = async () => {
+ let blockNumber = (await this.helper.callRpc('api.query.system.number')).toJSON();
+ if(blockNumber == 0) {
+ await this.helper.wait.newBlocks(1);
+ blockNumber = (await this.helper.callRpc('api.query.system.number')).toJSON();
+ }
+ const block2 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])]);
+ const block1 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber - 1])]);
+ const findCreationDate = (block: any) => {
+ const humanBlock = block.toHuman();
+ let date;
+ humanBlock.block.extrinsics.forEach((ext: any) => {
+ if(ext.method.section === 'timestamp') {
+ date = Number(ext.method.args.now.replaceAll(',', ''));
+ }
+ });
+ return date;
+ };
+ const block1date = await findCreationDate(block1);
+ const block2date = await findCreationDate(block2);
+ if(block2date! - block1date! < 9000) return true;
+ return false;
+ };
+
+ async calculcateFee(payer: ICrossAccountId, promise: () => Promise<any>): Promise<bigint> {
+ const address = 'Substrate' in payer ? payer.Substrate : this.helper.address.ethToSubstrate(payer.Ethereum);
+ let balance = await this.helper.balance.getSubstrate(address);
+
+ await promise();
+
+ balance -= await this.helper.balance.getSubstrate(address);
+
+ return balance;
+ }
+
+ async calculatePoVInfo(txs: any[]): Promise<IPovInfo> {
+ const rawPovInfo = await this.helper.callRpc('api.rpc.povinfo.estimateExtrinsicPoV', [txs]);
+
+ const kvJson: {[key: string]: string} = {};
+
+ for(const kv of rawPovInfo.keyValues) {
+ kvJson[kv.key.toHex()] = kv.value.toHex();
+ }
+
+ const kvStr = JSON.stringify(kvJson);
+
+ const chainql = spawnSync(
+ 'chainql',
+ [
+ `--tla-code=data=${kvStr}`,
+ '-e', `function(data) cql.dump(cql.chain("${this.helper.getEndpoint()}").latest._meta, data, {omit_empty:true})`,
+ ],
+ );
+
+ if(!chainql.stdout) {
+ throw Error('unable to get an output from the `chainql`');
+ }
+
+ return {
+ proofSize: rawPovInfo.proofSize.toNumber(),
+ compactProofSize: rawPovInfo.compactProofSize.toNumber(),
+ compressedProofSize: rawPovInfo.compressedProofSize.toNumber(),
+ results: rawPovInfo.results,
+ kv: JSON.parse(chainql.stdout.toString()),
+ };
+ }
+
+ calculatePalletAddress(palletId: any) {
+ const address = stringToU8a(('modl' + palletId).padEnd(32, '\0'));
+ return encodeAddress(address, this.helper.chain.getChainProperties().ss58Format);
+ }
+
+ makeScheduledIds(num: number): string[] {
+ function makeId(slider: number) {
+ const scheduledIdSize = 64;
+ const hexId = slider.toString(16);
+ const prefixSize = scheduledIdSize - hexId.length;
+
+ const scheduledId = '0x' + '0'.repeat(prefixSize) + hexId;
+
+ return scheduledId;
+ }
+
+ const ids = [];
+ for(let i = 0; i < num; i++) {
+ ids.push(makeId(this.scheduledIdSlider));
+ this.scheduledIdSlider += 1;
+ }
+
+ return ids;
+ }
+
+ makeScheduledId(): string {
+ return (this.makeScheduledIds(1))[0];
+ }
+
+ async captureEvents(eventSection: string, eventMethod: string): Promise<EventCapture> {
+ const capture = new EventCapture(this.helper, eventSection, eventMethod);
+ await capture.startCapture();
+
+ return capture;
+ }
+
+ makeXcmProgramWithdrawDeposit(beneficiary: Uint8Array, id: any, amount: bigint) {
+ return {
+ V2: [
+ {
+ WithdrawAsset: [
+ {
+ id,
+ fun: {
+ Fungible: amount,
+ },
+ },
+ ],
+ },
+ {
+ BuyExecution: {
+ fees: {
+ id,
+ fun: {
+ Fungible: amount,
+ },
+ },
+ weightLimit: 'Unlimited',
+ },
+ },
+ {
+ DepositAsset: {
+ assets: {
+ Wild: 'All',
+ },
+ maxAssets: 1,
+ beneficiary: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: beneficiary,
+ },
+ },
+ },
+ },
+ },
+ },
+ ],
+ };
+ }
+
+ makeXcmProgramReserveAssetDeposited(beneficiary: Uint8Array, id: any, amount: bigint) {
+ return {
+ V2: [
+ {
+ ReserveAssetDeposited: [
+ {
+ id,
+ fun: {
+ Fungible: amount,
+ },
+ },
+ ],
+ },
+ {
+ BuyExecution: {
+ fees: {
+ id,
+ fun: {
+ Fungible: amount,
+ },
+ },
+ weightLimit: 'Unlimited',
+ },
+ },
+ {
+ DepositAsset: {
+ assets: {
+ Wild: 'All',
+ },
+ maxAssets: 1,
+ beneficiary: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: beneficiary,
+ },
+ },
+ },
+ },
+ },
+ },
+ ],
+ };
+ }
+
+ makeUnpaidSudoTransactProgram(info: {weightMultiplier: number, call: string}) {
+ return {
+ V3: [
+ {
+ UnpaidExecution: {
+ weightLimit: 'Unlimited',
+ checkOrigin: null,
+ },
+ },
+ {
+ Transact: {
+ originKind: 'Superuser',
+ requireWeightAtMost: {
+ refTime: info.weightMultiplier * 200000000,
+ proofSize: info.weightMultiplier * 3000,
+ },
+ call: {
+ encoded: info.call,
+ },
+ },
+ },
+ ],
+ };
+ }
+}
+
+class MoonbeamAccountGroup {
+ helper: MoonbeamHelper;
+
+ keyring: Keyring;
+ _alithAccount: IKeyringPair;
+ _baltatharAccount: IKeyringPair;
+ _dorothyAccount: IKeyringPair;
+
+ constructor(helper: MoonbeamHelper) {
+ this.helper = helper;
+
+ this.keyring = new Keyring({type: 'ethereum'});
+ const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';
+ const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';
+ const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';
+
+ this._alithAccount = this.keyring.addFromUri(alithPrivateKey, undefined, 'ethereum');
+ this._baltatharAccount = this.keyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');
+ this._dorothyAccount = this.keyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');
+ }
+
+ alithAccount() {
+ return this._alithAccount;
+ }
+
+ baltatharAccount() {
+ return this._baltatharAccount;
+ }
+
+ dorothyAccount() {
+ return this._dorothyAccount;
+ }
+
+ create() {
+ return this.keyring.addFromUri(mnemonicGenerate());
+ }
+}
+
+class MoonbeamFastDemocracyGroup {
+ helper: DevMoonbeamHelper;
+
+ constructor(helper: DevMoonbeamHelper) {
+ this.helper = helper;
+ }
+
+ async executeProposal(proposalDesciption: string, encodedProposal: string) {
+ const proposalHash = blake2AsHex(encodedProposal);
+
+ const alithAccount = this.helper.account.alithAccount();
+ const baltatharAccount = this.helper.account.baltatharAccount();
+ const dorothyAccount = this.helper.account.dorothyAccount();
+
+ const councilVotingThreshold = 2;
+ const technicalCommitteeThreshold = 2;
+ const fastTrackVotingPeriod = 3;
+ const fastTrackDelayPeriod = 0;
+
+ console.log(`[democracy] executing '${proposalDesciption}' proposal`);
+
+ // >>> Propose external motion through council >>>
+ console.log('\t* Propose external motion through council.......');
+ const externalMotion = this.helper.democracy.externalProposeMajority({Inline: encodedProposal});
+ const encodedMotion = externalMotion?.method.toHex() || '';
+ const motionHash = blake2AsHex(encodedMotion);
+ console.log('\t* Motion hash is %s', motionHash);
+
+ await this.helper.collective.council.propose(
+ baltatharAccount,
+ councilVotingThreshold,
+ externalMotion,
+ externalMotion.encodedLength,
+ );
+
+ const councilProposalIdx = await this.helper.collective.council.proposalCount() - 1;
+ await this.helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
+ await this.helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
+
+ await this.helper.collective.council.close(
+ dorothyAccount,
+ motionHash,
+ councilProposalIdx,
+ {
+ refTime: 1_000_000_000,
+ proofSize: 1_000_000,
+ },
+ externalMotion.encodedLength,
+ );
+ console.log('\t* Propose external motion through council.......DONE');
+ // <<< Propose external motion through council <<<
+
+ // >>> Fast track proposal through technical committee >>>
+ console.log('\t* Fast track proposal through technical committee.......');
+ const fastTrack = this.helper.democracy.fastTrack(proposalHash, fastTrackVotingPeriod, fastTrackDelayPeriod);
+ const encodedFastTrack = fastTrack?.method.toHex() || '';
+ const fastTrackHash = blake2AsHex(encodedFastTrack);
+ console.log('\t* FastTrack hash is %s', fastTrackHash);
+
+ await this.helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);
+
+ const techProposalIdx = await this.helper.collective.techCommittee.proposalCount() - 1;
+ await this.helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
+ await this.helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
+
+ await this.helper.collective.techCommittee.close(
+ baltatharAccount,
+ fastTrackHash,
+ techProposalIdx,
+ {
+ refTime: 1_000_000_000,
+ proofSize: 1_000_000,
+ },
+ fastTrack.encodedLength,
+ );
+ console.log('\t* Fast track proposal through technical committee.......DONE');
+ // <<< Fast track proposal through technical committee <<<
+
+ const democracyStarted = await this.helper.wait.expectEvent(3, Event.Democracy.Started);
+ const referendumIndex = democracyStarted.referendumIndex;
+
+ // >>> Referendum voting >>>
+ console.log(`\t* Referendum #${referendumIndex} voting.......`);
+ await this.helper.democracy.referendumVote(dorothyAccount, referendumIndex, {
+ balance: 10_000_000_000_000_000_000n,
+ vote: {aye: true, conviction: 1},
+ });
+ console.log(`\t* Referendum #${referendumIndex} voting.......DONE`);
+ // <<< Referendum voting <<<
+
+ // Wait the proposal to pass
+ await this.helper.wait.expectEvent(3, Event.Democracy.Passed, event => event.referendumIndex == referendumIndex);
+
+ await this.helper.wait.newBlocks(1);
+
+ console.log(`[democracy] executing '${proposalDesciption}' proposal.......DONE`);
+ }
+}
+
+class WaitGroup {
+ helper: ChainHelperBase;
+
+ constructor(helper: ChainHelperBase) {
+ this.helper = helper;
+ }
+
+ sleep(milliseconds: number) {
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
+ }
+
+ private async waitWithTimeout(promise: Promise<any>, timeout: number) {
+ let isBlock = false;
+ promise.then(() => isBlock = true).catch(() => isBlock = true);
+ let totalTime = 0;
+ const step = 100;
+ while(!isBlock) {
+ await this.sleep(step);
+ totalTime += step;
+ if(totalTime >= timeout) throw Error('Blocks production failed');
+ }
+ return promise;
+ }
+
+ /**
+ * Launch some async operation, or throw an error after some time. Note that it will still continue executing after the timeout.
+ * @param promise async operation to race against the timeout
+ * @param timeoutMS time after which to time out
+ * @param timeoutError error message to throw
+ * @returns promise of the same type the operation had
+ */
+ withTimeout<T>(
+ promise: Promise<T>,
+ timeoutMS = 30000,
+ timeoutError = 'The operation has timed out!',
+ ): Promise<T> {
+ const timeout = new Promise<never>((_, reject) => {
+ setTimeout(() => {
+ reject(new Error(timeoutError));
+ }, timeoutMS);
+ });
+
+ return Promise.race<T>([promise, timeout]).catch(e => {throw new Error(e);});
+ }
+
+ /**
+ * Wait for specified number of blocks
+ * @param blocksCount number of blocks to wait
+ * @returns
+ */
+ async newBlocks(blocksCount = 1, timeout?: number): Promise<void> {
+ timeout = timeout ?? blocksCount * 60_000;
+ // eslint-disable-next-line no-async-promise-executor
+ const promise = new Promise<void>(async (resolve) => {
+ const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(() => {
+ if(blocksCount > 0) {
+ blocksCount--;
+ } else {
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ await this.waitWithTimeout(promise, timeout);
+ return promise;
+ }
+
+ /**
+ * Wait for the specified number of sessions to pass.
+ * Only applicable if the Session pallet is turned on.
+ * @param sessionCount number of sessions to wait
+ * @param blockTimeout time in ms until panicking that the chain has stopped producing blocks
+ * @returns
+ */
+ async newSessions(sessionCount = 1, blockTimeout = 60000): Promise<void> {
+ console.log(`Waiting for ${sessionCount} new session${sessionCount > 1 ? 's' : ''}.`
+ + ' This might take a while -- check SessionPeriod in pallet_session::Config for session time.');
+
+ const expectedSessionIndex = await (this.helper as DevUniqueHelper).session.getIndex() + sessionCount;
+ let currentSessionIndex = -1;
+
+ while(currentSessionIndex < expectedSessionIndex) {
+ // eslint-disable-next-line no-async-promise-executor
+ currentSessionIndex = await this.withTimeout(new Promise(async (resolve) => {
+ await this.newBlocks(1);
+ const res = await (this.helper as DevUniqueHelper).session.getIndex();
+ resolve(res);
+ }), blockTimeout, 'The chain has stopped producing blocks!');
+ }
+ }
+
+ async forParachainBlockNumber(blockNumber: bigint | number, timeout?: number) {
+ timeout = timeout ?? 30 * 60 * 1000;
+ // eslint-disable-next-line no-async-promise-executor
+ const promise = new Promise<void>(async (resolve) => {
+ const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads((data: any) => {
+ if(data.number.toNumber() >= blockNumber) {
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ await this.waitWithTimeout(promise, timeout);
+ return promise;
+ }
+
+ async forRelayBlockNumber(blockNumber: bigint | number, timeout?: number) {
+ timeout = timeout ?? 30 * 60 * 1000;
+ // eslint-disable-next-line no-async-promise-executor
+ const promise = new Promise<void>(async (resolve) => {
+ const unsubscribe = await this.helper.getApi().query.parachainSystem.validationData((data: any) => {
+ if(data.value.relayParentNumber.toNumber() >= blockNumber) {
+ // @ts-ignore
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ await this.waitWithTimeout(promise, timeout);
+ return promise;
+ }
+
+ noScheduledTasks() {
+ const api = this.helper.getApi();
+
+ // eslint-disable-next-line no-async-promise-executor
+ const promise = new Promise<void>(async resolve => {
+ const unsubscribe = await api.rpc.chain.subscribeNewHeads(async () => {
+ const areThereScheduledTasks = await api.query.scheduler.lookup.entries();
+
+ if(areThereScheduledTasks.length == 0) {
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+
+ return promise;
+ }
+
+ parachainBlockMultiplesOf(val: bigint) {
+ // eslint-disable-next-line no-async-promise-executor
+ const promise = new Promise<void>(async resolve => {
+ const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads((data: any) => {
+ if(data.number.toBigInt() % val == 0n) {
+ console.log(`from waiter: ${data.number.toBigInt()}`);
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ return promise;
+ }
+
+ event<T extends IEventHelper>(
+ maxBlocksToWait: number,
+ eventHelper: T,
+ filter: (_: any) => boolean = () => true,
+ ): any {
+ // eslint-disable-next-line no-async-promise-executor
+ const promise = new Promise<T | null>(async (resolve) => {
+ const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(async header => {
+ const blockNumber = header.number.toJSON();
+ const blockHash = header.hash;
+ const eventIdStr = `${eventHelper.section()}.${eventHelper.method()}`;
+ const waitLimitStr = `wait blocks remaining: ${maxBlocksToWait}`;
+
+ this.helper.logger.log(`[Block #${blockNumber}] Waiting for event \`${eventIdStr}\` (${waitLimitStr})`);
+
+ const apiAt = await this.helper.getApi().at(blockHash);
+ const eventRecords = (await apiAt.query.system.events()) as any;
+
+ const neededEvent = eventRecords.toArray()
+ .filter((r: FrameSystemEventRecord) => r.event.section == eventHelper.section() && r.event.method == eventHelper.method())
+ .map((r: FrameSystemEventRecord) => eventHelper.wrapEvent(r.event.data))
+ .find(filter);
+
+ if(neededEvent) {
+ unsubscribe();
+ resolve(neededEvent);
+ } else if(maxBlocksToWait > 0) {
+ maxBlocksToWait--;
+ } else {
+ this.helper.logger.log(`Eligible event \`${eventIdStr}\` is NOT found.
+ The wait lasted until block ${blockNumber} inclusive`);
+ unsubscribe();
+ resolve(null);
+ }
+ });
+ });
+ return promise;
+ }
+
+ async expectEvent<T extends IEventHelper>(
+ maxBlocksToWait: number,
+ eventHelper: T,
+ filter: (e: any) => boolean = () => true,
+ ) {
+ const e = await this.event(maxBlocksToWait, eventHelper, filter);
+ if(e == null) {
+ throw Error(`The event '${eventHelper.section()}.${eventHelper.method()}' is expected`);
+ } else {
+ return e;
+ }
+ }
+}
+
+class SessionGroup {
+ helper: ChainHelperBase;
+
+ constructor(helper: ChainHelperBase) {
+ this.helper = helper;
+ }
+
+ //todo:collator documentation
+ async getIndex(): Promise<number> {
+ return (await this.helper.callRpc('api.query.session.currentIndex', [])).toNumber();
+ }
+
+ newSessions(sessionCount = 1, blockTimeout = 24000): Promise<void> {
+ return (this.helper as DevUniqueHelper).wait.newSessions(sessionCount, blockTimeout);
+ }
+
+ setOwnKeys(signer: TSigner, key: string) {
+ return this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.session.setKeys',
+ [key, '0x0'],
+ true,
+ );
+ }
+
+ setOwnKeysFromAddress(signer: TSigner) {
+ return this.setOwnKeys(signer, '0x' + Buffer.from(signer.addressRaw).toString('hex'));
+ }
+}
+
+class TestUtilGroup {
+ helper: DevUniqueHelper;
+
+ constructor(helper: DevUniqueHelper) {
+ this.helper = helper;
+ }
+
+ async enable(testUtilsPalletName: string) {
+ if(this.helper.fetchMissingPalletNames([testUtilsPalletName]).length != 0) {
+ return;
+ }
+
+ const signer = this.helper.util.fromSeed('//Alice');
+ await this.helper.getSudo<DevUniqueHelper>().executeExtrinsic(signer, 'api.tx.testUtils.enable', [], true);
+ }
+
+ async setTestValue(signer: TSigner, testVal: number) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValue', [testVal], true);
+ }
+
+ async incTestValue(signer: TSigner) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.incTestValue', [], true);
+ }
+
+ async setTestValueAndRollback(signer: TSigner, testVal: number) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValueAndRollback', [testVal], true);
+ }
+
+ async testValue(blockIdx?: number) {
+ const api = blockIdx
+ ? await this.helper.getApi().at(await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockIdx]))
+ : this.helper.getApi();
+
+ return (await api.query.testUtils.testValue()).toJSON();
+ }
+
+ async justTakeFee(signer: TSigner) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.justTakeFee', [], true);
+ }
+
+ async selfCancelingInc(signer: TSigner, scheduledId: string, maxTestVal: number) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.selfCancelingInc', [scheduledId, maxTestVal], true);
+ }
+}
+
+class EventCapture {
+ helper: DevUniqueHelper;
+ eventSection: string;
+ eventMethod: string;
+ events: EventRecord[] = [];
+ unsubscribe: VoidFn | null = null;
+
+ constructor(
+ helper: DevUniqueHelper,
+ eventSection: string,
+ eventMethod: string,
+ ) {
+ this.helper = helper;
+ this.eventSection = eventSection;
+ this.eventMethod = eventMethod;
+ }
+
+ async startCapture() {
+ this.stopCapture();
+ this.unsubscribe = (await this.helper.getApi().query.system.events((eventRecords: FrameSystemEventRecord[]) => {
+ const newEvents = eventRecords.filter(r => r.event.section == this.eventSection && r.event.method == this.eventMethod);
+
+ this.events.push(...newEvents);
+ })) as any;
+ }
+
+ stopCapture() {
+ if(this.unsubscribe !== null) {
+ this.unsubscribe();
+ }
+ }
+
+ extractCapturedEvents() {
+ return this.events;
+ }
+}
+
+class AdminGroup {
+ helper: UniqueHelper;
+
+ constructor(helper: UniqueHelper) {
+ this.helper = helper;
+ }
+
+ async payoutStakers(signer: IKeyringPair, stakersToPayout: number): Promise<{staker: string, stake: bigint, payout: bigint}[]> {
+ const payoutResult = await this.helper.executeExtrinsic(signer, 'api.tx.appPromotion.payoutStakers', [stakersToPayout], true);
+ return payoutResult.result.events.filter(e => e.event.method === 'StakingRecalculation').map(e => ({
+ staker: e.event.data[0].toString(),
+ stake: e.event.data[1].toBigInt(),
+ payout: e.event.data[2].toBigInt(),
+ }));
+ }
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {
+ return class extends Base {
+ scheduleFn: 'schedule' | 'scheduleAfter';
+ blocksNum: number;
+ options: ISchedulerOptions;
+
+ constructor(...args: any[]) {
+ const logger = args[0] as ILogger;
+ const options = args[1] as {
+ scheduleFn: 'schedule' | 'scheduleAfter',
+ blocksNum: number,
+ options: ISchedulerOptions
+ };
+
+ super(logger);
+
+ this.scheduleFn = options.scheduleFn;
+ this.blocksNum = options.blocksNum;
+ this.options = options.options;
+ }
+
+ override executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {
+ const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);
+
+ const mandatorySchedArgs = [
+ this.blocksNum,
+ this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,
+ this.options.priority ?? null,
+ scheduledTx,
+ ];
+
+ let schedArgs;
+ let scheduleFn;
+
+ if(this.options.scheduledId) {
+ schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];
+
+ if(this.scheduleFn == 'schedule') {
+ scheduleFn = 'scheduleNamed';
+ } else if(this.scheduleFn == 'scheduleAfter') {
+ scheduleFn = 'scheduleNamedAfter';
+ }
+ } else {
+ schedArgs = mandatorySchedArgs;
+ scheduleFn = this.scheduleFn;
+ }
+
+ const extrinsic = 'api.tx.scheduler.' + scheduleFn;
+
+ return super.executeExtrinsic(
+ sender,
+ extrinsic as any,
+ schedArgs,
+ expectSuccess,
+ );
+ }
+ };
+}
js-packages/playgrounds/unique.governance.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/playgrounds/unique.governance.ts
@@ -0,0 +1,531 @@
+import {blake2AsHex} from '@polkadot/util-crypto';
+import type {PalletDemocracyConviction} from '@polkadot/types/lookup';
+import type {IPhasicEvent, TSigner} from './types.js';
+import {HelperGroup, UniqueHelper} from './unique.js';
+
+export class CollectiveGroup extends HelperGroup<UniqueHelper> {
+ /**
+ * Pallet name to make an API call to. Examples: 'council', 'technicalCommittee'
+ */
+ private collective: string;
+
+ constructor(helper: UniqueHelper, collective: string) {
+ super(helper);
+ this.collective = collective;
+ }
+
+ /**
+ * Check the result of a proposal execution for the success of the underlying proposed extrinsic.
+ * @param events events of the proposal execution
+ * @returns proposal hash
+ */
+ private checkExecutedEvent(events: IPhasicEvent[]): string {
+ const executionEvents = events.filter(x =>
+ x.event.section === this.collective && (x.event.method === 'Executed' || x.event.method === 'MemberExecuted'));
+
+ if(executionEvents.length != 1) {
+ if(events.filter(x => x.event.section === this.collective && x.event.method === 'Disapproved').length > 0)
+ throw new Error(`Disapproved by ${this.collective}`);
+ else
+ throw new Error(`Expected one 'Executed' or 'MemberExecuted' event for ${this.collective}`);
+ }
+
+ const result = (executionEvents[0].event.data as any).result;
+
+ if(result.isErr) {
+ if(result.asErr.isModule) {
+ const error = result.asErr.asModule;
+ const metaError = this.helper.getApi()?.registry.findMetaError(error);
+ throw new Error(`Proposal execution failed with ${metaError.section}.${metaError.name}`);
+ } else {
+ throw new Error('Proposal execution failed with ' + result.asErr.toHuman());
+ }
+ }
+
+ return (executionEvents[0].event.data as any).proposalHash;
+ }
+
+ /**
+ * Returns an array of members' addresses.
+ */
+ async getMembers() {
+ return (await this.helper.callRpc(`api.query.${this.collective}.members`, [])).toHuman();
+ }
+
+ /**
+ * Returns the optional address of the prime member of the collective.
+ */
+ async getPrimeMember() {
+ return (await this.helper.callRpc(`api.query.${this.collective}.prime`, [])).toHuman();
+ }
+
+ /**
+ * Returns an array of proposal hashes that are currently active for this collective.
+ */
+ async getProposals() {
+ return (await this.helper.callRpc(`api.query.${this.collective}.proposals`, [])).toHuman();
+ }
+
+ /**
+ * Returns the call originally encoded under the specified hash.
+ * @param hash h256-encoded proposal
+ * @returns the optional call that the proposal hash stands for.
+ */
+ async getProposalCallOf(hash: string) {
+ return (await this.helper.callRpc(`api.query.${this.collective}.proposalOf`, [hash])).toHuman();
+ }
+
+ /**
+ * Returns the total number of proposals so far.
+ */
+ async getTotalProposalsCount() {
+ return (await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, [])).toNumber();
+ }
+
+ /**
+ * Creates a new proposal up for voting. If the threshold is set to 1, the proposal will be executed immediately.
+ * @param signer keyring of the proposer
+ * @param proposal constructed call to be executed if the proposal is successful
+ * @param voteThreshold minimal number of votes for the proposal to be verified and executed
+ * @param lengthBound byte length of the encoded call
+ * @returns promise of extrinsic execution and its result
+ */
+ async propose(signer: TSigner, proposal: any, voteThreshold: number, lengthBound = 10000) {
+ return await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [voteThreshold, proposal, lengthBound]);
+ }
+
+ /**
+ * Casts a vote to either approve or reject a proposal.
+ * @param signer keyring of the voter
+ * @param proposalHash hash of the proposal to be voted for
+ * @param proposalIndex absolute index of the proposal used for absolutely nothing but throwing pointless errors
+ * @param approve aye or nay
+ * @returns promise of extrinsic execution and its result
+ */
+ vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve]);
+ }
+
+ /**
+ * Executes a call immediately as a member of the collective. Needed for the Member origin.
+ * @param signer keyring of the executor member
+ * @param proposal constructed call to be executed by the member
+ * @param lengthBound byte length of the encoded call
+ * @returns promise of extrinsic execution
+ */
+ async execute(signer: TSigner, proposal: any, lengthBound = 10000) {
+ const result = await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.execute`, [proposal, lengthBound]);
+ this.checkExecutedEvent(result.result.events);
+ return result;
+ }
+
+ /**
+ * Attempt to close and execute a proposal. Note that there must already be enough votes to meet the threshold set when proposing.
+ * @param signer keyring of the executor. Can be absolutely anyone.
+ * @param proposalHash hash of the proposal to close
+ * @param proposalIndex index of the proposal generated on its creation
+ * @param weightBound weight of the proposed call. Can be obtained by calling `paymentInfo()` on the call.
+ * @param lengthBound byte length of the encoded call
+ * @returns promise of extrinsic execution and its result
+ */
+ async close(
+ signer: TSigner,
+ proposalHash: string,
+ proposalIndex: number,
+ weightBound: [number, number] | any = [20_000_000_000, 1000_000],
+ lengthBound = 10_000,
+ ) {
+ const result = await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [
+ proposalHash,
+ proposalIndex,
+ weightBound,
+ lengthBound,
+ ]);
+ this.checkExecutedEvent(result.result.events);
+ return result;
+ }
+
+ /**
+ * Shut down a proposal, regardless of its current state.
+ * @param signer keyring of the disapprover. Must be root
+ * @param proposalHash hash of the proposal to close
+ * @returns promise of extrinsic execution and its result
+ */
+ disapproveProposal(signer: TSigner, proposalHash: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.disapproveProposal`, [proposalHash]);
+ }
+}
+
+export class CollectiveMembershipGroup extends HelperGroup<UniqueHelper> {
+ /**
+ * Pallet name to make an API call to. Examples: 'councilMembership', 'technicalCommitteeMembership'
+ */
+ private membership: string;
+
+ constructor(helper: UniqueHelper, membership: string) {
+ super(helper);
+ this.membership = membership;
+ }
+
+ /**
+ * Returns an array of members' addresses according to the membership pallet's perception.
+ * Note that it does not recognize the original pallet's members set with `setMembers()`.
+ */
+ async getMembers() {
+ return (await this.helper.callRpc(`api.query.${this.membership}.members`, [])).toHuman();
+ }
+
+ /**
+ * Returns the optional address of the prime member of the collective.
+ */
+ async getPrimeMember() {
+ return (await this.helper.callRpc(`api.query.${this.membership}.prime`, [])).toHuman();
+ }
+
+ /**
+ * Add a member to the collective.
+ * @param signer keyring of the setter. Must be root
+ * @param member address of the member to add
+ * @returns promise of extrinsic execution and its result
+ */
+ addMember(signer: TSigner, member: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.addMember`, [member]);
+ }
+
+ addMemberCall(member: string) {
+ return this.helper.constructApiCall(`api.tx.${this.membership}.addMember`, [member]);
+ }
+
+ /**
+ * Remove a member from the collective.
+ * @param signer keyring of the setter. Must be root
+ * @param member address of the member to remove
+ * @returns promise of extrinsic execution and its result
+ */
+ removeMember(signer: TSigner, member: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.removeMember`, [member]);
+ }
+
+ removeMemberCall(member: string) {
+ return this.helper.constructApiCall(`api.tx.${this.membership}.removeMember`, [member]);
+ }
+
+ /**
+ * Set members of the collective to the given list of addresses.
+ * @param signer keyring of the setter. Must be root (for the direct call, bypassing a public motion)
+ * @param members addresses of the members to set
+ * @returns promise of extrinsic execution and its result
+ */
+ resetMembers(signer: TSigner, members: string[]) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.resetMembers`, [members]);
+ }
+
+ /**
+ * Set the collective's prime member to the given address.
+ * @param signer keyring of the setter. Must be root (for the direct call, bypassing a public motion)
+ * @param prime address of the prime member of the collective
+ * @returns promise of extrinsic execution and its result
+ */
+ setPrime(signer: TSigner, prime: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.setPrime`, [prime]);
+ }
+
+ setPrimeCall(member: string) {
+ return this.helper.constructApiCall(`api.tx.${this.membership}.setPrime`, [member]);
+ }
+
+ /**
+ * Remove the collective's prime member.
+ * @param signer keyring of the setter. Must be root (for the direct call, bypassing a public motion)
+ * @returns promise of extrinsic execution and its result
+ */
+ clearPrime(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.membership}.clearPrime`, []);
+ }
+
+ clearPrimeCall() {
+ return this.helper.constructApiCall(`api.tx.${this.membership}.clearPrime`, []);
+ }
+}
+
+export class RankedCollectiveGroup extends HelperGroup<UniqueHelper> {
+ /**
+ * Pallet name to make an API call to. Examples: 'FellowshipCollective'
+ */
+ private collective: string;
+
+ constructor(helper: UniqueHelper, collective: string) {
+ super(helper);
+ this.collective = collective;
+ }
+
+ addMember(signer: TSigner, newMember: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.addMember`, [newMember]);
+ }
+
+ addMemberCall(newMember: string) {
+ return this.helper.constructApiCall(`api.tx.${this.collective}.addMember`, [newMember]);
+ }
+
+ removeMember(signer: TSigner, member: string, minRank: number) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.removeMember`, [member, minRank]);
+ }
+
+ removeMemberCall(newMember: string, minRank: number) {
+ return this.helper.constructApiCall(`api.tx.${this.collective}.removeMember`, [newMember, minRank]);
+ }
+
+ promote(signer: TSigner, member: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.promoteMember`, [member]);
+ }
+
+ promoteCall(member: string) {
+ return this.helper.constructApiCall(`api.tx.${this.collective}.promoteMember`, [member]);
+ }
+
+ demote(signer: TSigner, member: string) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.demoteMember`, [member]);
+ }
+
+ demoteCall(newMember: string) {
+ return this.helper.constructApiCall(`api.tx.${this.collective}.demoteMember`, [newMember]);
+ }
+
+ vote(signer: TSigner, pollIndex: number, aye: boolean) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [pollIndex, aye]);
+ }
+
+ async getMembers() {
+ return (await this.helper.getApi().query.fellowshipCollective.members.keys())
+ .map((key) => key.args[0].toString());
+ }
+
+ async getMemberRank(member: string) {
+ return (await this.helper.callRpc('api.query.fellowshipCollective.members', [member])).toJSON().rank;
+ }
+}
+
+export class ReferendaGroup extends HelperGroup<UniqueHelper> {
+ /**
+ * Pallet name to make an API call to. Examples: 'FellowshipReferenda'
+ */
+ private referenda: string;
+
+ constructor(helper: UniqueHelper, referenda: string) {
+ super(helper);
+ this.referenda = referenda;
+ }
+
+ submit(
+ signer: TSigner,
+ proposalOrigin: string,
+ proposal: any,
+ enactmentMoment: any,
+ ) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.referenda}.submit`, [
+ {Origins: proposalOrigin},
+ proposal,
+ enactmentMoment,
+ ]);
+ }
+
+ placeDecisionDeposit(signer: TSigner, referendumIndex: number) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.referenda}.placeDecisionDeposit`, [referendumIndex]);
+ }
+
+ cancel(signer: TSigner, referendumIndex: number) {
+ return this.helper.executeExtrinsic(signer, `api.tx.${this.referenda}.cancel`, [referendumIndex]);
+ }
+
+ cancelCall(referendumIndex: number) {
+ return this.helper.constructApiCall(`api.tx.${this.referenda}.cancel`, [referendumIndex]);
+ }
+
+ async referendumInfo(referendumIndex: number) {
+ return (await this.helper.callRpc(`api.query.${this.referenda}.referendumInfoFor`, [referendumIndex])).toJSON();
+ }
+
+ async enactmentEventId(referendumIndex: number) {
+ const api = await this.helper.getApi();
+
+ const bytes = api.createType('([u8;8], Text, u32)', ['assembly', 'enactment', referendumIndex]).toU8a();
+ return blake2AsHex(bytes, 256);
+ }
+}
+
+export interface IFellowshipGroup {
+ collective: RankedCollectiveGroup;
+ referenda: ReferendaGroup;
+}
+
+export interface ICollectiveGroup {
+ collective: CollectiveGroup;
+ membership: CollectiveMembershipGroup;
+}
+
+export class DemocracyGroup extends HelperGroup<UniqueHelper> {
+ // todo displace proposal into types?
+ propose(signer: TSigner, call: any, deposit: bigint) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.propose', [{Inline: call.method.toHex()}, deposit]);
+ }
+
+ proposeWithPreimage(signer: TSigner, preimage: string, deposit: bigint) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.propose', [{Legacy: preimage}, deposit]);
+ }
+
+ proposeCall(call: any, deposit: bigint) {
+ return this.helper.constructApiCall('api.tx.democracy.propose', [{Inline: call.method.toHex()}, deposit]);
+ }
+
+ second(signer: TSigner, proposalIndex: number) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.second', [proposalIndex]);
+ }
+
+ externalPropose(signer: TSigner, proposalCall: any) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalPropose', [{Inline: proposalCall.method.toHex()}]);
+ }
+
+ externalProposeMajority(signer: TSigner, proposalCall: any) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalProposeMajority', [{Inline: proposalCall.method.toHex()}]);
+ }
+
+ externalProposeDefault(signer: TSigner, proposalCall: any) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalProposeDefault', [{Inline: proposalCall.method.toHex()}]);
+ }
+
+ externalProposeDefaultWithPreimage(signer: TSigner, preimage: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.externalProposeDefault', [{Legacy: preimage}]);
+ }
+
+ externalProposeCall(proposalCall: any) {
+ return this.helper.constructApiCall('api.tx.democracy.externalPropose', [{Inline: proposalCall.method.toHex()}]);
+ }
+
+ externalProposeMajorityCall(proposalCall: any) {
+ return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [{Inline: proposalCall.method.toHex()}]);
+ }
+
+ externalProposeDefaultCall(proposalCall: any) {
+ return this.helper.constructApiCall('api.tx.democracy.externalProposeDefault', [{Inline: proposalCall.method.toHex()}]);
+ }
+
+ externalProposeDefaultWithPreimageCall(preimage: string) {
+ return this.helper.constructApiCall('api.tx.democracy.externalProposeDefault', [{Legacy: preimage}]);
+ }
+
+ // ... and blacklist external proposal hash.
+ vetoExternal(signer: TSigner, proposalHash: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.vetoExternal', [proposalHash]);
+ }
+
+ vetoExternalCall(proposalHash: string) {
+ return this.helper.constructApiCall('api.tx.democracy.vetoExternal', [proposalHash]);
+ }
+
+ blacklist(signer: TSigner, proposalHash: string, referendumIndex: number | null = null) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.blacklist', [proposalHash, referendumIndex]);
+ }
+
+ blacklistCall(proposalHash: string, referendumIndex: number | null = null) {
+ return this.helper.constructApiCall('api.tx.democracy.blacklist', [proposalHash, referendumIndex]);
+ }
+
+ // proposal. CancelProposalOrigin (root or all techcom)
+ cancelProposal(signer: TSigner, proposalIndex: number) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.cancelProposal', [proposalIndex]);
+ }
+
+ cancelProposalCall(proposalIndex: number) {
+ return this.helper.constructApiCall('api.tx.democracy.cancelProposal', [proposalIndex]);
+ }
+
+ clearPublicProposals(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.clearPublicProposals', []);
+ }
+
+ fastTrack(signer: TSigner, proposalHash: string, votingPeriod: number, delayPeriod: number) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);
+ }
+
+ fastTrackCall(proposalHash: string, votingPeriod: number, delayPeriod: number) {
+ return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);
+ }
+
+ // referendum. CancellationOrigin (TechCom member)
+ emergencyCancel(signer: TSigner, referendumIndex: number) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.emergencyCancel', [referendumIndex]);
+ }
+
+ emergencyCancelCall(referendumIndex: number) {
+ return this.helper.constructApiCall('api.tx.democracy.emergencyCancel', [referendumIndex]);
+ }
+
+ vote(signer: TSigner, referendumIndex: number, vote: any) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, vote]);
+ }
+
+ removeVote(signer: TSigner, referendumIndex: number, targetAccount?: string) {
+ if(targetAccount) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.removeOtherVote', [targetAccount, referendumIndex]);
+ } else {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.removeVote', [referendumIndex]);
+ }
+ }
+
+ unlock(signer: TSigner, targetAccount: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.unlock', [targetAccount]);
+ }
+
+ delegate(signer: TSigner, toAccount: string, conviction: PalletDemocracyConviction, balance: bigint) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.delegate', [toAccount, conviction, balance]);
+ }
+
+ undelegate(signer: TSigner) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.undelegate', []);
+ }
+
+ async referendumInfo(referendumIndex: number) {
+ return (await this.helper.callRpc('api.query.democracy.referendumInfoOf', [referendumIndex])).toJSON();
+ }
+
+ async publicProposals() {
+ return (await this.helper.callRpc('api.query.democracy.publicProps', [])).toJSON();
+ }
+
+ async findPublicProposal(proposalIndex: number) {
+ const proposalInfo = (await this.publicProposals()).find((proposalInfo: any[]) => proposalInfo[0] == proposalIndex);
+
+ return proposalInfo ? proposalInfo[1] : null;
+ }
+
+ async expectPublicProposal(proposalIndex: number) {
+ const proposal = await this.findPublicProposal(proposalIndex);
+
+ if(proposal) {
+ return proposal;
+ } else {
+ throw Error(`Proposal #${proposalIndex} is expected to exist`);
+ }
+ }
+
+ async getExternalProposal() {
+ return (await this.helper.callRpc('api.query.democracy.nextExternal', []));
+ }
+
+ async expectExternalProposal() {
+ const proposal = await this.getExternalProposal();
+
+ if(proposal) {
+ return proposal;
+ } else {
+ throw Error('An external proposal is expected to exist');
+ }
+ }
+
+ /* setMetadata? */
+
+ /* todo?
+ referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);
+ }*/
+}
js-packages/playgrounds/unique.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/playgrounds/unique.ts
@@ -0,0 +1,3498 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+/* eslint-disable @typescript-eslint/no-var-requires */
+/* eslint-disable function-call-argument-newline */
+/* eslint-disable no-prototype-builtins */
+
+import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';
+import type {SignerOptions} from '@polkadot/api/types';
+import type {AugmentedSubmittables} from '@polkadot/api-base/types/submittable';
+import type {ApiInterfaceEvents} from '@polkadot/api/types';
+import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {hexToU8a} from '@polkadot/util/hex';
+import {u8aConcat} from '@polkadot/util/u8a';
+import type {
+ IApiListeners,
+ IBlock,
+ IEvent,
+ IChainProperties,
+ ICollectionCreationOptions,
+ ICollectionLimits,
+ ICollectionPermissions,
+ ICrossAccountId,
+ ICrossAccountIdLower,
+ ILogger,
+ INestingPermissions,
+ IProperty,
+ IStakingInfo,
+ ISubstrateBalance,
+ IToken,
+ ITokenPropertyPermission,
+ ITransactionResult,
+ IUniqueHelperLog,
+ TApiAllowedListeners,
+ TEthereumAccount,
+ TSigner,
+ TSubstrateAccount,
+ TNetworks,
+ IEthCrossAccountId,
+} from './types.js';
+import type {RuntimeDispatchInfo} from '@polkadot/types/interfaces';
+
+export class CrossAccountId {
+ account: ICrossAccountId;
+
+ constructor(account: ICrossAccountId) {
+ this.account = account;
+ }
+
+ static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {
+ switch (domain) {
+ case 'Substrate': return new CrossAccountId({Substrate: account.address});
+ case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();
+ }
+ }
+
+ static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {
+ if('substrate' in address) return new CrossAccountId({Substrate: address.substrate});
+ else return new CrossAccountId({Ethereum: address.ethereum});
+ }
+
+ static normalizeSubstrateAddress(address: {Substrate: TSubstrateAccount}, ss58Format = 42): TSubstrateAccount {
+ return encodeAddress(decodeAddress(address.Substrate), ss58Format);
+ }
+
+ static withNormalizedSubstrate(address: ICrossAccountId, ss58Format = 42): ICrossAccountId {
+ if('Substrate' in address) return {Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)};
+ return address;
+ }
+
+ withNormalizedSubstrate(ss58Format = 42): CrossAccountId {
+ if('Substrate' in this.account) this.account = CrossAccountId.withNormalizedSubstrate(this.account, ss58Format);
+ return this;
+ }
+
+ static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {
+ return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));
+ }
+
+ toEthereum(): CrossAccountId {
+ this.account = CrossAccountId.toEthereum(this.account);
+ return this;
+ }
+
+ static toEthereum(account: ICrossAccountId): ICrossAccountId {
+ if('Substrate' in account) return {Ethereum: CrossAccountId.translateSubToEth(account.Substrate)};
+ return account;
+ }
+
+ static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {
+ return evmToAddress(address, ss58Format);
+ }
+
+ toSubstrate(ss58Format?: number): CrossAccountId {
+ this.account = CrossAccountId.toSubstrate(this.account, ss58Format);
+ return this;
+ }
+
+ static toSubstrate(account: ICrossAccountId, ss58Format?: number): ICrossAccountId {
+ if('Ethereum' in account) return {Substrate: CrossAccountId.translateEthToSub(account.Ethereum, ss58Format)};
+ return account;
+ }
+
+ toLowerCase(): CrossAccountId {
+ this.account = CrossAccountId.toLowerCase(this.account);
+ return this;
+ }
+
+ static toLowerCase(account: ICrossAccountId) {
+ if('Substrate' in account) return {Substrate: account.Substrate.toLowerCase()};
+ if('Ethereum' in account) return {Ethereum: account.Ethereum.toLowerCase()};
+ return account;
+ }
+
+ toICrossAccountId(): ICrossAccountId {
+ return this.account;
+ }
+}
+
+const nesting = {
+ toChecksumAddress(address: string): string {
+ if(typeof address === 'undefined') return '';
+
+ if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);
+
+ address = address.toLowerCase().replace(/^0x/i, '');
+ const addressHash = keccakAsHex(address).replace(/^0x/i, '');
+ const checksumAddress = ['0x'];
+
+ for(let i = 0; i < address.length; i++) {
+ // If ith character is 8 to f then make it uppercase
+ if(parseInt(addressHash[i], 16) > 7) {
+ checksumAddress.push(address[i].toUpperCase());
+ } else {
+ checksumAddress.push(address[i]);
+ }
+ }
+ return checksumAddress.join('');
+ },
+ tokenIdToAddress(collectionId: number, tokenId: number) {
+ return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8, '0')}${tokenId.toString(16).padStart(8, '0')}`);
+ },
+};
+
+class UniqueUtil {
+ static transactionStatus = {
+ NOT_READY: 'NotReady',
+ FAIL: 'Fail',
+ SUCCESS: 'Success',
+ };
+
+ static chainLogType = {
+ EXTRINSIC: 'extrinsic',
+ RPC: 'rpc',
+ };
+
+ static getTokenAccount(token: IToken): ICrossAccountId {
+ return {Ethereum: this.getTokenAddress(token)};
+ }
+
+ static getTokenAddress(token: IToken): string {
+ return nesting.tokenIdToAddress(token.collectionId, token.tokenId);
+ }
+
+ static getDefaultLogger(): ILogger {
+ return {
+ log(msg: any, level = 'INFO') {
+ console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));
+ },
+ level: {
+ ERROR: 'ERROR',
+ WARNING: 'WARNING',
+ INFO: 'INFO',
+ },
+ };
+ }
+
+ static vec2str(arr: string[] | number[]) {
+ return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');
+ }
+
+ static str2vec(string: string) {
+ if(typeof string !== 'string') return string;
+ return Array.from(string).map(x => x.charCodeAt(0));
+ }
+
+ static fromSeed(seed: string, ss58Format = 42) {
+ const keyring = new Keyring({type: 'sr25519', ss58Format});
+ return keyring.addFromUri(seed);
+ }
+
+ static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {
+ if(creationResult.status !== this.transactionStatus.SUCCESS) {
+ throw Error('Unable to create collection!');
+ }
+
+ let collectionId = null;
+ creationResult.result.events.forEach(({event: {data, method, section}}) => {
+ if((section === 'common') && (method === 'CollectionCreated')) {
+ collectionId = parseInt(data[0].toString(), 10);
+ }
+ });
+
+ if(collectionId === null) {
+ throw Error('No CollectionCreated event was found!');
+ }
+
+ return collectionId;
+ }
+
+ static extractTokensFromCreationResult(creationResult: ITransactionResult): {
+ success: boolean,
+ tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],
+ } {
+ if(creationResult.status !== this.transactionStatus.SUCCESS) {
+ throw Error('Unable to create tokens!');
+ }
+ let success = false;
+ const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];
+ creationResult.result.events.forEach(({event: {data, method, section}}) => {
+ if(method === 'ExtrinsicSuccess') {
+ success = true;
+ } else if((section === 'common') && (method === 'ItemCreated')) {
+ tokens.push({
+ collectionId: parseInt(data[0].toString(), 10),
+ tokenId: parseInt(data[1].toString(), 10),
+ owner: data[2].toHuman(),
+ amount: data[3].toBigInt(),
+ });
+ }
+ });
+ return {success, tokens};
+ }
+
+ static extractTokensFromBurnResult(burnResult: ITransactionResult): {
+ success: boolean,
+ tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],
+ } {
+ if(burnResult.status !== this.transactionStatus.SUCCESS) {
+ throw Error('Unable to burn tokens!');
+ }
+ let success = false;
+ const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];
+ burnResult.result.events.forEach(({event: {data, method, section}}: any) => {
+ if(method === 'ExtrinsicSuccess') {
+ success = true;
+ } else if((section === 'common') && (method === 'ItemDestroyed')) {
+ tokens.push({
+ collectionId: parseInt(data[0].toString(), 10),
+ tokenId: parseInt(data[1].toString(), 10),
+ owner: data[2].toHuman(),
+ amount: data[3].toBigInt(),
+ });
+ }
+ });
+ return {success, tokens};
+ }
+
+ static findCollectionInEvents(events: { event: IEvent }[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {
+ let eventId = null;
+ events.forEach(({event: {data, method, section}}) => {
+ if((section === expectedSection) && (method === expectedMethod)) {
+ eventId = parseInt(data[0].toString(), 10);
+ }
+ });
+
+ if(eventId === null) {
+ throw Error(`No ${expectedMethod} event was found!`);
+ }
+ return eventId === collectionId;
+ }
+
+ static isTokenTransferSuccess(events: { event: IEvent }[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
+ const normalizeAddress = (address: string | ICrossAccountId) => {
+ if(typeof address === 'string') return address;
+ if('Substrate' in address) return CrossAccountId.withNormalizedSubstrate(address);
+ if('Ethereum' in address) return CrossAccountId.toLowerCase(address);
+ return address;
+ };
+ let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;
+ events.forEach(({event: {data, method, section}}) => {
+ if((section === 'common') && (method === 'Transfer')) {
+ transfer = {
+ collectionId: data[0].toJSON(),
+ tokenId: data[1].toJSON(),
+ from: normalizeAddress(data[2].toHuman()),
+ to: normalizeAddress(data[3].toHuman()),
+ amount: BigInt(data[4].toJSON()),
+ };
+ }
+ });
+ let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;
+ isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);
+ isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);
+ isSuccess = isSuccess && amount === transfer.amount;
+ return isSuccess;
+ }
+
+ static bigIntToDecimals(number: bigint, decimals = 18) {
+ const numberStr = number.toString();
+ const dotPos = numberStr.length - decimals;
+
+ if(dotPos <= 0) {
+ return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;
+ } else {
+ const intPart = numberStr.substring(0, dotPos);
+ const fractPart = numberStr.substring(dotPos);
+ return intPart + '.' + fractPart;
+ }
+ }
+}
+
+class UniqueEventHelper {
+ static extractIndex(index: any): [number, number] | string {
+ if(index.toRawType() === '[u8;2]') return [index[0], index[1]];
+ return index.toJSON();
+ }
+
+ static extractSub(data: any, subTypes: any): { [key: string]: any } {
+ let obj: any = {};
+ let index = 0;
+
+ if(data.entries) {
+ for(const [key, value] of data.entries()) {
+ obj[key] = this.extractData(value, subTypes[index]);
+ index++;
+ }
+ } else obj = data.toJSON();
+
+ return obj;
+ }
+
+ static toHuman(data: any) {
+ return data && data.toHuman ? data.toHuman() : `${data}`;
+ }
+
+ static extractData(data: any, type: any): any {
+ if(!type) return this.toHuman(data);
+ if(['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();
+ if(['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();
+ if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);
+ return this.toHuman(data);
+ }
+
+ public static extractEvents(events: { event: any, phase: any }[]): IEvent[] {
+ const parsedEvents: IEvent[] = [];
+
+ events.forEach((record) => {
+ const {event, phase} = record;
+ const types = event.typeDef;
+
+ const eventData: IEvent = {
+ section: event.section.toString(),
+ method: event.method.toString(),
+ index: this.extractIndex(event.index),
+ data: [],
+ phase: phase.toJSON(),
+ };
+
+ event.data.forEach((val: any, index: number) => {
+ eventData.data.push(this.extractData(val, types[index]));
+ });
+
+ parsedEvents.push(eventData);
+ });
+
+ return parsedEvents;
+ }
+}
+const InvalidTypeSymbol = Symbol('Invalid type');
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export type Invalid =
+ | ((
+ invalidType: typeof InvalidTypeSymbol,
+ ..._: typeof InvalidTypeSymbol[]
+ ) => typeof InvalidTypeSymbol)
+ | null
+ | undefined;
+// Has slightly better error messages than Get
+type Get2<T, P extends string, E> =
+ P extends `${infer Key}.${infer Key2}` ? Key extends keyof T ? Key2 extends keyof T[Key] ? T[Key][Key2] : E : E : E;
+type ForceFunction<T> = T extends (...args: any) => any ? T : (...args: any) => Invalid;
+
+export class ChainHelperBase {
+ helperBase: any;
+
+ transactionStatus = UniqueUtil.transactionStatus;
+ chainLogType = UniqueUtil.chainLogType;
+ util: typeof UniqueUtil;
+ eventHelper: typeof UniqueEventHelper;
+ logger: ILogger;
+ api: ApiPromise | null;
+ forcedNetwork: TNetworks | null;
+ network: TNetworks | null;
+ wsEndpoint: string | null;
+ chainLog: IUniqueHelperLog[];
+ children: ChainHelperBase[];
+ address: AddressGroup;
+ chain: ChainGroup;
+
+ constructor(logger?: ILogger, helperBase?: any) {
+ this.helperBase = helperBase;
+
+ this.util = UniqueUtil;
+ this.eventHelper = UniqueEventHelper;
+ if(typeof logger == 'undefined') logger = this.util.getDefaultLogger();
+ this.logger = logger;
+ this.api = null;
+ this.forcedNetwork = null;
+ this.network = null;
+ this.wsEndpoint = null;
+ this.chainLog = [];
+ this.children = [];
+ this.address = new AddressGroup(this);
+ this.chain = new ChainGroup(this);
+ }
+
+ clone(helperCls: ChainHelperBaseConstructor, options: { [key: string]: any } = {}) {
+ Object.setPrototypeOf(helperCls.prototype, this);
+ const newHelper = new helperCls(this.logger, options);
+
+ newHelper.api = this.api;
+ newHelper.network = this.network;
+ newHelper.forceNetwork = this.forceNetwork;
+
+ this.children.push(newHelper);
+
+ return newHelper;
+ }
+
+ getEndpoint(): string {
+ if(this.wsEndpoint === null) throw Error('No connection was established');
+ return this.wsEndpoint;
+ }
+
+ getApi(): ApiPromise {
+ if(this.api === null) throw Error('API not initialized');
+ return this.api;
+ }
+
+ async subscribeEvents(expectedEvents: { section: string, names: string[] }[]) {
+ const collectedEvents: IEvent[] = [];
+ const unsubscribe = await this.getApi().query.system.events((events: any) => {
+ const ievents = this.eventHelper.extractEvents(events);
+ ievents.forEach((event) => {
+ expectedEvents.forEach((e => {
+ if(event.section === e.section && e.names.includes(event.method)) {
+ collectedEvents.push(event);
+ }
+ }));
+ });
+ });
+ return {unsubscribe: unsubscribe as any, collectedEvents};
+ }
+
+ clearChainLog(): void {
+ this.chainLog = [];
+ }
+
+ forceNetwork(value: TNetworks): void {
+ this.forcedNetwork = value;
+ }
+
+ async connect(wsEndpoint: string, listeners?: IApiListeners) {
+ if(this.api !== null) throw Error('Already connected');
+ const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);
+ this.wsEndpoint = wsEndpoint;
+ this.api = api;
+ this.network = network;
+ }
+
+ async disconnect() {
+ for(const child of this.children) {
+ child.clearApi();
+ }
+
+ if(this.api === null) return;
+ await this.api.disconnect();
+ this.clearApi();
+ }
+
+ clearApi() {
+ this.api = null;
+ this.network = null;
+ }
+
+ static async detectNetwork(api: ApiPromise): Promise<TNetworks> {
+ const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;
+ const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];
+
+ if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;
+
+ if(['quartz', 'unique', 'sapphire'].indexOf(spec.specName) > -1) return spec.specName;
+ return 'opal';
+ }
+
+ static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {
+ if(!wsEndpoint) throw new Error('wsEndpoint was not set');
+ const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});
+ await api.isReady;
+
+ const network = await this.detectNetwork(api);
+
+ await api.disconnect();
+
+ return network;
+ }
+
+ static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{
+ api: ApiPromise;
+ network: TNetworks;
+ }> {
+ if(typeof network === 'undefined' || network === null) network = 'opal';
+ if(!wsEndpoint) throw new Error('wsEndpoint was not set');
+ const supportedRPC = {
+ opal: {
+ unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,
+ },
+ quartz: {
+ unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,
+ },
+ unique: {
+ unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,
+ },
+ rococo: {},
+ westend: {},
+ moonbeam: {},
+ moonriver: {},
+ acala: {},
+ karura: {},
+ westmint: {},
+ };
+ if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);
+ const rpc = supportedRPC[network] as any;
+
+ // TODO: investigate how to replace rpc in runtime
+ // api._rpcCore.addUserInterfaces(rpc);
+
+ const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});
+
+ await api.isReadyOrError;
+
+ if(typeof listeners === 'undefined') listeners = {};
+ for(const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {
+ if(!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;
+ api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);
+ }
+
+ return {api, network};
+ }
+
+ getTransactionStatus(data: { events: { event: IEvent }[], status: any }) {
+ const {events, status} = data;
+ if(status.isReady) {
+ return this.transactionStatus.NOT_READY;
+ }
+ if(status.isBroadcast) {
+ return this.transactionStatus.NOT_READY;
+ }
+ if(status.isInBlock || status.isFinalized) {
+ const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');
+ if(errors.length > 0) {
+ return this.transactionStatus.FAIL;
+ }
+ if(events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {
+ return this.transactionStatus.SUCCESS;
+ }
+ }
+
+ return this.transactionStatus.FAIL;
+ }
+
+ signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {
+ const sign = (callback: any) => {
+ if(options !== null) return transaction.signAndSend(sender, options, callback);
+ return transaction.signAndSend(sender, callback);
+ };
+ // eslint-disable-next-line no-async-promise-executor
+ return new Promise(async (resolve, reject) => {
+ try {
+ const unsub = await sign((result: any) => {
+ const status = this.getTransactionStatus(result);
+
+ if(status === this.transactionStatus.SUCCESS) {
+ this.logger.log(`${label} successful`);
+ unsub();
+ resolve({result, status, blockHash: result.status.asInBlock.toHuman()});
+ } else if(status === this.transactionStatus.FAIL) {
+ let moduleError = null;
+
+ if(result.hasOwnProperty('dispatchError')) {
+ const dispatchError = result['dispatchError'];
+
+ if(dispatchError) {
+ if(dispatchError.isModule) {
+ const modErr = dispatchError.asModule;
+ const errorMeta = dispatchError.registry.findMetaError(modErr);
+
+ moduleError = `${errorMeta.section}.${errorMeta.name}`;
+ } else if(dispatchError.isToken) {
+ moduleError = `Token: ${dispatchError.asToken}`;
+ } else {
+ // May be [object Object] in case of unhandled non-unit enum
+ moduleError = `Misc: ${dispatchError.toHuman()}`;
+ }
+ } else {
+ this.logger.log(result, this.logger.level.ERROR);
+ }
+ }
+
+ this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);
+ unsub();
+ reject({status, moduleError, result});
+ }
+ });
+ } catch (e) {
+ this.logger.log(e, this.logger.level.ERROR);
+ reject(e);
+ }
+ });
+ }
+
+ async signTransactionWithoutSending(signer: TSigner, tx: any) {
+ const api = this.getApi();
+ const signingInfo = await api.derive.tx.signingInfo(signer.address);
+
+ tx.sign(signer, {
+ blockHash: api.genesisHash,
+ genesisHash: api.genesisHash,
+ runtimeVersion: api.runtimeVersion,
+ nonce: signingInfo.nonce,
+ });
+
+ return tx.toHex();
+ }
+
+ async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {
+ const api = this.getApi();
+ const signingInfo = await api.derive.tx.signingInfo(signer.address);
+
+ // We need to sign the tx because
+ // unsigned transactions does not have an inclusion fee
+ tx.sign(signer, {
+ blockHash: api.genesisHash,
+ genesisHash: api.genesisHash,
+ runtimeVersion: api.runtimeVersion,
+ nonce: signingInfo.nonce,
+ });
+
+ if(len === null) {
+ return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;
+ } else {
+ return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;
+ }
+ }
+
+ constructApiCall(apiCall: string, params: any[]) {
+ if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);
+ let call = this.getApi() as any;
+ for(const part of apiCall.slice(4).split('.')) {
+ call = call[part];
+ if(!call) {
+ const advice = part.includes('_') ? ' Looks like it needs to be converted to camel case.' : '';
+ throw Error(`Function ${part} of api call ${apiCall} not found.${advice}`);
+ }
+ }
+ return call(...params);
+ }
+
+ encodeApiCall(apiCall: string, params: any[]) {
+ return this.constructApiCall(apiCall, params).method.toHex();
+ }
+
+ async executeExtrinsic<
+ E extends string,
+ V extends (
+ ...args: any) => any = ForceFunction<
+ Get2<
+ AugmentedSubmittables<'promise'>,
+ E, (...args: any) => Invalid
+ >
+ >
+ >(
+ sender: TSigner,
+ extrinsic: `api.tx.${E}`,
+ params: Parameters<V>,
+ expectSuccess = true,
+ options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/
+ ): Promise<ITransactionResult> {
+ if(this.api === null) throw Error('API not initialized');
+
+ const startTime = (new Date()).getTime();
+ let result: ITransactionResult;
+ let events: IEvent[] = [];
+ try {
+ result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;
+ events = this.eventHelper.extractEvents(result.result.events);
+ const errorEvent = events.find((event) => event.method == 'ExecutedFailed' || event.method == 'CreatedFailed');
+ if(errorEvent)
+ throw Error(errorEvent.method + ': ' + extrinsic);
+ }
+ catch (e) {
+ if(!(e as object).hasOwnProperty('status')) throw e;
+ result = e as ITransactionResult;
+ }
+
+ const endTime = (new Date()).getTime();
+
+ const log = {
+ executedAt: endTime,
+ executionTime: endTime - startTime,
+ type: this.chainLogType.EXTRINSIC,
+ status: result.status,
+ call: extrinsic,
+ signer: this.getSignerAddress(sender),
+ params,
+ } as IUniqueHelperLog;
+
+ let errorMessage = '';
+
+ if(result.status !== this.transactionStatus.SUCCESS) {
+ if(result.moduleError) {
+ errorMessage = typeof result.moduleError === 'string'
+ ? result.moduleError
+ : `${Object.keys(result.moduleError)[0]}: ${Object.values(result.moduleError)[0]}`;
+ log.moduleError = errorMessage;
+ }
+ else if(result.result.dispatchError) log.dispatchError = result.result.dispatchError;
+ }
+ if(events.length > 0) log.events = events;
+
+ this.chainLog.push(log);
+
+ if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {
+ if(result.moduleError) throw Error(`${errorMessage}`);
+ else if(result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));
+ }
+ return result as any;
+ }
+ executeExtrinsicUncheckedWeight<
+ E extends string,
+ V extends (
+ ...args: any) => any = ForceFunction<
+ Get2<
+ AugmentedSubmittables<'promise'>,
+ E, (...args: any) => Invalid
+ >
+ >
+ >(
+ _sender: TSigner,
+ _extrinsic: `api.tx.${E}`,
+ _params: Parameters<V>,
+ _expectSuccess = true,
+ _options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/
+ ): Promise<ITransactionResult> {
+ throw new Error('executeExtrinsicUncheckedWeight only supported in sudo');
+ }
+
+ async callRpc
+ // TODO: make it strongly typed, or use api.query/api.rpc directly
+ // <
+ // K extends 'rpc' | 'query',
+ // E extends string,
+ // V extends (...args: any) => any = ForceFunction<
+ // Get2<
+ // K extends 'rpc' ? DecoratedRpc<'promise', RpcInterface> : QueryableStorage<'promise'>,
+ // E, (...args: any) => Invalid<'not found'>
+ // >
+ // >,
+ // P = Parameters<V>,
+ // >
+ (rpc: string, params?: any[]): Promise<any> {
+
+ if(typeof params === 'undefined') params = [] as any;
+ if(this.api === null) throw Error('API not initialized');
+ if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);
+
+ const startTime = (new Date()).getTime();
+ let result;
+ let error = null;
+ const log = {
+ type: this.chainLogType.RPC,
+ call: rpc,
+ params,
+ } as any as IUniqueHelperLog;
+
+ try {
+ result = await this.constructApiCall(rpc, params as any);
+ }
+ catch (e) {
+ error = e;
+ }
+
+ const endTime = (new Date()).getTime();
+
+ log.executedAt = endTime;
+ log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';
+ log.executionTime = endTime - startTime;
+
+ this.chainLog.push(log);
+
+ if(error !== null) throw error;
+
+ return result;
+ }
+
+ getSignerAddress(signer: IKeyringPair | string): string {
+ if(typeof signer === 'string') return signer;
+ return signer.address;
+ }
+
+ fetchAllPalletNames(): string[] {
+ if(this.api === null) throw Error('API not initialized');
+ return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()).sort();
+ }
+
+ fetchMissingPalletNames(requiredPallets: readonly string[]): string[] {
+ const palletNames = this.fetchAllPalletNames();
+ return requiredPallets.filter(p => !palletNames.includes(p));
+ }
+}
+
+
+export class HelperGroup<T extends ChainHelperBase> {
+ helper: T;
+
+ constructor(uniqueHelper: T) {
+ this.helper = uniqueHelper;
+ }
+}
+
+
+class CollectionGroup extends HelperGroup<UniqueHelper> {
+ /**
+ * Get number of blocks when sponsored transaction is available.
+ *
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param addressObj address for which the sponsorship is checked
+ * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});
+ * @returns number of blocks or null if sponsorship hasn't been set
+ */
+ async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {
+ return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();
+ }
+
+ /**
+ * Get the number of created collections.
+ *
+ * @returns number of created collections
+ */
+ async getTotalCount(): Promise<number> {
+ return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();
+ }
+
+ /**
+ * Get information about the collection with additional data,
+ * including the number of tokens it contains, its administrators,
+ * the normalized address of the collection's owner, and decoded name and description.
+ *
+ * @param collectionId ID of collection
+ * @example await getData(2)
+ * @returns collection information object
+ */
+ async getData(collectionId: number): Promise<{
+ id: number;
+ name: string;
+ description: string;
+ tokensCount: number;
+ admins: CrossAccountId[];
+ normalizedOwner: TSubstrateAccount;
+ raw: any
+ } | null> {
+ const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);
+ const humanCollection = collection.toHuman(), collectionData = {
+ id: collectionId, name: null, description: null, tokensCount: 0, admins: [],
+ raw: humanCollection,
+ } as any, jsonCollection = collection.toJSON();
+ if(humanCollection === null) return null;
+ collectionData.raw.limits = jsonCollection.limits;
+ collectionData.raw.permissions = jsonCollection.permissions;
+ collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);
+ for(const key of ['name', 'description']) {
+ collectionData[key] = this.helper.util.vec2str(humanCollection[key]);
+ }
+
+ collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))
+ ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)
+ : 0;
+ collectionData.admins = await this.getAdmins(collectionId);
+
+ return collectionData;
+ }
+
+ /**
+ * Get the addresses of the collection's administrators, optionally normalized.
+ *
+ * @param collectionId ID of collection
+ * @param normalize whether to normalize the addresses to the default ss58 format
+ * @example await getAdmins(1)
+ * @returns array of administrators
+ */
+ async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
+ const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman() as ICrossAccountId[];
+
+ return normalize
+ ? admins.map(address => CrossAccountId.withNormalizedSubstrate(address))
+ : admins;
+ }
+
+ /**
+ * Get the addresses added to the collection allow-list, optionally normalized.
+ * @param collectionId ID of collection
+ * @param normalize whether to normalize the addresses to the default ss58 format
+ * @example await getAllowList(1)
+ * @returns array of allow-listed addresses
+ */
+ async getAllowList(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
+ const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman() as ICrossAccountId[];
+ return normalize
+ ? allowListed.map(address => CrossAccountId.withNormalizedSubstrate(address))
+ : allowListed;
+ }
+
+ /**
+ * Get the effective limits of the collection instead of null for default values
+ *
+ * @param collectionId ID of collection
+ * @example await getEffectiveLimits(2)
+ * @returns object of collection limits
+ */
+ async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {
+ return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();
+ }
+
+ /**
+ * Burns the collection if the signer has sufficient permissions and collection is empty.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @example await helper.collection.burn(aliceKeyring, 3);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async burn(signer: TSigner, collectionId: number): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.destroyCollection', [collectionId],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');
+ }
+
+ /**
+ * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param sponsorAddress Sponsor substrate address
+ * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');
+ }
+
+ /**
+ * Confirms consent to sponsor the collection on behalf of the signer.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @example confirmSponsorship(aliceKeyring, 10)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.confirmSponsorship', [collectionId],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');
+ }
+
+ /**
+ * Removes the sponsor of a collection, regardless if it consented or not.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @example removeSponsor(aliceKeyring, 10)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.removeCollectionSponsor', [collectionId],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');
+ }
+
+ /**
+ * Sets the limits of the collection. At least one limit must be specified for a correct call.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param limits collection limits object
+ * @example
+ * await setLimits(
+ * aliceKeyring,
+ * 10,
+ * {
+ * sponsorTransferTimeout: 0,
+ * ownerCanDestroy: false
+ * }
+ * )
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setCollectionLimits', [collectionId, limits],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');
+ }
+
+ /**
+ * Changes the owner of the collection to the new Substrate address.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param ownerAddress substrate address of new owner
+ * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');
+ }
+
+ /**
+ * Adds a collection administrator.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param adminAddressObj Administrator address (substrate or ethereum)
+ * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');
+ }
+
+ /**
+ * Removes a collection administrator.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param adminAddressObj Administrator address (substrate or ethereum)
+ * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');
+ }
+
+ /**
+ * Check if user is in allow list.
+ *
+ * @param collectionId ID of collection
+ * @param user Account to check
+ * @example await getAdmins(1)
+ * @returns is user in allow list
+ */
+ async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {
+ return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();
+ }
+
+ /**
+ * Adds an address to allow list
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param addressObj address to add to the allow list
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.addToAllowList', [collectionId, addressObj],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');
+ }
+
+ /**
+ * Removes an address from allow list
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param addressObj address to remove from the allow list
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');
+ }
+
+ /**
+ * Sets onchain permissions for selected collection.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param permissions collection permissions object
+ * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setCollectionPermissions', [collectionId, permissions],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');
+ }
+
+ /**
+ * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param permissions nesting permissions object
+ * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {
+ return await this.setPermissions(signer, collectionId, {nesting: permissions});
+ }
+
+ /**
+ * Disables nesting for selected collection.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @example disableNesting(aliceKeyring, 10);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {
+ return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});
+ }
+
+ /**
+ * Sets onchain properties to the collection.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param properties array of property objects
+ * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setCollectionProperties', [collectionId, properties],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');
+ }
+
+ /**
+ * Get collection properties.
+ *
+ * @param collectionId ID of collection
+ * @param propertyKeys optionally filter the returned properties to only these keys
+ * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);
+ * @returns array of key-value pairs
+ */
+ async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {
+ return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();
+ }
+
+ async getPropertiesConsumedSpace(collectionId: number): Promise<number> {
+ const api = this.helper.getApi();
+ const props = (await api.query.common.collectionProperties(collectionId)).toJSON();
+
+ return (props! as any).consumedSpace;
+ }
+
+ async getCollectionOptions(collectionId: number) {
+ return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();
+ }
+
+ /**
+ * Deletes onchain properties from the collection.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param propertyKeys array of property keys to delete
+ * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');
+ }
+
+ /**
+ * Changes the owner of the token.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param addressObj address of a new owner
+ * @param amount amount of tokens to be transfered. For NFT must be set to 1n
+ * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @returns true if the token success, otherwise false
+ */
+ async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],
+ true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,
+ );
+
+ return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);
+ }
+
+ /**
+ *
+ * Change ownership of a token(s) on behalf of the owner.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param fromAddressObj address on behalf of which the token will be sent
+ * @param toAddressObj new token owner
+ * @param amount amount of tokens to be transfered. For NFT must be set to 1n
+ * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})
+ * @returns true if the token success, otherwise false
+ */
+ async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],
+ true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,
+ );
+ return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
+ }
+
+ /**
+ *
+ * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param amount amount of tokens to be burned. For NFT must be set to 1n
+ * @example burnToken(aliceKeyring, 10, 5);
+ * @returns ```true``` if the extrinsic is successful, otherwise ```false```
+ */
+ async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {
+ const burnResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.burnItem', [collectionId, tokenId, amount],
+ true, // `Unable to burn token for ${label}`,
+ );
+ const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);
+ if(burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');
+ return burnedTokens.success;
+ }
+
+ /**
+ * Destroys a concrete instance of NFT on behalf of the owner
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param fromAddressObj address on behalf of which the token will be burnt
+ * @param amount amount of tokens to be burned. For NFT must be set to 1n
+ * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ const burnResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],
+ true, // `Unable to burn token from for ${label}`,
+ );
+ const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);
+ return burnedTokens.success && burnedTokens.tokens.length > 0;
+ }
+
+ /**
+ * Set, change, or remove approved address to transfer the ownership of the NFT.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
+ * @param amount amount of token to be approved. For NFT must be set to 1n
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ const approveResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],
+ true, // `Unable to approve token for ${label}`,
+ );
+
+ return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');
+ }
+
+ /**
+ * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param fromAddressObj Signer's Ethereum address containing her tokens
+ * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
+ * @param amount amount of token to be approved. For NFT must be set to 1n
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async approveTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
+ const approveResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.approveFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],
+ true, // `Unable to approve token for ${label}`,
+ );
+
+ return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');
+ }
+
+ /**
+ * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
+ * @param amount amount of token to be approved. For NFT must be set to 1n
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async approveTokenFromEth(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ const ethMirror = CrossAccountId.fromKeyring(signer).toEthereum().toICrossAccountId();
+ return await this.approveTokenFrom(signer, collectionId, tokenId, ethMirror, toAddressObj, amount);
+ }
+
+ /**
+ * Get the amount of token pieces approved to transfer or burn. Normally 0.
+ *
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param toAccountObj address which is approved to use token pieces
+ * @param fromAccountObj address which may have allowed the use of its owned tokens
+ * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})
+ * @returns number of approved to transfer pieces
+ */
+ async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();
+ }
+
+ /**
+ * Get the last created token ID in a collection
+ *
+ * @param collectionId ID of collection
+ * @example getLastTokenId(10);
+ * @returns id of the last created token
+ */
+ async getLastTokenId(collectionId: number): Promise<number> {
+ return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();
+ }
+
+ /**
+ * Check if token exists
+ *
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @example doesTokenExist(10, 20);
+ * @returns true if the token exists, otherwise false
+ */
+ async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {
+ return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();
+ }
+}
+
+class NFTnRFT extends CollectionGroup {
+ /**
+ * Get tokens owned by account
+ *
+ * @param collectionId ID of collection
+ * @param addressObj tokens owner
+ * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @returns array of token ids owned by account
+ */
+ async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {
+ return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();
+ }
+
+ /**
+ * Get token data
+ *
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param propertyKeys optionally filter the token properties to only these keys
+ * @param blockHashAt optionally query the data at some block with this hash
+ * @example getToken(10, 5);
+ * @returns human readable token data
+ */
+ async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{
+ properties: IProperty[];
+ owner: ICrossAccountId;
+ normalizedOwner: ICrossAccountId;
+ } | null> {
+ let args;
+ if(typeof blockHashAt === 'undefined') {
+ args = [collectionId, tokenId];
+ }
+ else {
+ if(propertyKeys.length == 0) {
+ const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();
+ if(!collection) return null;
+ propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);
+ }
+ args = [collectionId, tokenId, propertyKeys, blockHashAt];
+ }
+ const tokenData = (await this.helper.callRpc('api.rpc.unique.tokenData', args)).toHuman();
+ if(tokenData === null || tokenData.owner === null) return null;
+ tokenData.normalizedOwner = CrossAccountId.withNormalizedSubstrate(tokenData.owner);
+ return tokenData;
+ }
+
+ /**
+ * Get token's owner
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param blockHashAt optionally query the data at the block with this hash
+ * @example getTokenOwner(10, 5);
+ * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}
+ */
+ async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId> {
+ let owner;
+ if(typeof blockHashAt === 'undefined') {
+ owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);
+ } else {
+ owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);
+ }
+ return CrossAccountId.fromLowerCaseKeys(owner.toJSON()).toICrossAccountId();
+ }
+
+ /**
+ * Recursively find the address that owns the token
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param blockHashAt
+ * @example getTokenTopmostOwner(10, 5);
+ * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}
+ */
+ async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId | null> {
+ let owner;
+ if(typeof blockHashAt === 'undefined') {
+ owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);
+ } else {
+ owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);
+ }
+
+ if(owner === null) return null;
+
+ return owner.toHuman();
+ }
+
+ /**
+ * Nest one token into another
+ * @param signer keyring of signer
+ * @param tokenObj token to be nested
+ * @param rootTokenObj token to be parent
+ * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {
+ const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
+ const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);
+ if(!result) {
+ throw Error('Unable to nest token!');
+ }
+ return result;
+ }
+
+ /**
+ * Remove token from nested state
+ * @param signer keyring of signer
+ * @param tokenObj token to unnest
+ * @param rootTokenObj parent of a token
+ * @param toAddressObj address of a new token owner
+ * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {
+ const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
+ const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);
+ if(!result) {
+ throw Error('Unable to unnest token!');
+ }
+ return result;
+ }
+
+ /**
+ * Set permissions to change token properties
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param permissions permissions to change a property by the collection admin or token owner
+ * @example setTokenPropertyPermissions(
+ * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]
+ * )
+ * @returns true if extrinsic success otherwise false
+ */
+ async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');
+ }
+
+ /**
+ * Get token property permissions.
+ *
+ * @param collectionId ID of collection
+ * @param propertyKeys optionally filter the returned property permissions to only these keys
+ * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);
+ * @returns array of key-permission pairs
+ */
+ async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {
+ return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();
+ }
+
+ /**
+ * Set token properties
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection
+ * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');
+ }
+
+ /**
+ * Get properties, metadata assigned to a token.
+ *
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param propertyKeys optionally filter the returned properties to only these keys
+ * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);
+ * @returns array of key-value pairs
+ */
+ async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {
+ return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();
+ }
+
+ /**
+ * Delete the provided properties of a token
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param propertyKeys property keys to be deleted
+ * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');
+ }
+
+ /**
+ * Mint new collection
+ *
+ * @param signer keyring of signer
+ * @param collectionOptions basic collection options and properties
+ * @param mode NFT or RFT type of a collection
+ * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")
+ * @returns object of the created collection
+ */
+ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {
+ collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
+ collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};
+ for(const key of ['name', 'description', 'tokenPrefix']) {
+ if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);
+ }
+
+ let flags = 0;
+ // convert CollectionFlags to number and join them in one number
+ if(collectionOptions.flags) {
+ for(let i = 0; i < collectionOptions.flags.length; i++){
+ const flag = collectionOptions.flags[i];
+ flags = flags | flag;
+ }
+ }
+ collectionOptions.flags = [flags];
+
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createCollectionEx', [collectionOptions],
+ true, // errorLabel,
+ );
+ return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
+ }
+
+ getCollectionObject(_collectionId: number): any {
+ return null;
+ }
+
+ getTokenObject(_collectionId: number, _tokenId: number): any {
+ return null;
+ }
+
+ /**
+ * Tells whether the given `owner` approves the `operator`.
+ * @param collectionId ID of collection
+ * @param owner owner address
+ * @param operator operator addrees
+ * @returns true if operator is enabled
+ */
+ async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {
+ return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();
+ }
+
+ /** Sets or unsets the approval of a given operator.
+ * The `operator` is allowed to transfer all tokens of the `caller` on their behalf.
+ * @param operator Operator
+ * @param approved Should operator status be granted or revoked?
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],
+ true,
+ );
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');
+ }
+}
+
+
+class NFTGroup extends NFTnRFT {
+ /**
+ * Get collection object
+ * @param collectionId ID of collection
+ * @example getCollectionObject(2);
+ * @returns instance of UniqueNFTCollection
+ */
+ override getCollectionObject(collectionId: number): UniqueNFTCollection {
+ return new UniqueNFTCollection(collectionId, this.helper);
+ }
+
+ /**
+ * Get token object
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @example getTokenObject(10, 5);
+ * @returns instance of UniqueNFTToken
+ */
+ override getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {
+ return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));
+ }
+
+ /**
+ * Is token approved to transfer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param toAccountObj address to be approved
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {
+ return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, (await this.getTokenOwner(collectionId, tokenId)))) === 1n;
+ }
+
+ /**
+ * Changes the owner of the token.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param addressObj address of a new owner
+ * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {
+ return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);
+ }
+
+ /**
+ *
+ * Change ownership of a NFT on behalf of the owner.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param fromAddressObj address on behalf of which the token will be sent
+ * @param toAddressObj new token owner
+ * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {
+ return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);
+ }
+
+ /**
+ * Get tokens nested in the provided token
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param blockHashAt optionally query the data at the block with this hash
+ * @example getTokenChildren(10, 5);
+ * @returns tokens whose depth of nesting is <= 5
+ */
+ async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {
+ let children;
+ if(typeof blockHashAt === 'undefined') {
+ children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);
+ } else {
+ children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);
+ }
+
+ return children.toJSON().map((x: any) => ({collectionId: x.collection, tokenId: x.token}));
+ }
+
+ /**
+ * Mint new collection
+ * @param signer keyring of signer
+ * @param collectionOptions Collection options
+ * @example
+ * mintCollection(aliceKeyring, {
+ * name: 'New',
+ * description: 'New collection',
+ * tokenPrefix: 'NEW',
+ * })
+ * @returns object of the created collection
+ */
+ override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {
+ return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;
+ }
+
+ /**
+ * Mint new token
+ * @param signer keyring of signer
+ * @param data token data
+ * @returns created token object
+ */
+ async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
+ NFT: {
+ properties: data.properties,
+ },
+ }],
+ true,
+ );
+ const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);
+ if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');
+ if(createdTokens.tokens.length < 1) throw Error('No tokens minted');
+ return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
+ }
+
+ /**
+ * Mint multiple NFT tokens
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokens array of tokens with owner and properties
+ * @example
+ * mintMultipleTokens(aliceKeyring, 10, [{
+ * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},
+ * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],
+ * },{
+ * owner: {Ethereum: "0x9F0583DbB855d..."},
+ * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],
+ * }]);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],
+ true,
+ );
+ const collection = this.getCollectionObject(collectionId);
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ }
+
+ /**
+ * Mint multiple NFT tokens with one owner
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param owner tokens owner
+ * @param tokens array of tokens with owner and properties
+ * @example
+ * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{
+ * properties: [{
+ * key: "gender",
+ * value: "female",
+ * },{
+ * key: "age",
+ * value: "33",
+ * }],
+ * }]);
+ * @returns array of newly created tokens
+ */
+ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {
+ const rawTokens = [];
+ for(const token of tokens) {
+ const raw = {NFT: {properties: token.properties}};
+ rawTokens.push(raw);
+ }
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
+ true,
+ );
+ const collection = this.getCollectionObject(collectionId);
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ }
+
+ /**
+ * Set, change, or remove approved address to transfer the ownership of the NFT.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param toAddressObj address to approve
+ * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);
+ }
+}
+
+
+class RFTGroup extends NFTnRFT {
+ /**
+ * Get collection object
+ * @param collectionId ID of collection
+ * @example getCollectionObject(2);
+ * @returns instance of UniqueRFTCollection
+ */
+ override getCollectionObject(collectionId: number): UniqueRFTCollection {
+ return new UniqueRFTCollection(collectionId, this.helper);
+ }
+
+ /**
+ * Get token object
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @example getTokenObject(10, 5);
+ * @returns instance of UniqueNFTToken
+ */
+ override getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {
+ return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));
+ }
+
+ /**
+ * Get top 10 token owners with the largest number of pieces
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @example getTokenTop10Owners(10, 5);
+ * @returns array of top 10 owners
+ */
+ async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<ICrossAccountId[]> {
+ return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map((a: CrossAccountId) => a.toICrossAccountId());
+ }
+
+ /**
+ * Get number of pieces owned by address
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param addressObj address token owner
+ * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});
+ * @returns number of pieces ownerd by address
+ */
+ async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();
+ }
+
+ /**
+ * Transfer pieces of token to another address
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param addressObj address of a new owner
+ * @param amount number of pieces to be transfered
+ * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);
+ }
+
+ /**
+ * Change ownership of some pieces of RFT on behalf of the owner.
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param fromAddressObj address on behalf of which the token will be sent
+ * @param toAddressObj new token owner
+ * @param amount number of pieces to be transfered
+ * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
+ }
+
+ /**
+ * Mint new collection
+ * @param signer keyring of signer
+ * @param collectionOptions Collection options
+ * @example
+ * mintCollection(aliceKeyring, {
+ * name: 'New',
+ * description: 'New collection',
+ * tokenPrefix: 'NEW',
+ * })
+ * @returns object of the created collection
+ */
+ override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {
+ return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;
+ }
+
+ /**
+ * Mint new token
+ * @param signer keyring of signer
+ * @param data token data
+ * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});
+ * @returns created token object
+ */
+ async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
+ ReFungible: {
+ pieces: data.pieces,
+ properties: data.properties,
+ },
+ }],
+ true,
+ );
+ const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);
+ if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');
+ if(createdTokens.tokens.length < 1) throw Error('No tokens minted');
+ return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
+ }
+
+ mintMultipleTokens(_signer: TSigner, _collectionId: number, _tokens: { owner: ICrossAccountId, pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {
+ throw Error('Not implemented');
+ // const creationResult = await this.helper.executeExtrinsic(
+ // signer,
+ // 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],
+ // true, // `Unable to mint RFT tokens for ${label}`,
+ // );
+ // const collection = this.getCollectionObject(collectionId);
+ // return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ }
+
+ /**
+ * Mint multiple RFT tokens with one owner
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param owner tokens owner
+ * @param tokens array of tokens with properties and pieces
+ * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);
+ * @returns array of newly created RFT tokens
+ */
+ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {
+ const rawTokens = [];
+ for(const token of tokens) {
+ const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};
+ rawTokens.push(raw);
+ }
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
+ true,
+ );
+ const collection = this.getCollectionObject(collectionId);
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ }
+
+ /**
+ * Destroys a concrete instance of RFT.
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param amount number of pieces to be burnt
+ * @example burnToken(aliceKeyring, 10, 5);
+ * @returns ```true``` if the extrinsic is successful, otherwise ```false```
+ */
+ override async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {
+ return await super.burnToken(signer, collectionId, tokenId, amount);
+ }
+
+ /**
+ * Destroys a concrete instance of RFT on behalf of the owner.
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param fromAddressObj address on behalf of which the token will be burnt
+ * @param amount number of pieces to be burnt
+ * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ override async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);
+ }
+
+ /**
+ * Set, change, or remove approved address to transfer the ownership of the RFT.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param toAddressObj address to approve
+ * @param amount number of pieces to be approved
+ * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);
+ * @returns true if the token success, otherwise false
+ */
+ override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);
+ }
+
+ /**
+ * Get total number of pieces
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @example getTokenTotalPieces(10, 5);
+ * @returns number of pieces
+ */
+ async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();
+ }
+
+ /**
+ * Change number of token pieces. Signer must be the owner of all token pieces.
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param tokenId ID of token
+ * @param amount new number of pieces
+ * @example repartitionToken(aliceKeyring, 10, 5, 12345n);
+ * @returns true if the repartion was success, otherwise false
+ */
+ async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {
+ const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);
+ const repartitionResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.repartition', [collectionId, tokenId, amount],
+ true,
+ );
+ if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');
+ return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');
+ }
+}
+
+
+class FTGroup extends CollectionGroup {
+ /**
+ * Get collection object
+ * @param collectionId ID of collection
+ * @example getCollectionObject(2);
+ * @returns instance of UniqueFTCollection
+ */
+ getCollectionObject(collectionId: number): UniqueFTCollection {
+ return new UniqueFTCollection(collectionId, this.helper);
+ }
+
+ /**
+ * Mint new fungible collection
+ * @param signer keyring of signer
+ * @param collectionOptions Collection options
+ * @param decimalPoints number of token decimals
+ * @example
+ * mintCollection(aliceKeyring, {
+ * name: 'New',
+ * description: 'New collection',
+ * tokenPrefix: 'NEW',
+ * }, 18)
+ * @returns newly created fungible collection
+ */
+ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {
+ collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
+ if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');
+ collectionOptions.mode = {fungible: decimalPoints};
+ for(const key of ['name', 'description', 'tokenPrefix']) {
+ if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);
+ }
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createCollectionEx', [collectionOptions],
+ true,
+ );
+ return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
+ }
+
+ /**
+ * Mint tokens
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param owner address owner of new tokens
+ * @param amount amount of tokens to be meanted
+ * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {
+ Fungible: {
+ value: amount,
+ },
+ }],
+ true, // `Unable to mint fungible tokens for ${label}`,
+ );
+ return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
+ }
+
+ /**
+ * Mint multiple Fungible tokens with one owner
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param owner tokens owner
+ * @param tokens array of tokens with properties and pieces
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: { value: bigint }[], owner: ICrossAccountId): Promise<boolean> {
+ const rawTokens = [];
+ for(const token of tokens) {
+ const raw = {Fungible: {Value: token.value}};
+ rawTokens.push(raw);
+ }
+ const creationResult = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
+ true,
+ );
+ return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
+ }
+
+ /**
+ * Get the top 10 owners with the largest balance for the Fungible collection
+ * @param collectionId ID of collection
+ * @example getTop10Owners(10);
+ * @returns array of ```ICrossAccountId```
+ */
+ async getTop10Owners(collectionId: number): Promise<ICrossAccountId[]> {
+ return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map((a: CrossAccountId) => a.toICrossAccountId());
+ }
+
+ /**
+ * Get account balance
+ * @param collectionId ID of collection
+ * @param addressObj address of owner
+ * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})
+ * @returns amount of fungible tokens owned by address
+ */
+ async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();
+ }
+
+ /**
+ * Transfer tokens to address
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param toAddressObj address recipient
+ * @param amount amount of tokens to be sent
+ * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);
+ }
+
+ /**
+ * Transfer some tokens on behalf of the owner.
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param fromAddressObj address on behalf of which tokens will be sent
+ * @param toAddressObj address where token to be sent
+ * @param amount number of tokens to be sent
+ * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);
+ }
+
+ /**
+ * Destroy some amount of tokens
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param amount amount of tokens to be destroyed
+ * @example burnTokens(aliceKeyring, 10, 1000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async burnTokens(signer: IKeyringPair, collectionId: number, amount = 1n): Promise<boolean> {
+ return await super.burnToken(signer, collectionId, 0, amount);
+ }
+
+ /**
+ * Burn some tokens on behalf of the owner.
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param fromAddressObj address on behalf of which tokens will be burnt
+ * @param amount amount of tokens to be burnt
+ * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {
+ return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);
+ }
+
+ /**
+ * Get total collection supply
+ * @param collectionId
+ * @returns
+ */
+ async getTotalPieces(collectionId: number): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();
+ }
+
+ /**
+ * Set, change, or remove approved address to transfer tokens.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @param toAddressObj address to be approved
+ * @param amount amount of tokens to be approved
+ * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ return super.approveToken(signer, collectionId, 0, toAddressObj, amount);
+ }
+
+ /**
+ * Get amount of fungible tokens approved to transfer
+ * @param collectionId ID of collection
+ * @param fromAddressObj owner of tokens
+ * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner
+ * @returns number of tokens approved for the transfer
+ */
+ getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+ return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);
+ }
+}
+
+
+class ChainGroup extends HelperGroup<ChainHelperBase> {
+ /**
+ * Get system properties of a chain
+ * @example getChainProperties();
+ * @returns ss58Format, token decimals, and token symbol
+ */
+ getChainProperties(): IChainProperties {
+ const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();
+ return {
+ ss58Format: properties.ss58Format.toJSON(),
+ tokenDecimals: properties.tokenDecimals.toJSON(),
+ tokenSymbol: properties.tokenSymbol.toJSON(),
+ };
+ }
+
+ /**
+ * Get chain header
+ * @example getLatestBlockNumber();
+ * @returns the number of the last block
+ */
+ async getLatestBlockNumber(): Promise<number> {
+ return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();
+ }
+
+ /**
+ * Get block hash by block number
+ * @param blockNumber number of block
+ * @example getBlockHashByNumber(12345);
+ * @returns hash of a block
+ */
+ async getBlockHashByNumber(blockNumber: number): Promise<string | null> {
+ const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();
+ if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;
+ return blockHash;
+ }
+
+ // TODO add docs
+ async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {
+ const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);
+ if(!blockHash) return null;
+ return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;
+ }
+
+ /**
+ * Get latest relay block
+ * @returns {number} relay block
+ */
+ async getRelayBlockNumber(): Promise<bigint> {
+ const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;
+ return BigInt(blockNumber);
+ }
+
+ /**
+ * Get account nonce
+ * @param address substrate address
+ * @example getNonce("5GrwvaEF5zXb26Fz...");
+ * @returns number, account's nonce
+ */
+ async getNonce(address: TSubstrateAccount): Promise<number> {
+ return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();
+ }
+}
+
+export class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ /**
+ * Get substrate address balance
+ * @param address substrate address
+ * @example getSubstrate("5GrwvaEF5zXb26Fz...")
+ * @returns amount of tokens on address
+ */
+ async getSubstrate(address: TSubstrateAccount): Promise<bigint> {
+ return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();
+ }
+
+ /**
+ * Transfer tokens to substrate address
+ * @param signer keyring of signer
+ * @param address substrate address of a recipient
+ * @param amount amount of tokens to be transfered
+ * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);
+
+ let transfer = {from: null, to: null, amount: 0n} as any;
+ result.result.events.forEach(({event: {data, method, section}}: any) => {
+ if((section === 'balances') && (method === 'Transfer')) {
+ transfer = {
+ from: this.helper.address.normalizeSubstrate(data[0]),
+ to: this.helper.address.normalizeSubstrate(data[1]),
+ amount: BigInt(data[2]),
+ };
+ }
+ });
+ const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from
+ && this.helper.address.normalizeSubstrate(address) === transfer.to
+ && BigInt(amount) === transfer.amount;
+ return isSuccess;
+ }
+
+ /**
+ * Get full substrate balance including free, frozen, and reserved
+ * @param address substrate address
+ * @returns
+ */
+ async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {
+ const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;
+ return {free: accountInfo.free.toBigInt(), frozen: accountInfo.frozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};
+ }
+
+ /**
+ * Get total issuance
+ * @returns
+ */
+ async getTotalIssuance(): Promise<bigint> {
+ const total = (await this.helper.callRpc('api.query.balances.totalIssuance', []));
+ return total.toBigInt();
+ }
+
+ async getLocked(address: TSubstrateAccount): Promise<{ id: string, amount: bigint, reason: string }[]> {
+ const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();
+ return locks.map((lock: any) => ({id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons}));
+ }
+ async getFrozen(address: TSubstrateAccount): Promise<{ id: string, amount: bigint }[]> {
+ const locks = (await this.helper.api!.query.balances.freezes(address)) as unknown as Array<any>;
+ return locks.map(lock => ({id: lock.id.toUtf8(), amount: lock.amount.toBigInt()}));
+ }
+}
+
+export class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ /**
+ * Get ethereum address balance
+ * @param address ethereum address
+ * @example getEthereum("0x9F0583DbB855d...")
+ * @returns amount of tokens on address
+ */
+ async getEthereum(address: TEthereumAccount): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();
+ }
+
+ /**
+ * Transfer tokens to address
+ * @param signer keyring of signer
+ * @param address Ethereum address of a recipient
+ * @param amount amount of tokens to be transfered
+ * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);
+
+ let transfer = {from: null, to: null, amount: 0n} as any;
+ result.result.events.forEach(({event: {data, method, section}}: any) => {
+ if((section === 'balances') && (method === 'Transfer')) {
+ transfer = {
+ from: data[0].toString(),
+ to: data[1].toString(),
+ amount: BigInt(data[2]),
+ };
+ }
+ });
+ const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from
+ && address === transfer.to
+ && BigInt(amount) === transfer.amount;
+ return isSuccess;
+ }
+}
+
+class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ subBalanceGroup: SubstrateBalanceGroup<T>;
+ ethBalanceGroup: EthereumBalanceGroup<T>;
+
+ constructor(helper: T) {
+ super(helper);
+ this.subBalanceGroup = new SubstrateBalanceGroup(helper);
+ this.ethBalanceGroup = new EthereumBalanceGroup(helper);
+ }
+
+ getCollectionCreationPrice(): bigint {
+ return 2n * this.getOneTokenNominal();
+ }
+ /**
+ * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).
+ * @example getOneTokenNominal()
+ * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.
+ */
+ getOneTokenNominal(): bigint {
+ const chainProperties = this.helper.chain.getChainProperties();
+ return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);
+ }
+
+ /**
+ * Get substrate address balance
+ * @param address substrate address
+ * @example getSubstrate("5GrwvaEF5zXb26Fz...")
+ * @returns amount of tokens on address
+ */
+ getSubstrate(address: TSubstrateAccount): Promise<bigint> {
+ return this.subBalanceGroup.getSubstrate(address);
+ }
+
+ /**
+ * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved
+ * @param address substrate address
+ * @returns
+ */
+ getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {
+ return this.subBalanceGroup.getSubstrateFull(address);
+ }
+
+ /**
+ * Get total issuance
+ * @returns
+ */
+ getTotalIssuance(): Promise<bigint> {
+ return this.subBalanceGroup.getTotalIssuance();
+ }
+
+ /**
+ * Get locked balances
+ * @param address substrate address
+ * @returns locked balances with reason via api.query.balances.locks
+ * @deprecated all the methods should switch to getFrozen
+ */
+ getLocked(address: TSubstrateAccount) {
+ return this.subBalanceGroup.getLocked(address);
+ }
+
+ /**
+ * Get frozen balances
+ * @param address substrate address
+ * @returns frozen balances with id via api.query.balances.freezes
+ */
+ getFrozen(address: TSubstrateAccount) {
+ return this.subBalanceGroup.getFrozen(address);
+ }
+
+ /**
+ * Get ethereum address balance
+ * @param address ethereum address
+ * @example getEthereum("0x9F0583DbB855d...")
+ * @returns amount of tokens on address
+ */
+ getEthereum(address: TEthereumAccount): Promise<bigint> {
+ return this.ethBalanceGroup.getEthereum(address);
+ }
+
+ async setBalanceSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceSetBalance', [address, amount], true);
+ }
+
+ /**
+ * Transfer tokens to substrate address
+ * @param signer keyring of signer
+ * @param address substrate address of a recipient
+ * @param amount amount of tokens to be transfered
+ * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
+ return this.subBalanceGroup.transferToSubstrate(signer, address, amount);
+ }
+
+ async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);
+
+ let transfer = {from: null, to: null, amount: 0n} as any;
+ result.result.events.forEach(({event: {data, method, section}}: any) => {
+ if((section === 'balances') && (method === 'Transfer')) {
+ transfer = {
+ from: this.helper.address.normalizeSubstrate(data[0]),
+ to: this.helper.address.normalizeSubstrate(data[1]),
+ amount: BigInt(data[2]),
+ };
+ }
+ });
+ let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;
+ isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;
+ isSuccess = isSuccess && BigInt(amount) === transfer.amount;
+ return isSuccess;
+ }
+
+ /**
+ * Transfer tokens with the unlock period
+ * @param signer signers Keyring
+ * @param address Substrate address of recipient
+ * @param schedule Schedule params
+ * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 5000
+ */
+ async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: { start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }): Promise<void> {
+ const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);
+ const event = result.result.events
+ .find((e: any) => e.event.section === 'vesting' &&
+ e.event.method === 'VestingScheduleAdded' &&
+ e.event.data[0].toHuman() === signer.address);
+ if(!event) throw Error('Cannot find transfer in events');
+ }
+
+ /**
+ * Get schedule for recepient of vested transfer
+ * @param address Substrate address of recipient
+ * @returns
+ */
+ async getVestingSchedules(address: TSubstrateAccount): Promise<{ start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }[]> {
+ const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();
+ return schedule.map((schedule: any) => ({
+ start: BigInt(schedule.start),
+ period: BigInt(schedule.period),
+ periodCount: BigInt(schedule.periodCount),
+ perPeriod: BigInt(schedule.perPeriod),
+ }));
+ }
+
+ /**
+ * Claim vested tokens
+ * @param signer signers Keyring
+ */
+ async claim(signer: TSigner) {
+ const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);
+ const event = result.result.events
+ .find((e: any) => e.event.section === 'vesting' &&
+ e.event.method === 'Claimed' &&
+ e.event.data[0].toHuman() === signer.address);
+ if(!event) throw Error('Cannot find claim in events');
+ }
+}
+
+class AddressGroup extends HelperGroup<ChainHelperBase> {
+ /**
+ * Normalizes the address to the specified ss58 format, by default ```42```.
+ * @param address substrate address
+ * @param ss58Format format for address conversion, by default ```42```
+ * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
+ * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation
+ */
+ normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {
+ return CrossAccountId.normalizeSubstrateAddress({Substrate: address}, ss58Format);
+ }
+
+ /**
+ * Get address in the connected chain format
+ * @param address substrate address
+ * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network
+ * @returns address in chain format
+ */
+ normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {
+ return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);
+ }
+
+ /**
+ * Get substrate mirror of an ethereum address
+ * @param ethAddress ethereum address
+ * @param toChainFormat false for normalized account
+ * @example ethToSubstrate('0x9F0583DbB855d...')
+ * @returns substrate mirror of a provided ethereum address
+ */
+ ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat = false): TSubstrateAccount {
+ return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);
+ }
+
+ /**
+ * Get ethereum mirror of a substrate address
+ * @param subAddress substrate account
+ * @example substrateToEth("5DnSF6RRjwteE3BrC...")
+ * @returns ethereum mirror of a provided substrate address
+ */
+ substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {
+ return CrossAccountId.translateSubToEth(subAddress);
+ }
+
+ /**
+ * Encode key to substrate address
+ * @param key key for encoding address
+ * @param ss58Format prefix for encoding to the address of the corresponding network
+ * @returns encoded substrate address
+ */
+ encodeSubstrateAddress(key: Uint8Array | string | bigint, ss58Format = 42): string {
+ const u8a: Uint8Array = typeof key === 'string'
+ ? hexToU8a(key)
+ : typeof key === 'bigint'
+ ? hexToU8a(key.toString(16))
+ : key;
+
+ if(ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {
+ throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);
+ }
+
+ const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];
+ if(!allowedDecodedLengths.includes(u8a.length)) {
+ throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);
+ }
+
+ const u8aPrefix = ss58Format < 64
+ ? new Uint8Array([ss58Format])
+ : new Uint8Array([
+ ((ss58Format & 0xfc) >> 2) | 0x40,
+ (ss58Format >> 8) | ((ss58Format & 0x03) << 6),
+ ]);
+
+ const input = u8aConcat(u8aPrefix, u8a);
+
+ return base58Encode(u8aConcat(
+ input,
+ blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),
+ ));
+ }
+
+ /**
+ * Restore substrate address from bigint representation
+ * @param number decimal representation of substrate address
+ * @returns substrate address
+ */
+ restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {
+ if(this.helper.api === null) {
+ throw 'Not connected';
+ }
+ const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();
+ if(res === undefined || res === null) {
+ throw 'Restore address error';
+ }
+ return res.toString();
+ }
+
+ /**
+ * Convert etherium cross account id to substrate cross account id
+ * @param ethCrossAccount etherium cross account
+ * @returns substrate cross account id
+ */
+ convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {
+ if(ethCrossAccount.sub === '0') {
+ return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};
+ }
+
+ const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));
+ return {Substrate: ss58};
+ }
+
+ paraSiblingSovereignAccount(paraid: number) {
+ // We are getting a *sibling* parachain sovereign account,
+ // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c
+ const siblingPrefix = '0x7369626c';
+
+ const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);
+ const suffix = '000000000000000000000000000000000000000000000000';
+
+ return siblingPrefix + encodedParaId + suffix;
+ }
+}
+
+
+class StakingGroup extends HelperGroup<UniqueHelper> {
+ /**
+ * Stake tokens for App Promotion
+ * @param signer keyring of signer
+ * @param amountToStake amount of tokens to stake
+ * @param label extra label for log
+ * @returns
+ */
+ async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {
+ if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;
+ await this.helper.executeExtrinsic(
+ signer, 'api.tx.appPromotion.stake',
+ [amountToStake], true,
+ );
+ // TODO extract info from stakeResult
+ return true;
+ }
+
+ /**
+ * Unstake all staked tokens
+ * @param signer keyring of signer
+ * @param amountToUnstake amount of tokens to unstake
+ * @param label extra label for log
+ * @returns block hash where unstake happened
+ */
+ async unstakeAll(signer: TSigner, label?: string): Promise<string> {
+ if(typeof label === 'undefined') label = `${signer.address}`;
+ const unstakeResult = await this.helper.executeExtrinsic(
+ signer, 'api.tx.appPromotion.unstakeAll',
+ [], true,
+ );
+ return unstakeResult.blockHash;
+ }
+
+ /**
+ * Unstake the part of a staked tokens
+ * @param signer keyring of signer
+ * @param amount amount of tokens to unstake
+ * @param label extra label for log
+ * @returns block hash where unstake happened
+ */
+ async unstakePartial(signer: TSigner, amount: bigint, label?: string): Promise<string> {
+ if(typeof label === 'undefined') label = `${signer.address}`;
+ const unstakeResult = await this.helper.executeExtrinsic(
+ signer, 'api.tx.appPromotion.unstakePartial',
+ [amount], true,
+ );
+ return unstakeResult.blockHash;
+ }
+
+ /**
+ * Get total number of active stakes
+ * @param address substrate address
+ * @returns {number}
+ */
+ async getStakesNumber(address: ICrossAccountId): Promise<number> {
+ if('Ethereum' in address) throw Error('only substrate address');
+ return (await this.helper.callRpc('api.query.appPromotion.stakesPerAccount', [address.Substrate])).toNumber();
+ }
+
+ /**
+ * Get total staked amount for address
+ * @param address substrate or ethereum address
+ * @returns total staked amount
+ */
+ async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {
+ if(address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();
+ return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();
+ }
+
+ /**
+ * Get total staked per block
+ * @param address substrate or ethereum address
+ * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block
+ */
+ async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
+ const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);
+ return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => ({
+ block: block.toBigInt(),
+ amount: amount.toBigInt(),
+ }));
+ }
+
+ /**
+ * Get total pending unstake amount for address
+ * @param address substrate or ethereum address
+ * @returns total pending unstake amount
+ */
+ async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();
+ }
+
+ /**
+ * Get pending unstake amount per block for address
+ * @param address substrate or ethereum address
+ * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block
+ */
+ async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
+ const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);
+ const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => ({
+ block: block.toBigInt(),
+ amount: amount.toBigInt(),
+ }));
+ return result;
+ }
+}
+
+
+class PreimageGroup extends HelperGroup<UniqueHelper> {
+ async getPreimageInfo(h256: string) {
+ return (await this.helper.callRpc('api.query.preimage.statusFor', [h256])).toJSON();
+ }
+
+ /**
+ * Create a preimage from an API call.
+ * @param signer keyring of the signer.
+ * @param call an extrinsic call
+ * @example await notePreimageFromCall(preimageMaker,
+ * helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd])
+ * );
+ * @returns promise of extrinsic execution.
+ */
+ notePreimageFromCall(signer: TSigner, call: any, returnPreimageHash = false) {
+ return this.notePreimage(signer, call.method.toHex(), returnPreimageHash);
+ }
+
+ /**
+ * Create a preimage with a hex or a byte array.
+ * @param signer keyring of the signer.
+ * @param bytes preimage encoded in hex or a byte array, e.g. an extrinsic call.
+ * @example await notePreimage(preimageMaker,
+ * helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex()
+ * );
+ * @returns promise of extrinsic execution.
+ */
+ async notePreimage(signer: TSigner, bytes: string | Uint8Array, returnPreimageHash = false) {
+ const promise = this.helper.executeExtrinsic(signer, 'api.tx.preimage.notePreimage', [bytes]);
+ if(returnPreimageHash) {
+ const result = await promise;
+ const events = result.result.events.filter((x: any) => x.event.method === 'Noted' && x.event.section === 'preimage');
+ const preimageHash = events[0].event.data[0].toHuman();
+ return preimageHash;
+ }
+ return promise;
+ }
+
+ /**
+ * Delete an existing preimage and return the deposit.
+ * @param signer keyring of the signer - either the owner or the preimage manager (sudo).
+ * @param h256 hash of the preimage.
+ * @returns promise of extrinsic execution.
+ */
+ unnotePreimage(signer: TSigner, h256: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unnotePreimage', [h256]);
+ }
+
+ /**
+ * Request a preimage be uploaded to the chain without paying any fees or deposits.
+ * @param signer keyring of the signer - either the owner or the preimage manager (sudo).
+ * @param h256 hash of the preimage.
+ * @returns promise of extrinsic execution.
+ */
+ requestPreimage(signer: TSigner, h256: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.preimage.requestPreimage', [h256]);
+ }
+
+ /**
+ * Clear a previously made request for a preimage.
+ * @param signer keyring of the signer - either the owner or the preimage manager (sudo).
+ * @param h256 hash of the preimage.
+ * @returns promise of extrinsic execution.
+ */
+ unrequestPreimage(signer: TSigner, h256: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unrequestPreimage', [h256]);
+ }
+}
+
+class UtilityGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ async batch(signer: TSigner, txs: any[]) {
+ return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batch', [txs]);
+ }
+
+ async batchAll(signer: TSigner, txs: any[]) {
+ return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batchAll', [txs]);
+ }
+
+ batchAllCall(txs: any[]) {
+ return this.helper.constructApiCall('api.tx.utility.batchAll', [txs]);
+ }
+}
+
+export type ChainHelperBaseConstructor = new (...args: any[]) => ChainHelperBase;
+export type UniqueHelperConstructor = new (...args: any[]) => UniqueHelper;
+
+export class UniqueHelper extends ChainHelperBase {
+ balance: BalanceGroup<UniqueHelper>;
+ collection: CollectionGroup;
+ nft: NFTGroup;
+ rft: RFTGroup;
+ ft: FTGroup;
+ staking: StakingGroup;
+ preimage: PreimageGroup;
+ utility: UtilityGroup<UniqueHelper>;
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? UniqueHelper);
+
+ this.balance = new BalanceGroup(this);
+ this.collection = new CollectionGroup(this);
+ this.nft = new NFTGroup(this);
+ this.rft = new RFTGroup(this);
+ this.ft = new FTGroup(this);
+ this.staking = new StakingGroup(this);
+ this.preimage = new PreimageGroup(this);
+ this.utility = new UtilityGroup(this);
+ }
+}
+
+export class UniqueBaseCollection {
+ helper: UniqueHelper;
+ collectionId: number;
+
+ constructor(collectionId: number, uniqueHelper: UniqueHelper) {
+ this.collectionId = collectionId;
+ this.helper = uniqueHelper;
+ }
+
+ async getData() {
+ return await this.helper.collection.getData(this.collectionId);
+ }
+
+ async getLastTokenId() {
+ return await this.helper.collection.getLastTokenId(this.collectionId);
+ }
+
+ async doesTokenExist(tokenId: number) {
+ return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);
+ }
+
+ async getAdmins() {
+ return await this.helper.collection.getAdmins(this.collectionId);
+ }
+
+ async getAllowList() {
+ return await this.helper.collection.getAllowList(this.collectionId);
+ }
+
+ async getEffectiveLimits() {
+ return await this.helper.collection.getEffectiveLimits(this.collectionId);
+ }
+
+ async getProperties(propertyKeys?: string[] | null) {
+ return await this.helper.collection.getProperties(this.collectionId, propertyKeys);
+ }
+
+ async getPropertiesConsumedSpace() {
+ return await this.helper.collection.getPropertiesConsumedSpace(this.collectionId);
+ }
+
+ async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {
+ return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);
+ }
+
+ async getOptions() {
+ return await this.helper.collection.getCollectionOptions(this.collectionId);
+ }
+
+ async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {
+ return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);
+ }
+
+ async confirmSponsorship(signer: TSigner) {
+ return await this.helper.collection.confirmSponsorship(signer, this.collectionId);
+ }
+
+ async removeSponsor(signer: TSigner) {
+ return await this.helper.collection.removeSponsor(signer, this.collectionId);
+ }
+
+ async setLimits(signer: TSigner, limits: ICollectionLimits) {
+ return await this.helper.collection.setLimits(signer, this.collectionId, limits);
+ }
+
+ async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {
+ return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);
+ }
+
+ async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {
+ return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);
+ }
+
+ async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {
+ return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);
+ }
+
+ async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {
+ return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);
+ }
+
+ async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {
+ return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);
+ }
+
+ async setProperties(signer: TSigner, properties: IProperty[]) {
+ return await this.helper.collection.setProperties(signer, this.collectionId, properties);
+ }
+
+ async deleteProperties(signer: TSigner, propertyKeys: string[]) {
+ return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);
+ }
+
+ async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {
+ return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);
+ }
+
+ async enableNesting(signer: TSigner, permissions: INestingPermissions) {
+ return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);
+ }
+
+ async disableNesting(signer: TSigner) {
+ return await this.helper.collection.disableNesting(signer, this.collectionId);
+ }
+
+ async burn(signer: TSigner) {
+ return await this.helper.collection.burn(signer, this.collectionId);
+ }
+}
+
+export class UniqueNFTCollection extends UniqueBaseCollection {
+ getTokenObject(tokenId: number) {
+ return new UniqueNFToken(tokenId, this);
+ }
+
+ async getTokensByAddress(addressObj: ICrossAccountId) {
+ return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);
+ }
+
+ async getToken(tokenId: number, blockHashAt?: string) {
+ return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);
+ }
+
+ async getTokenOwner(tokenId: number, blockHashAt?: string) {
+ return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);
+ }
+
+ async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {
+ return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);
+ }
+
+ async getTokenChildren(tokenId: number, blockHashAt?: string) {
+ return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);
+ }
+
+ async getPropertyPermissions(propertyKeys: string[] | null = null) {
+ return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);
+ }
+
+ async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {
+ return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);
+ }
+
+ async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {
+ const api = this.helper.getApi();
+ const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;
+
+ return props?.consumedSpace ?? 0;
+ }
+
+ async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {
+ return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);
+ }
+
+ async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+ return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);
+ }
+
+ async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {
+ return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);
+ }
+
+ async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {
+ return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);
+ }
+
+ async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {
+ return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});
+ }
+
+ async mintMultipleTokens(signer: TSigner, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]) {
+ return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);
+ }
+
+ async burnToken(signer: TSigner, tokenId: number) {
+ return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);
+ }
+
+ async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {
+ return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);
+ }
+
+ async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {
+ return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);
+ }
+
+ async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {
+ return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);
+ }
+
+ async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {
+ return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
+ }
+
+ async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
+ return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
+ }
+
+ async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+ return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
+ }
+}
+
+export class UniqueRFTCollection extends UniqueBaseCollection {
+ getTokenObject(tokenId: number) {
+ return new UniqueRFToken(tokenId, this);
+ }
+
+ async getToken(tokenId: number, blockHashAt?: string) {
+ return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);
+ }
+
+ async getTokenOwner(tokenId: number, blockHashAt?: string) {
+ return await this.helper.rft.getTokenOwner(this.collectionId, tokenId, blockHashAt);
+ }
+
+ async getTokensByAddress(addressObj: ICrossAccountId) {
+ return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);
+ }
+
+ async getTop10TokenOwners(tokenId: number) {
+ return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);
+ }
+
+ async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {
+ return await this.helper.rft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);
+ }
+
+ async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {
+ return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);
+ }
+
+ async getTokenTotalPieces(tokenId: number) {
+ return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);
+ }
+
+ async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+ return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);
+ }
+
+ async getPropertyPermissions(propertyKeys: string[] | null = null) {
+ return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);
+ }
+
+ async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {
+ return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);
+ }
+
+ async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {
+ const api = this.helper.getApi();
+ const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;
+
+ return props?.consumedSpace ?? 0;
+ }
+
+ async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);
+ }
+
+ async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);
+ }
+
+ async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);
+ }
+
+ async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {
+ return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);
+ }
+
+ async mintToken(signer: TSigner, pieces = 1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {
+ return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});
+ }
+
+ async mintMultipleTokens(signer: TSigner, tokens: { pieces: bigint, owner: ICrossAccountId, properties?: IProperty[] }[]) {
+ return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);
+ }
+
+ async burnToken(signer: TSigner, tokenId: number, amount = 1n) {
+ return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);
+ }
+
+ async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);
+ }
+
+ async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {
+ return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);
+ }
+
+ async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {
+ return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);
+ }
+
+ async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {
+ return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
+ }
+
+ async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
+ return await this.helper.rft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
+ }
+
+ async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+ return await this.helper.rft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
+ }
+}
+
+export class UniqueFTCollection extends UniqueBaseCollection {
+ async getBalance(addressObj: ICrossAccountId) {
+ return await this.helper.ft.getBalance(this.collectionId, addressObj);
+ }
+
+ async getTotalPieces() {
+ return await this.helper.ft.getTotalPieces(this.collectionId);
+ }
+
+ async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+ return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);
+ }
+
+ async getTop10Owners() {
+ return await this.helper.ft.getTop10Owners(this.collectionId);
+ }
+
+ async mint(signer: TSigner, amount = 1n, owner: ICrossAccountId = {Substrate: signer.address}) {
+ return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);
+ }
+
+ async mintWithOneOwner(signer: TSigner, tokens: { value: bigint }[], owner: ICrossAccountId = {Substrate: signer.address}) {
+ return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);
+ }
+
+ async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);
+ }
+
+ async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);
+ }
+
+ async burnTokens(signer: TSigner, amount = 1n) {
+ return await this.helper.ft.burnTokens(signer, this.collectionId, amount);
+ }
+
+ async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);
+ }
+
+ async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);
+ }
+}
+
+export class UniqueBaseToken {
+ collection: UniqueNFTCollection | UniqueRFTCollection;
+ collectionId: number;
+ tokenId: number;
+
+ constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {
+ this.collection = collection;
+ this.collectionId = collection.collectionId;
+ this.tokenId = tokenId;
+ }
+
+ async getNextSponsored(addressObj: ICrossAccountId) {
+ return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);
+ }
+
+ async getProperties(propertyKeys?: string[] | null) {
+ return await this.collection.getTokenProperties(this.tokenId, propertyKeys);
+ }
+
+ async getTokenPropertiesConsumedSpace() {
+ return await this.collection.getTokenPropertiesConsumedSpace(this.tokenId);
+ }
+
+ async setProperties(signer: TSigner, properties: IProperty[]) {
+ return await this.collection.setTokenProperties(signer, this.tokenId, properties);
+ }
+
+ async deleteProperties(signer: TSigner, propertyKeys: string[]) {
+ return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);
+ }
+
+ async doesExist() {
+ return await this.collection.doesTokenExist(this.tokenId);
+ }
+
+ nestingAccount(): ICrossAccountId {
+ return this.collection.helper.util.getTokenAccount(this);
+ }
+}
+
+export class UniqueNFToken extends UniqueBaseToken {
+ declare collection: UniqueNFTCollection;
+
+ constructor(tokenId: number, collection: UniqueNFTCollection) {
+ super(tokenId, collection);
+ this.collection = collection;
+ }
+
+ async getData(blockHashAt?: string) {
+ return await this.collection.getToken(this.tokenId, blockHashAt);
+ }
+
+ async getOwner(blockHashAt?: string) {
+ return await this.collection.getTokenOwner(this.tokenId, blockHashAt);
+ }
+
+ async getTopmostOwner(blockHashAt?: string) {
+ return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);
+ }
+
+ async getChildren(blockHashAt?: string) {
+ return await this.collection.getTokenChildren(this.tokenId, blockHashAt);
+ }
+
+ async nest(signer: TSigner, toTokenObj: IToken) {
+ return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
+ }
+
+ async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+ return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
+ }
+
+ async transfer(signer: TSigner, addressObj: ICrossAccountId) {
+ return await this.collection.transferToken(signer, this.tokenId, addressObj);
+ }
+
+ async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+ return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);
+ }
+
+ async approve(signer: TSigner, toAddressObj: ICrossAccountId) {
+ return await this.collection.approveToken(signer, this.tokenId, toAddressObj);
+ }
+
+ async isApproved(toAddressObj: ICrossAccountId) {
+ return await this.collection.isTokenApproved(this.tokenId, toAddressObj);
+ }
+
+ async burn(signer: TSigner) {
+ return await this.collection.burnToken(signer, this.tokenId);
+ }
+
+ async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {
+ return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);
+ }
+}
+
+export class UniqueRFToken extends UniqueBaseToken {
+ declare collection: UniqueRFTCollection;
+
+ constructor(tokenId: number, collection: UniqueRFTCollection) {
+ super(tokenId, collection);
+ this.collection = collection;
+ }
+
+ async getData(blockHashAt?: string) {
+ return await this.collection.getToken(this.tokenId, blockHashAt);
+ }
+
+ async getOwner(blockHashAt?: string) {
+ return await this.collection.getTokenOwner(this.tokenId, blockHashAt);
+ }
+
+ async getTop10Owners() {
+ return await this.collection.getTop10TokenOwners(this.tokenId);
+ }
+
+ async getTopmostOwner(blockHashAt?: string) {
+ return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);
+ }
+
+ async nest(signer: TSigner, toTokenObj: IToken) {
+ return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
+ }
+
+ async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+ return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
+ }
+
+ async getBalance(addressObj: ICrossAccountId) {
+ return await this.collection.getTokenBalance(this.tokenId, addressObj);
+ }
+
+ async getTotalPieces() {
+ return await this.collection.getTokenTotalPieces(this.tokenId);
+ }
+
+ async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {
+ return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);
+ }
+
+ async transfer(signer: TSigner, addressObj: ICrossAccountId, amount = 1n) {
+ return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);
+ }
+
+ async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);
+ }
+
+ async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);
+ }
+
+ async repartition(signer: TSigner, amount: bigint) {
+ return await this.collection.repartitionToken(signer, this.tokenId, amount);
+ }
+
+ async burn(signer: TSigner, amount = 1n) {
+ return await this.collection.burnToken(signer, this.tokenId, amount);
+ }
+
+ async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {
+ return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);
+ }
+}
js-packages/playgrounds/unique.xcm.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/playgrounds/unique.xcm.ts
@@ -0,0 +1,375 @@
+import {ApiPromise, WsProvider} from '@polkadot/api';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {ChainHelperBase, EthereumBalanceGroup, HelperGroup, SubstrateBalanceGroup, UniqueHelper} from './unique.js';
+import type {ILogger, TSigner, TSubstrateAccount} from './types.js';
+import type {AcalaAssetMetadata, DemocracyStandardAccountVote, IForeignAssetMetadata, MoonbeamAssetInfo} from './types.xcm.js';
+
+
+export class XcmChainHelper extends ChainHelperBase {
+ override async connect(wsEndpoint: string, _listeners?: any): Promise<void> {
+ const wsProvider = new WsProvider(wsEndpoint);
+ this.api = new ApiPromise({
+ provider: wsProvider,
+ });
+ await this.api.isReadyOrError;
+ this.network = await UniqueHelper.detectNetwork(this.api);
+ }
+}
+
+class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {
+ async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);
+ }
+}
+
+class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {
+ makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {
+ const apiPrefix = 'api.tx.assetManager.';
+
+ const registerTx = this.helper.constructApiCall(
+ apiPrefix + 'registerForeignAsset',
+ [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],
+ );
+
+ const setUnitsTx = this.helper.constructApiCall(
+ apiPrefix + 'setAssetUnitsPerSecond',
+ [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],
+ );
+
+ const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);
+ const encodedProposal = batchCall?.method.toHex() || '';
+ return encodedProposal;
+ }
+
+ async assetTypeId(location: any) {
+ return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);
+ }
+}
+
+class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {
+ notePreimagePallet: string;
+
+ constructor(helper: MoonbeamHelper, options: { [key: string]: any } = {}) {
+ super(helper);
+ this.notePreimagePallet = options.notePreimagePallet;
+ }
+
+ async notePreimage(signer: TSigner, encodedProposal: string) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);
+ }
+
+ externalProposeMajority(proposal: any) {
+ return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);
+ }
+
+ fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {
+ return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);
+ }
+
+ async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);
+ }
+}
+
+class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {
+ collective: string;
+
+ constructor(helper: MoonbeamHelper, collective: string) {
+ super(helper);
+
+ this.collective = collective;
+ }
+
+ async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);
+ }
+
+ async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);
+ }
+
+ async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);
+ }
+
+ async proposalCount() {
+ return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));
+ }
+}
+
+class PolkadexXcmHelperGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ async whitelistToken(signer: TSigner, assetId: any) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.xcmHelper.whitelistToken', [assetId], true);
+ }
+}
+
+export class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {
+ async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {
+ await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.foreignAssets.registerForeignAsset',
+ [ownerAddress, location, metadata],
+ true,
+ );
+ }
+
+ async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {
+ await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.foreignAssets.updateForeignAsset',
+ [foreignAssetId, location, metadata],
+ true,
+ );
+ }
+}
+
+export class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ palletName: string;
+
+ constructor(helper: T, palletName: string) {
+ super(helper);
+
+ this.palletName = palletName;
+ }
+
+ async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);
+ }
+
+ async setSafeXcmVersion(signer: TSigner, version: number) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.forceDefaultXcmVersion`, [version], true);
+ }
+
+ async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);
+ }
+
+ async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint, xcmVersion = 3) {
+ const destinationContent = {
+ parents: 0,
+ interior: {
+ X1: {
+ Parachain: destinationParaId,
+ },
+ },
+ };
+
+ const beneficiaryContent = {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: targetAccount,
+ },
+ },
+ },
+ };
+
+ const assetsContent = [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: amount,
+ },
+ },
+ ];
+
+ let destination;
+ let beneficiary;
+ let assets;
+
+ if(xcmVersion == 2) {
+ destination = {V1: destinationContent};
+ beneficiary = {V1: beneficiaryContent};
+ assets = {V1: assetsContent};
+
+ } else if(xcmVersion == 3) {
+ destination = {V2: destinationContent};
+ beneficiary = {V2: beneficiaryContent};
+ assets = {V2: assetsContent};
+
+ } else {
+ throw Error('Unknown XCM version: ' + xcmVersion);
+ }
+
+ const feeAssetItem = 0;
+
+ await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem);
+ }
+
+ async send(signer: IKeyringPair, destination: any, message: any) {
+ await this.helper.executeExtrinsic(
+ signer,
+ `api.tx.${this.palletName}.send`,
+ [
+ destination,
+ message,
+ ],
+ true,
+ );
+ }
+}
+
+export class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);
+ }
+
+ async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);
+ }
+
+ async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);
+ }
+}
+
+
+
+export class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ async accounts(address: string, currencyId: any) {
+ const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;
+ return BigInt(free);
+ }
+}
+
+export class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {
+ async create(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);
+ }
+
+ async forceCreate(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint, isSufficient = true) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.assets.forceCreate', [assetId, admin, isSufficient, minimalBalance], true);
+ }
+
+ async setMetadata(signer: TSigner, assetId: number | bigint, name: string, symbol: string, decimals: number) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);
+ }
+
+ async mint(signer: TSigner, assetId: number | bigint, beneficiary: string, amount: bigint) {
+ await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);
+ }
+
+ async account(assetId: string | number | bigint, address: string) {
+ const accountAsset = (
+ await this.helper.callRpc('api.query.assets.account', [assetId, address])
+ ).toJSON()! as any;
+
+ if(accountAsset !== null) {
+ return BigInt(accountAsset['balance']);
+ } else {
+ return null;
+ }
+ }
+}
+
+export class RelayHelper extends XcmChainHelper {
+ balance: SubstrateBalanceGroup<RelayHelper>;
+ xcm: XcmGroup<RelayHelper>;
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? RelayHelper);
+
+ this.balance = new SubstrateBalanceGroup(this);
+ this.xcm = new XcmGroup(this, 'xcmPallet');
+ }
+}
+
+export class WestmintHelper extends XcmChainHelper {
+ balance: SubstrateBalanceGroup<WestmintHelper>;
+ xcm: XcmGroup<WestmintHelper>;
+ assets: AssetsGroup<WestmintHelper>;
+ xTokens: XTokensGroup<WestmintHelper>;
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? WestmintHelper);
+
+ this.balance = new SubstrateBalanceGroup(this);
+ this.xcm = new XcmGroup(this, 'polkadotXcm');
+ this.assets = new AssetsGroup(this);
+ this.xTokens = new XTokensGroup(this);
+ }
+}
+
+export class MoonbeamHelper extends XcmChainHelper {
+ balance: EthereumBalanceGroup<MoonbeamHelper>;
+ assetManager: MoonbeamAssetManagerGroup;
+ assets: AssetsGroup<MoonbeamHelper>;
+ xTokens: XTokensGroup<MoonbeamHelper>;
+ democracy: MoonbeamDemocracyGroup;
+ collective: {
+ council: MoonbeamCollectiveGroup,
+ techCommittee: MoonbeamCollectiveGroup,
+ };
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? MoonbeamHelper);
+
+ this.balance = new EthereumBalanceGroup(this);
+ this.assetManager = new MoonbeamAssetManagerGroup(this);
+ this.assets = new AssetsGroup(this);
+ this.xTokens = new XTokensGroup(this);
+ this.democracy = new MoonbeamDemocracyGroup(this, options);
+ this.collective = {
+ council: new MoonbeamCollectiveGroup(this, 'councilCollective'),
+ techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),
+ };
+ }
+}
+
+export class AstarHelper extends XcmChainHelper {
+ balance: SubstrateBalanceGroup<AstarHelper>;
+ assets: AssetsGroup<AstarHelper>;
+ xcm: XcmGroup<AstarHelper>;
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? AstarHelper);
+
+ this.balance = new SubstrateBalanceGroup(this);
+ this.assets = new AssetsGroup(this);
+ this.xcm = new XcmGroup(this, 'polkadotXcm');
+ }
+}
+
+export class AcalaHelper extends XcmChainHelper {
+ balance: SubstrateBalanceGroup<AcalaHelper>;
+ assetRegistry: AcalaAssetRegistryGroup;
+ xTokens: XTokensGroup<AcalaHelper>;
+ tokens: TokensGroup<AcalaHelper>;
+ xcm: XcmGroup<AcalaHelper>;
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? AcalaHelper);
+
+ this.balance = new SubstrateBalanceGroup(this);
+ this.assetRegistry = new AcalaAssetRegistryGroup(this);
+ this.xTokens = new XTokensGroup(this);
+ this.tokens = new TokensGroup(this);
+ this.xcm = new XcmGroup(this, 'polkadotXcm');
+ }
+}
+
+export class PolkadexHelper extends XcmChainHelper {
+ assets: AssetsGroup<PolkadexHelper>;
+ balance: SubstrateBalanceGroup<PolkadexHelper>;
+ xTokens: XTokensGroup<PolkadexHelper>;
+ xcm: XcmGroup<PolkadexHelper>;
+ xcmHelper: PolkadexXcmHelperGroup<PolkadexHelper>;
+
+ constructor(logger?: ILogger, options: { [key: string]: any } = {}) {
+ super(logger, options.helperBase ?? PolkadexHelper);
+
+ this.assets = new AssetsGroup(this);
+ this.balance = new SubstrateBalanceGroup(this);
+ this.xTokens = new XTokensGroup(this);
+ this.xcm = new XcmGroup(this, 'polkadotXcm');
+ this.xcmHelper = new PolkadexXcmHelperGroup(this);
+ }
+}
+
js-packages/scripts/benchmarks/mintFee/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/mintFee/index.ts
@@ -0,0 +1,399 @@
+import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
+import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {readFile} from 'fs/promises';
+import type {ICrossAccountId} from '@unique/playgrounds/types.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {UniqueNFTCollection} from '@unique/playgrounds/unique.js';
+import {Contract} from 'web3-eth-contract';
+import {createObjectCsvWriter} from 'csv-writer';
+import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from '../utils/common.js';
+import {makeNames} from '@unique/tests/util/index.js';
+import type {ContractImports} from '@unique/tests/eth/util/playgrounds/types.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+export const CONTRACT_IMPORT: ContractImports[] = [
+ {
+ fsPath: `${dirname}/../../../../tests/eth/api/CollectionHelpers.sol`,
+ solPath: 'eth/api/CollectionHelpers.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../tests/eth/api/ContractHelpers.sol`,
+ solPath: 'eth/api/ContractHelpers.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../tests/eth/api/UniqueRefungibleToken.sol`,
+ solPath: 'eth/api/UniqueRefungibleToken.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../tests/eth/api/UniqueRefungible.sol`,
+ solPath: 'eth/api/UniqueRefungible.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../tests/eth/api/UniqueNFT.sol`,
+ solPath: 'eth/api/UniqueNFT.sol',
+ },
+];
+
+interface IBenchmarkResultForProp {
+ propertiesNumber: number;
+ substrateFee: number;
+ ethFee: number;
+ ethBulkFee: number;
+ ethMintCrossFee: number;
+ evmProxyContractFee: number;
+ evmProxyContractBulkFee: number;
+}
+
+const main = async () => {
+ const benchmarks = [
+ 'substrateFee',
+ 'ethFee',
+ 'ethBulkFee',
+ 'ethMintCrossFee',
+ 'evmProxyContractFee',
+ 'evmProxyContractBulkFee',
+ ];
+ const headers = [
+ 'propertiesNumber',
+ ...benchmarks,
+ ];
+
+
+ const csvWriter = createObjectCsvWriter({
+ path: 'properties.csv',
+ header: headers,
+ });
+
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ const CONTRACT_SOURCE = (
+ await readFile(`${dirname}/proxyContract.sol`)
+ ).toString();
+
+ const donor = await privateKey('//Alice'); // Seed from account with balance on this network
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+
+ const contract = await helper.ethContract.deployByCode(
+ ethSigner,
+ 'ProxyMint',
+ CONTRACT_SOURCE,
+ CONTRACT_IMPORT,
+ );
+
+ const fees = await benchMintFee(helper, privateKey, contract);
+ console.log('Minting without properties');
+ console.table(fees);
+
+ const result: IBenchmarkResultForProp[] = [];
+ const csvResult: IBenchmarkResultForProp[] = [];
+
+ for(let i = 1; i <= 20; i++) {
+ const benchResult = await benchMintWithProperties(helper, privateKey, contract, {
+ propertiesNumber: i,
+ }) as any;
+
+ csvResult.push(benchResult);
+
+ const minFee = Math.min(...(benchmarks.map(x => benchResult[x])));
+ for(const key of benchmarks) {
+ const keyPercent = Math.round((benchResult[key] / minFee) * 100);
+ benchResult[key] = `${benchResult[key]} (${keyPercent}%)`;
+ }
+
+ result.push(benchResult);
+ }
+
+ await csvWriter.writeRecords(csvResult);
+
+ console.log('Minting with properties');
+ console.table(result, headers);
+ });
+};
+
+main()
+ .then(() => process.exit(0))
+ .catch((e) => {
+ console.log(e);
+ process.exit(1);
+ });
+
+
+
+async function benchMintFee(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+ proxyContract: Contract,
+): Promise<{
+ substrateFee: number;
+ ethFee: number;
+ evmProxyContractFee: number;
+}> {
+ const donor = await privateKey('//Alice');
+ const substrateReceiver = await privateKey('//Bob');
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+
+ const nominal = helper.balance.getOneTokenNominal();
+
+ await helper.eth.transferBalanceFromSubstrate(
+ donor,
+ proxyContract.options.address,
+ 100n,
+ );
+
+ const collection = (await createCollectionForBenchmarks(
+ 'nft',
+ helper,
+ privateKey,
+ ethSigner,
+ proxyContract.options.address,
+ PERMISSIONS,
+ )) as UniqueNFTCollection;
+
+ const substrateFee = await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),
+ );
+
+ const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionContract = await helper.ethNativeContract.collection(
+ collectionEthAddress,
+ 'nft',
+ );
+
+ const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);
+
+ const encodedCall = collectionContract.methods
+ .mint(receiverEthAddress)
+ .encodeABI();
+
+ const ethFee = await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ async () => {
+ await helper.eth.sendEVM(
+ donor,
+ collectionContract.options.address,
+ encodedCall,
+ '0',
+ );
+ },
+ );
+
+ const evmProxyContractFee = await helper.arrange.calculcateFee(
+ {Ethereum: ethSigner},
+ async () => {
+ await proxyContract.methods
+ .mintToSubstrate(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ substrateReceiver.addressRaw,
+ )
+ .send({from: ethSigner});
+ },
+ );
+
+ return {
+ substrateFee: convertToTokens(substrateFee, nominal),
+ ethFee: convertToTokens(ethFee, nominal),
+ evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),
+ };
+}
+
+async function benchMintWithProperties(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+ proxyContract: Contract,
+ setup: { propertiesNumber: number },
+): Promise<IBenchmarkResultForProp> {
+ const donor = await privateKey('//Alice'); // Seed from account with balance on this network
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+
+ const susbstrateReceiver = await privateKey('//Bob');
+ const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);
+
+ const nominal = helper.balance.getOneTokenNominal();
+
+ const substrateFee = await calculateFeeNftMintWithProperties(
+ helper,
+ privateKey,
+ {Substrate: donor.address},
+ ethSigner,
+ proxyContract.options.address,
+ async (collection) => {
+ await collection.mintToken(
+ donor,
+ {Substrate: susbstrateReceiver.address},
+ PROPERTIES.slice(0, setup.propertiesNumber).map((p) => ({key: p.key, value: Buffer.from(p.value).toString()})),
+ );
+ },
+ );
+
+ const ethFee = await calculateFeeNftMintWithProperties(
+ helper,
+ privateKey,
+ {Substrate: donor.address},
+ ethSigner,
+ proxyContract.options.address,
+ async (collection) => {
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'nft',
+ undefined,
+ true,
+ );
+
+ const subTokenId = await evmContract.methods.nextTokenId().call();
+
+ let encodedCall = evmContract.methods
+ .mint(receiverEthAddress)
+ .encodeABI();
+
+ await helper.eth.sendEVM(
+ donor,
+ evmContract.options.address,
+ encodedCall,
+ '0',
+ );
+
+ for(const val of PROPERTIES.slice(0, setup.propertiesNumber)) {
+ encodedCall = await evmContract.methods
+ .setProperty(subTokenId, val.key, Buffer.from(val.value))
+ .encodeABI();
+
+ await helper.eth.sendEVM(
+ donor,
+ evmContract.options.address,
+ encodedCall,
+ '0',
+ );
+ }
+ },
+ );
+
+ const ethBulkFee = await calculateFeeNftMintWithProperties(
+ helper,
+ privateKey,
+ {Substrate: donor.address},
+ ethSigner,
+ proxyContract.options.address,
+ async (collection) => {
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'nft',
+ );
+
+ const subTokenId = await evmContract.methods.nextTokenId().call();
+
+ let encodedCall = evmContract.methods
+ .mint(receiverEthAddress)
+ .encodeABI();
+
+ await helper.eth.sendEVM(
+ donor,
+ evmContract.options.address,
+ encodedCall,
+ '0',
+ );
+
+ encodedCall = await evmContract.methods
+ .setProperties(
+ subTokenId,
+ PROPERTIES.slice(0, setup.propertiesNumber),
+ )
+ .encodeABI();
+
+ await helper.eth.sendEVM(
+ donor,
+ evmContract.options.address,
+ encodedCall,
+ '0',
+ );
+ },
+ );
+
+ const ethMintCrossFee = await calculateFeeNftMintWithProperties(
+ helper,
+ privateKey,
+ {Ethereum: ethSigner},
+ ethSigner,
+ proxyContract.options.address,
+ async (collection) => {
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'nft',
+ );
+
+ await evmContract.methods.mintCross(
+ helper.ethCrossAccount.fromAddress(receiverEthAddress),
+ PROPERTIES.slice(0, setup.propertiesNumber),
+ )
+ .send({from: ethSigner});
+ },
+ );
+
+ const proxyContractFee = await calculateFeeNftMintWithProperties(
+ helper,
+ privateKey,
+ {Ethereum: ethSigner},
+ ethSigner,
+ proxyContract.options.address,
+ async (collection) => {
+ await proxyContract.methods
+ .mintToSubstrateWithProperty(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ susbstrateReceiver.addressRaw,
+ PROPERTIES.slice(0, setup.propertiesNumber),
+ )
+ .send({from: ethSigner});
+ },
+ );
+
+ const proxyContractBulkFee = await calculateFeeNftMintWithProperties(
+ helper,
+ privateKey,
+ {Ethereum: ethSigner},
+ ethSigner,
+ proxyContract.options.address,
+ async (collection) => {
+ await proxyContract.methods
+ .mintToSubstrateBulkProperty(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ susbstrateReceiver.addressRaw,
+ PROPERTIES.slice(0, setup.propertiesNumber),
+ )
+ .send({from: ethSigner});
+ },
+ );
+
+ return {
+ propertiesNumber: setup.propertiesNumber,
+ substrateFee: convertToTokens(substrateFee, nominal),
+ ethFee: convertToTokens(ethFee, nominal),
+ ethBulkFee: convertToTokens(ethBulkFee, nominal),
+ ethMintCrossFee: convertToTokens(ethMintCrossFee, nominal),
+ evmProxyContractFee: convertToTokens(proxyContractFee, nominal),
+ evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),
+ };
+}
+
+async function calculateFeeNftMintWithProperties(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+ payer: ICrossAccountId,
+ ethSigner: string,
+ proxyContractAddress: string,
+ calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,
+): Promise<bigint> {
+ const collection = (await createCollectionForBenchmarks(
+ 'nft',
+ helper,
+ privateKey,
+ ethSigner,
+ proxyContractAddress,
+ PERMISSIONS,
+ )) as UniqueNFTCollection;
+ return helper.arrange.calculcateFee(payer, async () => {
+ await calculatedCall(collection);
+ });
+}
+
+
+
js-packages/scripts/benchmarks/mintFee/proxyContract.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/mintFee/proxyContract.sol
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: Apache License
+pragma solidity >=0.8.0;
+import {CollectionHelpers} from "eth/api/CollectionHelpers.sol";
+import {ContractHelpers} from "eth/api/ContractHelpers.sol";
+import {UniqueRefungibleToken} from "eth/api/UniqueRefungibleToken.sol";
+import {UniqueRefungible, Collection, CrossAddress as RftCrossAccountId, Property as RftProperty} from "eth/api/UniqueRefungible.sol";
+import {UniqueNFT, CrossAddress as NftCrossAccountId, Property as NftProperty} from "eth/api/UniqueNFT.sol";
+
+struct Property {
+ string key;
+ bytes value;
+}
+
+interface SoftDeprecatedMethods {
+ /// @notice Set token property value.
+ /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ /// @param tokenId ID of the token.
+ /// @param key Property key.
+ /// @param value Property value.
+ /// @dev EVM selector for this function is: 0x1752d67b,
+ /// or in textual repr: setProperty(uint256,string,bytes)
+ function setProperty(
+ uint256 tokenId,
+ string memory key,
+ bytes memory value
+ ) external;
+}
+
+interface BenchUniqueRefungible is UniqueRefungible, SoftDeprecatedMethods {}
+interface BenchUniqueNFT is UniqueNFT, SoftDeprecatedMethods {}
+
+
+
+contract ProxyMint {
+ bytes32 constant REFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("ReFungible"));
+ bytes32 constant NONFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("NFT"));
+
+ modifier checkRestrictions(address _collection) {
+ Collection commonContract = Collection(_collection);
+ require(
+ commonContract.isOwnerOrAdminCross(RftCrossAccountId(msg.sender, 0)),
+ "Only collection admin/owner can call this method"
+ );
+ _;
+ }
+
+ /// @dev This emits when a mint to a substrate address has been made.
+ event MintToSub(address _toEth, uint256 _toSub, address _collection, uint256 _tokenId);
+
+ function mintToSubstrate(address _collection, uint256 _substrateReceiver) external checkRestrictions(_collection) {
+ Collection commonContract = Collection(_collection);
+ bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
+ uint256 tokenId;
+
+ if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
+ UniqueRefungible rftCollection = UniqueRefungible(_collection);
+
+ tokenId = rftCollection.mint(address(this));
+
+ rftCollection.transferFromCross(
+ RftCrossAccountId(address(this), 0),
+ RftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
+ UniqueNFT nftCollection = UniqueNFT(_collection);
+ tokenId = nftCollection.mint(address(this));
+
+ nftCollection.transferFromCross(
+ NftCrossAccountId(address(this), 0),
+ NftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else {
+ revert("Wrong collection type. Works only with NFT or RFT");
+ }
+
+ emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
+ }
+
+ function mintToSubstrateWithProperty(
+ address _collection,
+ uint256 _substrateReceiver,
+ Property[] calldata _properties
+ ) external checkRestrictions(_collection) {
+ uint256 propertiesLength = _properties.length;
+ require(propertiesLength > 0, "Properies is empty");
+
+ Collection commonContract = Collection(_collection);
+ bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
+ uint256 tokenId;
+
+ if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
+ BenchUniqueRefungible rftCollection = BenchUniqueRefungible(_collection);
+ tokenId = rftCollection.nextTokenId();
+ rftCollection.mint(address(this));
+
+ for (uint256 i = 0; i < propertiesLength; ++i) {
+ rftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);
+ }
+ rftCollection.transferFromCross(
+ RftCrossAccountId(address(this), 0),
+ RftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
+ BenchUniqueNFT nftCollection = BenchUniqueNFT(_collection);
+ tokenId = nftCollection.mint(address(this));
+ for (uint256 i = 0; i < propertiesLength; ++i) {
+ nftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);
+ }
+ nftCollection.transferFromCross(
+ NftCrossAccountId(address(this), 0),
+ NftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else {
+ revert("Wrong collection type. Works only with NFT or RFT");
+ }
+
+ emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
+ }
+
+ function mintToSubstrateBulkProperty(
+ address _collection,
+ uint256 _substrateReceiver,
+ NftProperty[] calldata _properties
+ ) external checkRestrictions(_collection) {
+ uint256 propertiesLength = _properties.length;
+ require(propertiesLength > 0, "Properies is empty");
+
+ Collection commonContract = Collection(_collection);
+ bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
+ uint256 tokenId;
+
+ if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {} else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
+ UniqueNFT nftCollection = UniqueNFT(_collection);
+ tokenId = nftCollection.mint(address(this));
+
+ nftCollection.setProperties(tokenId, _properties);
+
+ nftCollection.transferFromCross(
+ NftCrossAccountId(address(this), 0),
+ NftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else {
+ revert("Wrong collection type. Works only with NFT or RFT");
+ }
+
+ emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
+ }
+}
js-packages/scripts/benchmarks/nesting/ABIGEN/RMRKNestableMintable.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/ABIGEN/RMRKNestableMintable.ts
@@ -0,0 +1,354 @@
+/* Autogenerated file. Do not edit manually. */
+/* tslint:disable */
+/* eslint-disable */
+
+import type BN from "bn.js";
+import type { ContractOptions } from "web3-eth-contract";
+import type { EventLog } from "web3-core";
+import type { EventEmitter } from "events";
+import type {
+ Callback,
+ NonPayableTransactionObject,
+ BlockType,
+ ContractEventLog,
+ BaseContract,
+} from "./types.js";
+
+export interface EventOptions {
+ filter?: object;
+ fromBlock?: BlockType;
+ topics?: string[];
+}
+
+export type AllChildrenRejected = ContractEventLog<{
+ tokenId: string;
+ 0: string;
+}>;
+export type Approval = ContractEventLog<{
+ owner: string;
+ approved: string;
+ tokenId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+}>;
+export type ApprovalForAll = ContractEventLog<{
+ owner: string;
+ operator: string;
+ approved: boolean;
+ 0: string;
+ 1: string;
+ 2: boolean;
+}>;
+export type ChildAccepted = ContractEventLog<{
+ tokenId: string;
+ childIndex: string;
+ childAddress: string;
+ childId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+}>;
+export type ChildProposed = ContractEventLog<{
+ tokenId: string;
+ childIndex: string;
+ childAddress: string;
+ childId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+}>;
+export type ChildTransferred = ContractEventLog<{
+ tokenId: string;
+ childIndex: string;
+ childAddress: string;
+ childId: string;
+ fromPending: boolean;
+ toZero: boolean;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+ 4: boolean;
+ 5: boolean;
+}>;
+export type NestTransfer = ContractEventLog<{
+ from: string;
+ to: string;
+ fromTokenId: string;
+ toTokenId: string;
+ tokenId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+ 3: string;
+ 4: string;
+}>;
+export type Transfer = ContractEventLog<{
+ from: string;
+ to: string;
+ tokenId: string;
+ 0: string;
+ 1: string;
+ 2: string;
+}>;
+
+export interface RMRKNestableMintable extends BaseContract {
+ constructor(
+ jsonInterface: any[],
+ address?: string,
+ options?: ContractOptions
+ ): RMRKNestableMintable;
+ clone(): RMRKNestableMintable;
+ methods: {
+ RMRK_INTERFACE(): NonPayableTransactionObject<string>;
+
+ VERSION(): NonPayableTransactionObject<string>;
+
+ acceptChild(
+ parentId: number | string | BN,
+ childIndex: number | string | BN,
+ childAddress: string,
+ childId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ addChild(
+ parentId: number | string | BN,
+ childId: number | string | BN,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ approve(
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ balanceOf(owner: string): NonPayableTransactionObject<string>;
+
+ "burn(uint256)"(
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ "burn(uint256,uint256)"(
+ tokenId: number | string | BN,
+ maxChildrenBurns: number | string | BN
+ ): NonPayableTransactionObject<string>;
+
+ childOf(
+ parentId: number | string | BN,
+ index: number | string | BN
+ ): NonPayableTransactionObject<[string, string]>;
+
+ childrenOf(
+ parentId: number | string | BN
+ ): NonPayableTransactionObject<[string, string][]>;
+
+ directOwnerOf(tokenId: number | string | BN): NonPayableTransactionObject<{
+ 0: string;
+ 1: string;
+ 2: boolean;
+ }>;
+
+ getApproved(
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<string>;
+
+ isApprovedForAll(
+ owner: string,
+ operator: string
+ ): NonPayableTransactionObject<boolean>;
+
+ mint(
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ name(): NonPayableTransactionObject<string>;
+
+ nestMint(
+ to: string,
+ tokenId: number | string | BN,
+ destinationId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ nestTransfer(
+ to: string,
+ tokenId: number | string | BN,
+ destinationId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ nestTransferFrom(
+ from: string,
+ to: string,
+ tokenId: number | string | BN,
+ destinationId: number | string | BN,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ onERC721Received(
+ _operator: string,
+ _from: string,
+ _tokenId: number | string | BN,
+ _data: string | number[]
+ ): NonPayableTransactionObject<string>;
+
+ ownerOf(tokenId: number | string | BN): NonPayableTransactionObject<string>;
+
+ pendingChildOf(
+ parentId: number | string | BN,
+ index: number | string | BN
+ ): NonPayableTransactionObject<[string, string]>;
+
+ pendingChildrenOf(
+ parentId: number | string | BN
+ ): NonPayableTransactionObject<[string, string][]>;
+
+ rejectAllChildren(
+ tokenId: number | string | BN,
+ maxRejections: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ safeMint(to: string): NonPayableTransactionObject<void>;
+
+ "safeTransferFrom(address,address,uint256)"(
+ from: string,
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ "safeTransferFrom(address,address,uint256,bytes)"(
+ from: string,
+ to: string,
+ tokenId: number | string | BN,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ setApprovalForAll(
+ operator: string,
+ approved: boolean
+ ): NonPayableTransactionObject<void>;
+
+ supportsInterface(
+ interfaceId: string | number[]
+ ): NonPayableTransactionObject<boolean>;
+
+ symbol(): NonPayableTransactionObject<string>;
+
+ transfer(
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+
+ transferChild(
+ tokenId: number | string | BN,
+ to: string,
+ destinationId: number | string | BN,
+ childIndex: number | string | BN,
+ childAddress: string,
+ childId: number | string | BN,
+ isPending: boolean,
+ data: string | number[]
+ ): NonPayableTransactionObject<void>;
+
+ transferFrom(
+ from: string,
+ to: string,
+ tokenId: number | string | BN
+ ): NonPayableTransactionObject<void>;
+ };
+ events: {
+ AllChildrenRejected(cb?: Callback<AllChildrenRejected>): EventEmitter;
+ AllChildrenRejected(
+ options?: EventOptions,
+ cb?: Callback<AllChildrenRejected>
+ ): EventEmitter;
+
+ Approval(cb?: Callback<Approval>): EventEmitter;
+ Approval(options?: EventOptions, cb?: Callback<Approval>): EventEmitter;
+
+ ApprovalForAll(cb?: Callback<ApprovalForAll>): EventEmitter;
+ ApprovalForAll(
+ options?: EventOptions,
+ cb?: Callback<ApprovalForAll>
+ ): EventEmitter;
+
+ ChildAccepted(cb?: Callback<ChildAccepted>): EventEmitter;
+ ChildAccepted(
+ options?: EventOptions,
+ cb?: Callback<ChildAccepted>
+ ): EventEmitter;
+
+ ChildProposed(cb?: Callback<ChildProposed>): EventEmitter;
+ ChildProposed(
+ options?: EventOptions,
+ cb?: Callback<ChildProposed>
+ ): EventEmitter;
+
+ ChildTransferred(cb?: Callback<ChildTransferred>): EventEmitter;
+ ChildTransferred(
+ options?: EventOptions,
+ cb?: Callback<ChildTransferred>
+ ): EventEmitter;
+
+ NestTransfer(cb?: Callback<NestTransfer>): EventEmitter;
+ NestTransfer(
+ options?: EventOptions,
+ cb?: Callback<NestTransfer>
+ ): EventEmitter;
+
+ Transfer(cb?: Callback<Transfer>): EventEmitter;
+ Transfer(options?: EventOptions, cb?: Callback<Transfer>): EventEmitter;
+
+ allEvents(options?: EventOptions, cb?: Callback<EventLog>): EventEmitter;
+ };
+
+ once(event: "AllChildrenRejected", cb: Callback<AllChildrenRejected>): void;
+ once(
+ event: "AllChildrenRejected",
+ options: EventOptions,
+ cb: Callback<AllChildrenRejected>
+ ): void;
+
+ once(event: "Approval", cb: Callback<Approval>): void;
+ once(event: "Approval", options: EventOptions, cb: Callback<Approval>): void;
+
+ once(event: "ApprovalForAll", cb: Callback<ApprovalForAll>): void;
+ once(
+ event: "ApprovalForAll",
+ options: EventOptions,
+ cb: Callback<ApprovalForAll>
+ ): void;
+
+ once(event: "ChildAccepted", cb: Callback<ChildAccepted>): void;
+ once(
+ event: "ChildAccepted",
+ options: EventOptions,
+ cb: Callback<ChildAccepted>
+ ): void;
+
+ once(event: "ChildProposed", cb: Callback<ChildProposed>): void;
+ once(
+ event: "ChildProposed",
+ options: EventOptions,
+ cb: Callback<ChildProposed>
+ ): void;
+
+ once(event: "ChildTransferred", cb: Callback<ChildTransferred>): void;
+ once(
+ event: "ChildTransferred",
+ options: EventOptions,
+ cb: Callback<ChildTransferred>
+ ): void;
+
+ once(event: "NestTransfer", cb: Callback<NestTransfer>): void;
+ once(
+ event: "NestTransfer",
+ options: EventOptions,
+ cb: Callback<NestTransfer>
+ ): void;
+
+ once(event: "Transfer", cb: Callback<Transfer>): void;
+ once(event: "Transfer", options: EventOptions, cb: Callback<Transfer>): void;
+}
js-packages/scripts/benchmarks/nesting/ABIGEN/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/ABIGEN/index.ts
@@ -0,0 +1,4 @@
+/* Autogenerated file. Do not edit manually. */
+/* tslint:disable */
+/* eslint-disable */
+export type { RMRKNestableMintable } from "./RMRKNestableMintable.js";
js-packages/scripts/benchmarks/nesting/ABIGEN/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/ABIGEN/types.ts
@@ -0,0 +1,73 @@
+/* Autogenerated file. Do not edit manually. */
+/* tslint:disable */
+/* eslint-disable */
+import type BN from "bn.js";
+import type { EventEmitter } from "events";
+import type { EventLog, PromiEvent, TransactionReceipt } from "web3-core";
+import type { Contract } from "web3-eth-contract";
+
+export interface EstimateGasOptions {
+ from?: string;
+ gas?: number;
+ value?: number | string | BN;
+}
+
+export interface EventOptions {
+ filter?: object;
+ fromBlock?: BlockType;
+ topics?: string[];
+}
+
+export type Callback<T> = (error: Error, result: T) => void;
+export interface ContractEventLog<T> extends EventLog {
+ returnValues: T;
+}
+export interface ContractEventEmitter<T> extends EventEmitter {
+ on(event: "connected", listener: (subscriptionId: string) => void): this;
+ on(
+ event: "data" | "changed",
+ listener: (event: ContractEventLog<T>) => void
+ ): this;
+ on(event: "error", listener: (error: Error) => void): this;
+}
+
+export interface NonPayableTx {
+ nonce?: string | number | BN;
+ chainId?: string | number | BN;
+ from?: string;
+ to?: string;
+ data?: string;
+ gas?: string | number | BN;
+ maxPriorityFeePerGas?: string | number | BN;
+ maxFeePerGas?: string | number | BN;
+ gasPrice?: string | number | BN;
+}
+
+export interface PayableTx extends NonPayableTx {
+ value?: string | number | BN;
+}
+
+export interface NonPayableTransactionObject<T> {
+ arguments: any[];
+ call(tx?: NonPayableTx, block?: BlockType): Promise<T>;
+ send(tx?: NonPayableTx): PromiEvent<TransactionReceipt>;
+ estimateGas(tx?: NonPayableTx): Promise<number>;
+ encodeABI(): string;
+}
+
+export interface PayableTransactionObject<T> {
+ arguments: any[];
+ call(tx?: PayableTx, block?: BlockType): Promise<T>;
+ send(tx?: PayableTx): PromiEvent<TransactionReceipt>;
+ estimateGas(tx?: PayableTx): Promise<number>;
+ encodeABI(): string;
+}
+
+export type BlockType =
+ | "latest"
+ | "pending"
+ | "genesis"
+ | "earliest"
+ | number
+ | BN;
+export type BaseContract = Omit<Contract, "clone" | "once">;
js-packages/scripts/benchmarks/nesting/RMRKNestableMintable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/RMRKNestableMintable.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.18;
+
+import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol";
+import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
+
+contract RMRKNestableMintable is RMRKNestable, IERC721Receiver {
+ uint256 private _counter;
+
+ constructor() RMRKNestable("RMRK", "nesting") {
+ _counter = 1;
+ }
+
+ function safeMint(address to) external {
+ _safeMint(to, _counter, "");
+ _counter++;
+ }
+
+ function mint(address to, uint256 tokenId) external {
+ _mint(to, tokenId, "");
+ }
+
+ function nestMint(address to, uint256 tokenId, uint256 destinationId) external {
+ _nestMint(to, tokenId, destinationId, "");
+ }
+
+ function nestTransfer(address to, uint256 tokenId, uint256 destinationId) public virtual {
+ nestTransferFrom(_msgSender(), to, tokenId, destinationId, "");
+ }
+
+ function transfer(address to, uint256 tokenId) public virtual {
+ transferFrom(_msgSender(), to, tokenId);
+ }
+
+ function onERC721Received(
+ address _operator,
+ address _from,
+ uint256 _tokenId,
+ bytes calldata _data
+ ) external returns (bytes4) {
+ return IERC721Receiver.onERC721Received.selector;
+ }
+}
js-packages/scripts/benchmarks/nesting/abigen.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/abigen.ts
@@ -0,0 +1,20 @@
+import {runTypeChain, glob, DEFAULT_FLAGS} from 'typechain';
+
+
+async function main() {
+ const cwd = process.cwd();
+
+ // find all files matching the glob
+ const allFiles = glob(cwd, ['./ABI/*.abi']);
+
+ await runTypeChain({
+ cwd,
+ filesToProcess: allFiles,
+ allFiles,
+ outDir: 'ABIGEN',
+ target: 'web3-v1',
+ flags: {...DEFAULT_FLAGS, alwaysGenerateOverloads: true, tsNocheck: false},
+ });
+}
+
+main().catch(console.error);
\ No newline at end of file
js-packages/scripts/benchmarks/nesting/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/index.ts
@@ -0,0 +1,222 @@
+import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
+import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {readFile} from 'fs/promises';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
+import {convertToTokens} from '../utils/common.js';
+import {makeNames} from '@unique/tests/util/index.js';
+import type {ContractImports} from '@unique/tests/eth/util/playgrounds/types.js';
+import type {RMRKNestableMintable} from './ABIGEN/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+export const CONTRACT_IMPORT: ContractImports[] = [
+ {
+ fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,
+ solPath: '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
+ solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,
+ solPath: '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Address.sol`,
+ solPath: '@openzeppelin/contracts/utils/Address.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
+ solPath: '@openzeppelin/contracts/utils/Context.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
+ solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol',
+ },
+ {
+ fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,
+ solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol',
+ },
+ {
+ fsPath: `${dirname}/RMRKNestableMintable.sol`,
+ solPath: 'RMRKNestableMintable.sol',
+ },
+];
+
+
+const main = async () => {
+
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+
+ const donor = await privateKey('//Alice'); // Seed from account with balance on this network
+
+ const eth = await measureEth(helper, donor);
+ const sub = await measureSub(helper, donor);
+ const rmrk = await measureRMRK(helper, donor);
+ console.table({susbtrate: sub, eth: eth, rmrk: rmrk});
+ });
+};
+
+async function measureRMRK(helper: EthUniqueHelper, donor: IKeyringPair) {
+ const CONTRACT_SOURCE = (
+ await readFile(`${dirname}/RMRKNestableMintable.sol`)
+ ).toString();
+ const RELAYER_SOURCE = (await readFile(`${dirname}/relayer.sol`)).toString();
+
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+
+ const contract = await helper.ethContract.deployByCode(
+ ethSigner,
+ 'RMRKNestableMintable',
+ CONTRACT_SOURCE,
+ CONTRACT_IMPORT,
+ 5000000,
+ );
+
+ const relayer = await helper.ethContract.deployByCode(
+ ethSigner,
+ 'Relayer',
+ RELAYER_SOURCE,
+ CONTRACT_IMPORT,
+ 5000000,
+ [contract.options.address],
+ );
+
+ const relayerAddress = relayer.options.address;
+
+ const rmrk = contract as any as RMRKNestableMintable;
+ const createTokenFor = async (receiver: string) => {
+ const tokenReceipt = await rmrk.methods.safeMint(receiver).send({from: ethSigner});
+ return tokenReceipt.events!['Transfer'].returnValues.tokenId as number;
+ };
+
+
+ const nestId = await createTokenFor(ethSigner);
+ const outerCollectionNestedId = 10;
+ const contractOwnedNestId = await createTokenFor(relayerAddress);
+ const nextTokenId = contractOwnedNestId + 1;
+
+ const nestTransfer = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
+ const addChildData = rmrk.methods.addChild(nestId, outerCollectionNestedId, []).encodeABI();
+ await relayer.methods.relay(addChildData).send({from: ethSigner});
+ await rmrk.methods.acceptChild(nestId, 0, relayerAddress, outerCollectionNestedId).send({from: ethSigner});
+ });
+
+
+ const nestMint = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
+ const nestMintData = rmrk.methods.nestMint(rmrk.options.address, nextTokenId, contractOwnedNestId).encodeABI();
+ await relayer.methods.relay(nestMintData).send({from: ethSigner});
+ const acceptNestedToken = rmrk.methods.acceptChild(contractOwnedNestId, 0, rmrk.options.address, nextTokenId).encodeABI();
+ await relayer.methods.relay(acceptNestedToken).send({from: ethSigner});
+ });
+
+
+ const unnestToken = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
+ const unnestData = rmrk.methods.transferChild(contractOwnedNestId, ethSigner, 0, 0, rmrk.options.address, nextTokenId, false, []).encodeABI();
+ await relayer.methods.relay(unnestData).send({from: ethSigner});
+ });
+
+ return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
+}
+
+async function measureEth(helper: EthUniqueHelper, donor: IKeyringPair) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Create a token to be nested to
+ const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
+
+ // Create a nested token
+ const nestMint = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
+ await contract.methods.mint(targetNftTokenAddress).send({from: owner});
+ });
+
+ // Create a token to be nested and nest
+ const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const nestedTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ const nestTransfer = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
+ await contract.methods.transfer(targetNftTokenAddress, nestedTokenId).send({from: owner});
+ });
+
+ const unnestToken = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
+ await contract.methods.transferFrom(targetNftTokenAddress, owner, nestedTokenId).send({from: owner});
+ });
+ return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
+}
+
+async function measureSub(helper: EthUniqueHelper, donor: IKeyringPair) {
+
+ const [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+
+
+ const collectionForNesting = await helper.nft.mintCollection(bob);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true},
+ });
+
+ const nestMint = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
+ await (collectionForNesting.mintToken(bob, targetTokenBob.nestingAccount()));
+ });
+
+ const nestedToken2 = await collectionForNesting.mintToken(bob);
+ const nestTransfer = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
+ await nestedToken2.nest(bob, targetTokenBob);
+ });
+
+ const unnestToken = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
+ await nestedToken2.transferFrom(bob, targetTokenBob.nestingAccount(), {Substrate: bob.address});
+ });
+
+ return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
+}
+
+
+const createNestingCollection = async (
+ helper: EthUniqueHelper,
+ owner: string,
+): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ await contract.methods.setCollectionNesting(true).send({from: owner});
+
+ return {collectionId, collectionAddress, contract};
+};
+
+main()
+ .then(() => process.exit(0))
+ .catch((e) => {
+ console.log(e);
+ process.exit(1);
+ });
+
+
+
+
+
+
js-packages/scripts/benchmarks/nesting/relayer.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/nesting/relayer.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.18;
+
+import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
+import "./RMRKNestableMintable.sol";
+
+contract Relayer is RMRKNestableMintable {
+ address _receiver;
+
+ constructor(address recevier) {
+ _receiver = recevier;
+ }
+
+ function relay(bytes calldata payload) external {
+ (bool succes, bytes memory _returnData) = address(_receiver).call(payload);
+ require(succes);
+ }
+}
js-packages/scripts/benchmarks/opsFee/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/opsFee/index.ts
@@ -0,0 +1,892 @@
+import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
+import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {readFile} from 'fs/promises';
+import {CollectionLimitField, CreateCollectionData, TokenPermissionField} from '@unique/tests/eth/util/playgrounds/types.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {UniqueFTCollection, UniqueNFTCollection} from '@unique/playgrounds/unique.js';
+import {Contract} from 'web3-eth-contract';
+import {createObjectCsvWriter} from 'csv-writer';
+import {FunctionFeeVM} from '../utils/types.js';
+import type {IFunctionFee} from '../utils/types.js';
+import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES, SUBS_PROPERTIES} from '../utils/common.js';
+import {makeNames} from '@unique/tests/util/index.js';
+
+
+const {dirname} = makeNames(import.meta.url);
+
+const main = async () => {
+
+ const headers = [
+ 'function',
+ 'ethFee',
+ 'ethGas',
+ 'substrate',
+ 'zeppelinFee',
+ 'zeppelinGas',
+ ];
+
+ const csvWriter20 = createObjectCsvWriter({
+ path: 'erc20.csv',
+ header: headers,
+ });
+
+ const csvWriter721 = createObjectCsvWriter({
+ path: 'erc721.csv',
+ header: headers,
+ });
+
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ console.log('\n ERC20 ops fees');
+ const erc20 = FunctionFeeVM.fromModel(await erc20CalculateFeeGas(helper, privateKey));
+ console.table(erc20);
+ await csvWriter20.writeRecords(FunctionFeeVM.toCsv(erc20));
+
+ console.log('\n ERC721 ops fees');
+ const erc721 = FunctionFeeVM.fromModel(await erc721CalculateFeeGas(helper, privateKey));
+ console.table(erc721);
+
+ await csvWriter721.writeRecords(FunctionFeeVM.toCsv(erc721));
+ });
+};
+
+main()
+ .then(() => process.exit(0))
+ .catch((e) => {
+ console.log(e);
+ process.exit(1);
+ });
+
+async function erc721CalculateFeeGas(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+): Promise<IFunctionFee> {
+ const res: IFunctionFee = {};
+ const donor = await privateKey('//Alice');
+ const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+ const ethReceiver = await helper.eth.createAccountWithBalance(donor);
+ const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);
+ const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);
+ const collection = (await createCollectionForBenchmarks(
+ 'nft',
+ helper,
+ privateKey,
+ ethSigner,
+ null,
+ PERMISSIONS,
+ )) as UniqueNFTCollection;
+
+ const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
+ let zeppelelinContract: Contract | null = null;
+ const ZEPPELIN_OBJECT = '0x' + (await readFile(`${dirname}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.bin`)).toString();
+ const ZEPPELIN_ABI = JSON.parse((await readFile(`${dirname}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.abi`)).toString());
+
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'nft',
+ ethSigner,
+ true,
+ );
+
+ res['createCollection'] = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => helperContract.methods.createNFTCollection('test','test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
+ );
+
+ res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.nft.mintCollection(
+ donor,
+ {name: 'test', description: 'test', tokenPrefix: 'test'},
+ ),
+ )));
+
+ res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ async () => {
+ zeppelelinContract = await helper.ethContract.deployByAbi(
+ ethSigner,
+ ZEPPELIN_ABI,
+ ZEPPELIN_OBJECT,
+ );
+ },
+ );
+
+ res['mint'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mint(ethSigner).send(),
+ );
+
+ res['mint'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.safeMint(ethSigner, '').send({from: ethSigner}),
+ );
+
+ res['mintCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintCross(crossSigner, []).send(),
+ );
+
+ res['mint'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintToken(
+ donor,
+ {Substrate: donor.address},
+ ),
+ )));
+
+ res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintMultipleTokens(donor, [{
+ owner: {Substrate: donor.address},
+ }]),
+ )));
+
+ res['mintWithTokenURI'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),
+ );
+
+ res['mintWithTokenURI'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintToken(
+ donor,
+ {Ethereum: ethSigner},
+ [{key: 'URI', value: 'Test URI'}],
+ ),
+ )));
+
+ res['mintWithTokenURI'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.safeMint(ethSigner, 'Test URI').send({from: ethSigner}),
+ );
+
+ res['setProperties'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setProperties(1, PROPERTIES.slice(0,1)).send(),
+ );
+
+ res['deleteProperties'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.deleteProperties(1, [PROPERTIES[0].key]).send(),
+ );
+
+ res['setProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setTokenProperties(
+ donor,
+ 1,
+ SUBS_PROPERTIES.slice(0, 1),
+ ),
+ )));
+
+ res['deleteProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.deleteTokenProperties(
+ donor,
+ 1,
+ SUBS_PROPERTIES.slice(0, 1)
+ .map(p => p.key),
+ ),
+ )));
+
+ res['transfer'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transfer(ethReceiver, 1).send(),
+ );
+
+ res['safeTransferFrom*'] = {
+ zeppelin:
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.safeTransferFrom(ethSigner, ethReceiver, 0).send({from: ethSigner}),
+ ),
+ };
+
+ res['transferCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
+ );
+
+ res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transferToken(
+ donor,
+ 3,
+ {Substrate: subReceiver.address},
+ ),
+ )));
+ await collection.approveToken(subReceiver, 3, {Substrate: donor.address});
+
+ res['transferFrom*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
+ );
+
+ res['transferFrom*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
+ );
+
+
+ res['transferFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
+ );
+
+ res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transferTokenFrom(donor, 3, {Substrate: subReceiver.address}, {Substrate: donor.address}),
+ )));
+
+ res['burn'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.burn(1).send(),
+ );
+
+ res['burn'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.burnToken(donor, 3),
+ )));
+
+ res['approve*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approve(ethReceiver, 2).send(),
+ );
+
+ res['approve*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.approve(ethReceiver, 0).send({from: ethSigner}),
+ );
+
+ res['approveCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approveCross(crossReceiver, 2).send(),
+ );
+
+ res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.approveToken(donor, 4, {Substrate: subReceiver.address}),
+ )));
+
+ res['setApprovalForAll*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setApprovalForAll(ethReceiver, true).send(),
+ );
+
+ res['setApprovalForAll*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.setApprovalForAll(ethReceiver, true).send({from: ethSigner}),
+ );
+
+ res['setApprovalForAll*'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.nft.setAllowanceForAll(donor, collection.collectionId, {Substrate: subReceiver.address}, true),
+ )));
+
+ res['burnFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),
+ );
+
+ res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.burnTokenFrom(subReceiver, 4, {Substrate: donor.address}),
+ )));
+
+ res['setTokenPropertyPermissions'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setTokenPropertyPermissions([
+ ['url', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).send(),
+ );
+
+ res['setTokenPropertyPermissions'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setTokenPropertyPermissions(donor, [{key: 'url', permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ }}]),
+ )));
+
+ res['setCollectionSponsorCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),
+ );
+
+ res['confirmCollectionSponsorship'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),
+ );
+
+ res['removeCollectionSponsor'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.removeCollectionSponsor().send(),
+ );
+
+ res['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setSponsor(donor, subReceiver.address),
+ )));
+
+ res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.confirmSponsorship(subReceiver),
+ )));
+
+ res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeSponsor(donor),
+ )));
+
+ res['setCollectionProperties'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),
+ );
+
+ res['deleteCollectionProperties'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),
+ );
+ res['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => ({key: p.key, value: p.value.toString()}))),
+ )));
+
+ res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => p.key)),
+ )));
+
+ res['setCollectionLimit'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
+ );
+
+ res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
+ )));
+
+ const {collectionAddress} = await helper.eth.createCollection(ethSigner, new CreateCollectionData('A', 'B', 'C', 'nft')).send();
+ const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);
+
+
+ res['addCollectionAdminCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),
+ );
+
+ res['removeCollectionAdminCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),
+ );
+
+ res['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['setCollectionNesting'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionNesting(true).send(),
+ );
+
+ res['setCollectionNesting[]'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),
+ );
+
+ res['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.disableNesting(donor),
+ )));
+
+ res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(
+ donor,
+ {
+ nesting: {
+ tokenOwner: true,
+ restricted: [collection.collectionId],
+ },
+ },
+ ),
+ )));
+
+ res['setCollectionAccess'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionAccess(1).send(),
+ );
+
+ res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {access: 'AllowList'}),
+ )));
+
+ res['addToCollectionAllowListCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),
+ );
+
+ res['removeFromCollectionAllowListCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),
+ );
+
+ res['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['setCollectionMintMode'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionMintMode(true).send(),
+ );
+
+ res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {mintMode: false}),
+ )));
+
+ res['changeCollectionOwnerCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
+ );
+
+ res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.changeOwner(donor, subReceiver.address),
+ )));
+
+ return res;
+}
+
+async function erc20CalculateFeeGas(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+
+): Promise<IFunctionFee> {
+ const res: IFunctionFee = {};
+ const donor = await privateKey('//Alice');
+ const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
+ const ethSigner = await helper.eth.createAccountWithBalance(donor);
+ const ethReceiver = await helper.eth.createAccountWithBalance(donor);
+ const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);
+ const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);
+ const collection = (await createCollectionForBenchmarks(
+ 'ft',
+ helper,
+ privateKey,
+ ethSigner,
+ null,
+ PERMISSIONS,
+ )) as UniqueFTCollection;
+
+ const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
+ let zeppelelinContract: Contract | null = null;
+ const ZEPPELIN_OBJECT = '0x' + (await readFile(`${dirname}/../utils/openZeppelin/ERC20/bin/ZeppelinContract.bin`)).toString();
+ const ZEPPELIN_ABI = JSON.parse((await readFile(`${dirname}/../utils/openZeppelin/ERC20/bin/ZeppelinContract.abi`)).toString());
+
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'ft',
+ ethSigner,
+ true,
+ );
+
+ res['createCollection'] = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => helperContract.methods.createFTCollection('test', 18,'test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
+ );
+
+ res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.ft.mintCollection(
+ donor,
+ {name: 'test', description: 'test', tokenPrefix: 'test'},
+ 18,
+ ),
+ )));
+
+ res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ async () => {
+ zeppelelinContract = await helper.ethContract.deployByAbi(
+ ethSigner,
+ ZEPPELIN_ABI,
+ ZEPPELIN_OBJECT,
+ );
+ },
+ );
+
+ res['mint'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mint(ethSigner, 1).send(),
+ );
+
+ res['mint'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.mint(ethSigner, 1).send(),
+ );
+
+ res['mintCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintCross(crossSigner, 1).send(),
+ );
+
+ res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mint(
+ donor,
+ 10n,
+ {Substrate: donor.address},
+ ),
+ )));
+
+ res['mintBulk'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintBulk([{to: ethSigner, amount: 1}]).send(),
+ );
+
+ res['mintBulk'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.executeExtrinsic(donor, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
+ Fungible: new Map([
+ [JSON.stringify({Ethereum: ethSigner}), 1],
+ ]),
+ }], true),
+ )));
+
+ res['transfer*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transfer(ethReceiver, 1).send(),
+ );
+
+ res['transfer*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.transfer(ethReceiver, 1).send(),
+ );
+
+ res['transferCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
+ );
+
+ res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transfer(
+ donor,
+ {Substrate: subReceiver.address},
+ 1n,
+ ),
+ )));
+ await collection.approveTokens(subReceiver, {Substrate: donor.address}, 1n);
+
+ res['transferFrom*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
+ );
+
+ await zeppelelinContract!.methods.approve(ethSigner, 10).send({from: ethReceiver});
+
+ res['transferFrom*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 1).send({from: ethSigner}),
+ );
+
+ res['transferFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
+ );
+
+ res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transferFrom(donor, {Substrate: subReceiver.address}, {Substrate: donor.address}, 1n),
+ )));
+
+
+ res['burnTokens'] = {fee: 0n, gas: 0n};
+ res['burnTokens'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.burnTokens(donor, 1n),
+ )));
+
+
+ res['approve*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approve(ethReceiver, 2).send(),
+ );
+
+ res['approve*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.approve(ethReceiver, 10).send(),
+ );
+
+ res['approveCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approveCross(crossReceiver, 2).send(),
+ );
+
+ res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.approveTokens(donor, {Substrate: subReceiver.address}, 1n),
+ )));
+
+ res['burnFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.burnFromCross(crossSigner, 1).send({from:ethReceiver}),
+ );
+
+ res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.burnTokensFrom(subReceiver, {Substrate: donor.address}, 1n),
+ )));
+
+ res['setCollectionSponsorCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),
+ );
+
+ res['confirmCollectionSponsorship'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),
+ );
+
+ res['removeCollectionSponsor'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.removeCollectionSponsor().send(),
+ );
+
+ res['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setSponsor(donor, subReceiver.address),
+ )));
+
+ res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.confirmSponsorship(subReceiver),
+ )));
+
+ res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeSponsor(donor),
+ )));
+
+ res['setCollectionProperties'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),
+ );
+
+ res['deleteCollectionProperties'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),
+ );
+ res['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => ({key: p.key, value: p.value.toString()}))),
+ )));
+
+ res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => p.key)),
+ )));
+
+ res['setCollectionLimit'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
+ );
+
+ res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
+ )));
+
+ const {collectionAddress} = await helper.eth.createCollection(ethSigner, new CreateCollectionData('A', 'B', 'C', 'nft')).send();
+ const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);
+
+
+ res['addCollectionAdminCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),
+ );
+
+ res['removeCollectionAdminCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),
+ );
+
+ res['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['setCollectionNesting'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionNesting(true).send(),
+ );
+
+ res['setCollectionNesting[]'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),
+ );
+
+ res['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.disableNesting(donor),
+ )));
+
+ res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(
+ donor,
+ {
+ nesting: {
+ tokenOwner: true,
+ restricted: [collection.collectionId],
+ },
+ },
+ ),
+ )));
+
+ res['setCollectionAccess'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionAccess(1).send(),
+ );
+
+ res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {access: 'AllowList'}),
+ )));
+
+ res['addToCollectionAllowListCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),
+ );
+
+ res['removeFromCollectionAllowListCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),
+ );
+
+ res['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['setCollectionMintMode'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionMintMode(true).send(),
+ );
+
+ res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {mintMode: false}),
+ )));
+
+ res['changeCollectionOwnerCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
+ );
+
+ res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.changeOwner(donor, subReceiver.address),
+ )));
+
+ return res;
+}
js-packages/scripts/benchmarks/utils/common.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/common.ts
@@ -0,0 +1,88 @@
+import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/unique.js';
+import type {ITokenPropertyPermission, TCollectionMode} from '@unique/playgrounds/types.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+export const PROPERTIES = Array(40)
+ .fill(0)
+ .map((_, i) => ({
+ key: `key_${i}`,
+ value: Uint8Array.from(Buffer.from(`value_${i}`)),
+ }));
+
+export const SUBS_PROPERTIES = Array(40)
+ .fill(0)
+ .map((_, i) => ({
+ key: `key_${i}`,
+ value: `value_${i}`,
+ }));
+
+export const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => ({
+ key: p.key,
+ permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+}));
+
+export function convertToTokens(value: bigint, nominal = 1000_000_000_000_000_000n): number {
+ return Number((value * 1000n) / nominal) / 1000;
+}
+
+export async function createCollectionForBenchmarks(
+ mode : TCollectionMode,
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+ ethSigner: string,
+ proxyContract: string | null,
+ permissions: ITokenPropertyPermission[],
+) {
+ const donor = await privateKey('//Alice');
+
+ const collection = await helper[mode].mintCollection(donor, {
+ name: 'test mintToSubstrate',
+ description: 'EVMHelpers',
+ tokenPrefix: mode,
+ ...(mode != 'ft' ? {
+ tokenPropertyPermissions: [
+ {
+ key: 'url',
+ permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+ },
+ {
+ key: 'URI',
+ permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+ },
+ ],
+ } : {}),
+ limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},
+ permissions: {mintMode: true},
+ });
+
+ await collection.addToAllowList(donor, {
+ Ethereum: helper.address.substrateToEth(donor.address),
+ });
+ await collection.addToAllowList(donor, {Substrate: donor.address});
+ await collection.addAdmin(donor, {Ethereum: ethSigner});
+ await collection.addAdmin(donor, {
+ Ethereum: helper.address.substrateToEth(donor.address),
+ });
+
+ if(proxyContract) {
+ await collection.addToAllowList(donor, {Ethereum: proxyContract});
+ await collection.addAdmin(donor, {Ethereum: proxyContract});
+ }
+ if(collection instanceof UniqueNFTCollection || collection instanceof UniqueRFTCollection)
+ await collection.setTokenPropertyPermissions(donor, permissions);
+
+ return collection;
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/README.mddiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/README.md
@@ -0,0 +1,12 @@
+# OpenZeppelin Contracts
+
+The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
+
+They are not meant to be edited.
+
+The originals can be found on [GitHub] and [npm].
+
+[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
+[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
+
+Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/access/Ownable.sol
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../utils/Context.sol";
+
+/**
+ * @dev Contract module which provides a basic access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership}.
+ *
+ * This module is used through inheritance. It will make available the modifier
+ * `onlyOwner`, which can be applied to your functions to restrict their use to
+ * the owner.
+ */
+abstract contract Ownable is Context {
+ address private _owner;
+
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
+
+ /**
+ * @dev Initializes the contract setting the deployer as the initial owner.
+ */
+ constructor() {
+ _transferOwnership(_msgSender());
+ }
+
+ /**
+ * @dev Throws if called by any account other than the owner.
+ */
+ modifier onlyOwner() {
+ _checkOwner();
+ _;
+ }
+
+ /**
+ * @dev Returns the address of the current owner.
+ */
+ function owner() public view virtual returns (address) {
+ return _owner;
+ }
+
+ /**
+ * @dev Throws if the sender is not the owner.
+ */
+ function _checkOwner() internal view virtual {
+ require(owner() == _msgSender(), "Ownable: caller is not the owner");
+ }
+
+ /**
+ * @dev Leaves the contract without owner. It will not be possible to call
+ * `onlyOwner` functions anymore. Can only be called by the current owner.
+ *
+ * NOTE: Renouncing ownership will leave the contract without an owner,
+ * thereby removing any functionality that is only available to the owner.
+ */
+ function renounceOwnership() public virtual onlyOwner {
+ _transferOwnership(address(0));
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Can only be called by the current owner.
+ */
+ function transferOwnership(address newOwner) public virtual onlyOwner {
+ require(newOwner != address(0), "Ownable: new owner is the zero address");
+ _transferOwnership(newOwner);
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Internal function without access restriction.
+ */
+ function _transferOwnership(address newOwner) internal virtual {
+ address oldOwner = _owner;
+ _owner = newOwner;
+ emit OwnershipTransferred(oldOwner, newOwner);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/governance/utils/IVotes.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/governance/utils/IVotes.sol
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
+ *
+ * _Available since v4.5._
+ */
+interface IVotes {
+ /**
+ * @dev Emitted when an account changes their delegate.
+ */
+ event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
+
+ /**
+ * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
+ */
+ event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
+
+ /**
+ * @dev Returns the current amount of votes that `account` has.
+ */
+ function getVotes(address account) external view returns (uint256);
+
+ /**
+ * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
+ */
+ function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
+
+ /**
+ * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
+ *
+ * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
+ * Votes that have not been delegated are still part of total supply, even though they would not participate in a
+ * vote.
+ */
+ function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
+
+ /**
+ * @dev Returns the delegate that `account` has chosen.
+ */
+ function delegates(address account) external view returns (address);
+
+ /**
+ * @dev Delegates votes from the sender to `delegatee`.
+ */
+ function delegate(address delegatee) external;
+
+ /**
+ * @dev Delegates votes from signer to `delegatee`.
+ */
+ function delegateBySig(
+ address delegatee,
+ uint256 nonce,
+ uint256 expiry,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC3156 FlashBorrower, as defined in
+ * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
+ *
+ * _Available since v4.1._
+ */
+interface IERC3156FlashBorrower {
+ /**
+ * @dev Receive a flash loan.
+ * @param initiator The initiator of the loan.
+ * @param token The loan currency.
+ * @param amount The amount of tokens lent.
+ * @param fee The additional amount of tokens to repay.
+ * @param data Arbitrary data structure, intended to contain user-defined parameters.
+ * @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan"
+ */
+ function onFlashLoan(
+ address initiator,
+ address token,
+ uint256 amount,
+ uint256 fee,
+ bytes calldata data
+ ) external returns (bytes32);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashLender.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC3156FlashBorrower.sol";
+
+/**
+ * @dev Interface of the ERC3156 FlashLender, as defined in
+ * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
+ *
+ * _Available since v4.1._
+ */
+interface IERC3156FlashLender {
+ /**
+ * @dev The amount of currency available to be lended.
+ * @param token The loan currency.
+ * @return The amount of `token` that can be borrowed.
+ */
+ function maxFlashLoan(address token) external view returns (uint256);
+
+ /**
+ * @dev The fee to be charged for a given loan.
+ * @param token The loan currency.
+ * @param amount The amount of tokens lent.
+ * @return The amount of `token` to be charged for the loan, on top of the returned principal.
+ */
+ function flashFee(address token, uint256 amount) external view returns (uint256);
+
+ /**
+ * @dev Initiate a flash loan.
+ * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
+ * @param token The loan currency.
+ * @param amount The amount of tokens lent.
+ * @param data Arbitrary data structure, intended to contain user-defined parameters.
+ */
+ function flashLoan(
+ IERC3156FlashBorrower receiver,
+ address token,
+ uint256 amount,
+ bytes calldata data
+ ) external returns (bool);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/security/Pausable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/security/Pausable.sol
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../utils/Context.sol";
+
+/**
+ * @dev Contract module which allows children to implement an emergency stop
+ * mechanism that can be triggered by an authorized account.
+ *
+ * This module is used through inheritance. It will make available the
+ * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
+ * the functions of your contract. Note that they will not be pausable by
+ * simply including this module, only once the modifiers are put in place.
+ */
+abstract contract Pausable is Context {
+ /**
+ * @dev Emitted when the pause is triggered by `account`.
+ */
+ event Paused(address account);
+
+ /**
+ * @dev Emitted when the pause is lifted by `account`.
+ */
+ event Unpaused(address account);
+
+ bool private _paused;
+
+ /**
+ * @dev Initializes the contract in unpaused state.
+ */
+ constructor() {
+ _paused = false;
+ }
+
+ /**
+ * @dev Modifier to make a function callable only when the contract is not paused.
+ *
+ * Requirements:
+ *
+ * - The contract must not be paused.
+ */
+ modifier whenNotPaused() {
+ _requireNotPaused();
+ _;
+ }
+
+ /**
+ * @dev Modifier to make a function callable only when the contract is paused.
+ *
+ * Requirements:
+ *
+ * - The contract must be paused.
+ */
+ modifier whenPaused() {
+ _requirePaused();
+ _;
+ }
+
+ /**
+ * @dev Returns true if the contract is paused, and false otherwise.
+ */
+ function paused() public view virtual returns (bool) {
+ return _paused;
+ }
+
+ /**
+ * @dev Throws if the contract is paused.
+ */
+ function _requireNotPaused() internal view virtual {
+ require(!paused(), "Pausable: paused");
+ }
+
+ /**
+ * @dev Throws if the contract is not paused.
+ */
+ function _requirePaused() internal view virtual {
+ require(paused(), "Pausable: not paused");
+ }
+
+ /**
+ * @dev Triggers stopped state.
+ *
+ * Requirements:
+ *
+ * - The contract must not be paused.
+ */
+ function _pause() internal virtual whenNotPaused {
+ _paused = true;
+ emit Paused(_msgSender());
+ }
+
+ /**
+ * @dev Returns to normal state.
+ *
+ * Requirements:
+ *
+ * - The contract must be paused.
+ */
+ function _unpause() internal virtual whenPaused {
+ _paused = false;
+ emit Unpaused(_msgSender());
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/ERC20.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/ERC20.sol
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC20.sol";
+import "./extensions/IERC20Metadata.sol";
+import "../../utils/Context.sol";
+
+/**
+ * @dev Implementation of the {IERC20} interface.
+ *
+ * This implementation is agnostic to the way tokens are created. This means
+ * that a supply mechanism has to be added in a derived contract using {_mint}.
+ * For a generic mechanism see {ERC20PresetMinterPauser}.
+ *
+ * TIP: For a detailed writeup see our guide
+ * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
+ * to implement supply mechanisms].
+ *
+ * We have followed general OpenZeppelin Contracts guidelines: functions revert
+ * instead returning `false` on failure. This behavior is nonetheless
+ * conventional and does not conflict with the expectations of ERC20
+ * applications.
+ *
+ * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
+ * This allows applications to reconstruct the allowance for all accounts just
+ * by listening to said events. Other implementations of the EIP may not emit
+ * these events, as it isn't required by the specification.
+ *
+ * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
+ * functions have been added to mitigate the well-known issues around setting
+ * allowances. See {IERC20-approve}.
+ */
+contract ERC20 is Context, IERC20, IERC20Metadata {
+ mapping(address => uint256) private _balances;
+
+ mapping(address => mapping(address => uint256)) private _allowances;
+
+ uint256 private _totalSupply;
+
+ string private _name;
+ string private _symbol;
+
+ /**
+ * @dev Sets the values for {name} and {symbol}.
+ *
+ * The default value of {decimals} is 18. To select a different value for
+ * {decimals} you should overload it.
+ *
+ * All two of these values are immutable: they can only be set once during
+ * construction.
+ */
+ constructor(string memory name_, string memory symbol_) {
+ _name = name_;
+ _symbol = symbol_;
+ }
+
+ /**
+ * @dev Returns the name of the token.
+ */
+ function name() public view virtual override returns (string memory) {
+ return _name;
+ }
+
+ /**
+ * @dev Returns the symbol of the token, usually a shorter version of the
+ * name.
+ */
+ function symbol() public view virtual override returns (string memory) {
+ return _symbol;
+ }
+
+ /**
+ * @dev Returns the number of decimals used to get its user representation.
+ * For example, if `decimals` equals `2`, a balance of `505` tokens should
+ * be displayed to a user as `5.05` (`505 / 10 ** 2`).
+ *
+ * Tokens usually opt for a value of 18, imitating the relationship between
+ * Ether and Wei. This is the value {ERC20} uses, unless this function is
+ * overridden;
+ *
+ * NOTE: This information is only used for _display_ purposes: it in
+ * no way affects any of the arithmetic of the contract, including
+ * {IERC20-balanceOf} and {IERC20-transfer}.
+ */
+ function decimals() public view virtual override returns (uint8) {
+ return 18;
+ }
+
+ /**
+ * @dev See {IERC20-totalSupply}.
+ */
+ function totalSupply() public view virtual override returns (uint256) {
+ return _totalSupply;
+ }
+
+ /**
+ * @dev See {IERC20-balanceOf}.
+ */
+ function balanceOf(address account) public view virtual override returns (uint256) {
+ return _balances[account];
+ }
+
+ /**
+ * @dev See {IERC20-transfer}.
+ *
+ * Requirements:
+ *
+ * - `to` cannot be the zero address.
+ * - the caller must have a balance of at least `amount`.
+ */
+ function transfer(address to, uint256 amount) public virtual override returns (bool) {
+ address owner = _msgSender();
+ _transfer(owner, to, amount);
+ return true;
+ }
+
+ /**
+ * @dev See {IERC20-allowance}.
+ */
+ function allowance(address owner, address spender) public view virtual override returns (uint256) {
+ return _allowances[owner][spender];
+ }
+
+ /**
+ * @dev See {IERC20-approve}.
+ *
+ * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
+ * `transferFrom`. This is semantically equivalent to an infinite approval.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ */
+ function approve(address spender, uint256 amount) public virtual override returns (bool) {
+ address owner = _msgSender();
+ _approve(owner, spender, amount);
+ return true;
+ }
+
+ /**
+ * @dev See {IERC20-transferFrom}.
+ *
+ * Emits an {Approval} event indicating the updated allowance. This is not
+ * required by the EIP. See the note at the beginning of {ERC20}.
+ *
+ * NOTE: Does not update the allowance if the current allowance
+ * is the maximum `uint256`.
+ *
+ * Requirements:
+ *
+ * - `from` and `to` cannot be the zero address.
+ * - `from` must have a balance of at least `amount`.
+ * - the caller must have allowance for ``from``'s tokens of at least
+ * `amount`.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) public virtual override returns (bool) {
+ address spender = _msgSender();
+ _spendAllowance(from, spender, amount);
+ _transfer(from, to, amount);
+ return true;
+ }
+
+ /**
+ * @dev Atomically increases the allowance granted to `spender` by the caller.
+ *
+ * This is an alternative to {approve} that can be used as a mitigation for
+ * problems described in {IERC20-approve}.
+ *
+ * Emits an {Approval} event indicating the updated allowance.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ */
+ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
+ address owner = _msgSender();
+ _approve(owner, spender, allowance(owner, spender) + addedValue);
+ return true;
+ }
+
+ /**
+ * @dev Atomically decreases the allowance granted to `spender` by the caller.
+ *
+ * This is an alternative to {approve} that can be used as a mitigation for
+ * problems described in {IERC20-approve}.
+ *
+ * Emits an {Approval} event indicating the updated allowance.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ * - `spender` must have allowance for the caller of at least
+ * `subtractedValue`.
+ */
+ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
+ address owner = _msgSender();
+ uint256 currentAllowance = allowance(owner, spender);
+ require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
+ unchecked {
+ _approve(owner, spender, currentAllowance - subtractedValue);
+ }
+
+ return true;
+ }
+
+ /**
+ * @dev Moves `amount` of tokens from `from` to `to`.
+ *
+ * This internal function is equivalent to {transfer}, and can be used to
+ * e.g. implement automatic token fees, slashing mechanisms, etc.
+ *
+ * Emits a {Transfer} event.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `from` must have a balance of at least `amount`.
+ */
+ function _transfer(
+ address from,
+ address to,
+ uint256 amount
+ ) internal virtual {
+ require(from != address(0), "ERC20: transfer from the zero address");
+ require(to != address(0), "ERC20: transfer to the zero address");
+
+ _beforeTokenTransfer(from, to, amount);
+
+ uint256 fromBalance = _balances[from];
+ require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
+ unchecked {
+ _balances[from] = fromBalance - amount;
+ // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
+ // decrementing then incrementing.
+ _balances[to] += amount;
+ }
+
+ emit Transfer(from, to, amount);
+
+ _afterTokenTransfer(from, to, amount);
+ }
+
+ /** @dev Creates `amount` tokens and assigns them to `account`, increasing
+ * the total supply.
+ *
+ * Emits a {Transfer} event with `from` set to the zero address.
+ *
+ * Requirements:
+ *
+ * - `account` cannot be the zero address.
+ */
+ function _mint(address account, uint256 amount) internal virtual {
+ require(account != address(0), "ERC20: mint to the zero address");
+
+ _beforeTokenTransfer(address(0), account, amount);
+
+ _totalSupply += amount;
+ unchecked {
+ // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
+ _balances[account] += amount;
+ }
+ emit Transfer(address(0), account, amount);
+
+ _afterTokenTransfer(address(0), account, amount);
+ }
+
+ /**
+ * @dev Destroys `amount` tokens from `account`, reducing the
+ * total supply.
+ *
+ * Emits a {Transfer} event with `to` set to the zero address.
+ *
+ * Requirements:
+ *
+ * - `account` cannot be the zero address.
+ * - `account` must have at least `amount` tokens.
+ */
+ function _burn(address account, uint256 amount) internal virtual {
+ require(account != address(0), "ERC20: burn from the zero address");
+
+ _beforeTokenTransfer(account, address(0), amount);
+
+ uint256 accountBalance = _balances[account];
+ require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
+ unchecked {
+ _balances[account] = accountBalance - amount;
+ // Overflow not possible: amount <= accountBalance <= totalSupply.
+ _totalSupply -= amount;
+ }
+
+ emit Transfer(account, address(0), amount);
+
+ _afterTokenTransfer(account, address(0), amount);
+ }
+
+ /**
+ * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
+ *
+ * This internal function is equivalent to `approve`, and can be used to
+ * e.g. set automatic allowances for certain subsystems, etc.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `owner` cannot be the zero address.
+ * - `spender` cannot be the zero address.
+ */
+ function _approve(
+ address owner,
+ address spender,
+ uint256 amount
+ ) internal virtual {
+ require(owner != address(0), "ERC20: approve from the zero address");
+ require(spender != address(0), "ERC20: approve to the zero address");
+
+ _allowances[owner][spender] = amount;
+ emit Approval(owner, spender, amount);
+ }
+
+ /**
+ * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
+ *
+ * Does not update the allowance amount in case of infinite allowance.
+ * Revert if not enough allowance is available.
+ *
+ * Might emit an {Approval} event.
+ */
+ function _spendAllowance(
+ address owner,
+ address spender,
+ uint256 amount
+ ) internal virtual {
+ uint256 currentAllowance = allowance(owner, spender);
+ if (currentAllowance != type(uint256).max) {
+ require(currentAllowance >= amount, "ERC20: insufficient allowance");
+ unchecked {
+ _approve(owner, spender, currentAllowance - amount);
+ }
+ }
+ }
+
+ /**
+ * @dev Hook that is called before any transfer of tokens. This includes
+ * minting and burning.
+ *
+ * Calling conditions:
+ *
+ * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+ * will be transferred to `to`.
+ * - when `from` is zero, `amount` tokens will be minted for `to`.
+ * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
+ * - `from` and `to` are never both zero.
+ *
+ * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+ */
+ function _beforeTokenTransfer(
+ address from,
+ address to,
+ uint256 amount
+ ) internal virtual {}
+
+ /**
+ * @dev Hook that is called after any transfer of tokens. This includes
+ * minting and burning.
+ *
+ * Calling conditions:
+ *
+ * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+ * has been transferred to `to`.
+ * - when `from` is zero, `amount` tokens have been minted for `to`.
+ * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
+ * - `from` and `to` are never both zero.
+ *
+ * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+ */
+ function _afterTokenTransfer(
+ address from,
+ address to,
+ uint256 amount
+ ) internal virtual {}
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/IERC20.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/IERC20.sol
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+ /**
+ * @dev Emitted when `value` tokens are moved from one account (`from`) to
+ * another (`to`).
+ *
+ * Note that `value` may be zero.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 value);
+
+ /**
+ * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+ * a call to {approve}. `value` is the new allowance.
+ */
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ /**
+ * @dev Returns the amount of tokens in existence.
+ */
+ function totalSupply() external view returns (uint256);
+
+ /**
+ * @dev Returns the amount of tokens owned by `account`.
+ */
+ function balanceOf(address account) external view returns (uint256);
+
+ /**
+ * @dev Moves `amount` tokens from the caller's account to `to`.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Returns the remaining number of tokens that `spender` will be
+ * allowed to spend on behalf of `owner` through {transferFrom}. This is
+ * zero by default.
+ *
+ * This value changes when {approve} or {transferFrom} are called.
+ */
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ /**
+ * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * IMPORTANT: Beware that changing an allowance with this method brings the risk
+ * that someone may use both the old and the new allowance by unfortunate
+ * transaction ordering. One possible solution to mitigate this race
+ * condition is to first reduce the spender's allowance to 0 and set the
+ * desired value afterwards:
+ * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /**
+ * @dev Moves `amount` tokens from `from` to `to` using the
+ * allowance mechanism. `amount` is then deducted from the caller's
+ * allowance.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC20.sol";
+import "../../../utils/Context.sol";
+
+/**
+ * @dev Extension of {ERC20} that allows token holders to destroy both their own
+ * tokens and those that they have an allowance for, in a way that can be
+ * recognized off-chain (via event analysis).
+ */
+abstract contract ERC20Burnable is Context, ERC20 {
+ /**
+ * @dev Destroys `amount` tokens from the caller.
+ *
+ * See {ERC20-_burn}.
+ */
+ function burn(uint256 amount) public virtual {
+ _burn(_msgSender(), amount);
+ }
+
+ /**
+ * @dev Destroys `amount` tokens from `account`, deducting from the caller's
+ * allowance.
+ *
+ * See {ERC20-_burn} and {ERC20-allowance}.
+ *
+ * Requirements:
+ *
+ * - the caller must have allowance for ``accounts``'s tokens of at least
+ * `amount`.
+ */
+ function burnFrom(address account, uint256 amount) public virtual {
+ _spendAllowance(account, _msgSender(), amount);
+ _burn(account, amount);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20FlashMint.sol)
+
+pragma solidity ^0.8.0;
+
+import "../../../interfaces/IERC3156FlashBorrower.sol";
+import "../../../interfaces/IERC3156FlashLender.sol";
+import "../ERC20.sol";
+
+/**
+ * @dev Implementation of the ERC3156 Flash loans extension, as defined in
+ * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
+ *
+ * Adds the {flashLoan} method, which provides flash loan support at the token
+ * level. By default there is no fee, but this can be changed by overriding {flashFee}.
+ *
+ * _Available since v4.1._
+ */
+abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
+ bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
+
+ /**
+ * @dev Returns the maximum amount of tokens available for loan.
+ * @param token The address of the token that is requested.
+ * @return The amount of token that can be loaned.
+ */
+ function maxFlashLoan(address token) public view virtual override returns (uint256) {
+ return token == address(this) ? type(uint256).max - ERC20.totalSupply() : 0;
+ }
+
+ /**
+ * @dev Returns the fee applied when doing flash loans. This function calls
+ * the {_flashFee} function which returns the fee applied when doing flash
+ * loans.
+ * @param token The token to be flash loaned.
+ * @param amount The amount of tokens to be loaned.
+ * @return The fees applied to the corresponding flash loan.
+ */
+ function flashFee(address token, uint256 amount) public view virtual override returns (uint256) {
+ require(token == address(this), "ERC20FlashMint: wrong token");
+ return _flashFee(token, amount);
+ }
+
+ /**
+ * @dev Returns the fee applied when doing flash loans. By default this
+ * implementation has 0 fees. This function can be overloaded to make
+ * the flash loan mechanism deflationary.
+ * @param token The token to be flash loaned.
+ * @param amount The amount of tokens to be loaned.
+ * @return The fees applied to the corresponding flash loan.
+ */
+ function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) {
+ // silence warning about unused variable without the addition of bytecode.
+ token;
+ amount;
+ return 0;
+ }
+
+ /**
+ * @dev Returns the receiver address of the flash fee. By default this
+ * implementation returns the address(0) which means the fee amount will be burnt.
+ * This function can be overloaded to change the fee receiver.
+ * @return The address for which the flash fee will be sent to.
+ */
+ function _flashFeeReceiver() internal view virtual returns (address) {
+ return address(0);
+ }
+
+ /**
+ * @dev Performs a flash loan. New tokens are minted and sent to the
+ * `receiver`, who is required to implement the {IERC3156FlashBorrower}
+ * interface. By the end of the flash loan, the receiver is expected to own
+ * amount + fee tokens and have them approved back to the token contract itself so
+ * they can be burned.
+ * @param receiver The receiver of the flash loan. Should implement the
+ * {IERC3156FlashBorrower-onFlashLoan} interface.
+ * @param token The token to be flash loaned. Only `address(this)` is
+ * supported.
+ * @param amount The amount of tokens to be loaned.
+ * @param data An arbitrary datafield that is passed to the receiver.
+ * @return `true` if the flash loan was successful.
+ */
+ // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount
+ // minted at the beginning is always recovered and burned at the end, or else the entire function will revert.
+ // slither-disable-next-line reentrancy-no-eth
+ function flashLoan(
+ IERC3156FlashBorrower receiver,
+ address token,
+ uint256 amount,
+ bytes calldata data
+ ) public virtual override returns (bool) {
+ require(amount <= maxFlashLoan(token), "ERC20FlashMint: amount exceeds maxFlashLoan");
+ uint256 fee = flashFee(token, amount);
+ _mint(address(receiver), amount);
+ require(
+ receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE,
+ "ERC20FlashMint: invalid return value"
+ );
+ address flashFeeReceiver = _flashFeeReceiver();
+ _spendAllowance(address(receiver), address(this), amount + fee);
+ if (fee == 0 || flashFeeReceiver == address(0)) {
+ _burn(address(receiver), amount + fee);
+ } else {
+ _burn(address(receiver), amount);
+ _transfer(address(receiver), flashFeeReceiver, fee);
+ }
+ return true;
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol)
+
+pragma solidity ^0.8.0;
+
+import "./draft-ERC20Permit.sol";
+import "../../../utils/math/Math.sol";
+import "../../../governance/utils/IVotes.sol";
+import "../../../utils/math/SafeCast.sol";
+import "../../../utils/cryptography/ECDSA.sol";
+
+/**
+ * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
+ * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
+ *
+ * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
+ *
+ * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
+ * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
+ * power can be queried through the public accessors {getVotes} and {getPastVotes}.
+ *
+ * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
+ * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
+ *
+ * _Available since v4.2._
+ */
+abstract contract ERC20Votes is IVotes, ERC20Permit {
+ struct Checkpoint {
+ uint32 fromBlock;
+ uint224 votes;
+ }
+
+ bytes32 private constant _DELEGATION_TYPEHASH =
+ keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
+
+ mapping(address => address) private _delegates;
+ mapping(address => Checkpoint[]) private _checkpoints;
+ Checkpoint[] private _totalSupplyCheckpoints;
+
+ /**
+ * @dev Get the `pos`-th checkpoint for `account`.
+ */
+ function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
+ return _checkpoints[account][pos];
+ }
+
+ /**
+ * @dev Get number of checkpoints for `account`.
+ */
+ function numCheckpoints(address account) public view virtual returns (uint32) {
+ return SafeCast.toUint32(_checkpoints[account].length);
+ }
+
+ /**
+ * @dev Get the address `account` is currently delegating to.
+ */
+ function delegates(address account) public view virtual override returns (address) {
+ return _delegates[account];
+ }
+
+ /**
+ * @dev Gets the current votes balance for `account`
+ */
+ function getVotes(address account) public view virtual override returns (uint256) {
+ uint256 pos = _checkpoints[account].length;
+ return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
+ }
+
+ /**
+ * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
+ *
+ * Requirements:
+ *
+ * - `blockNumber` must have been already mined
+ */
+ function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
+ require(blockNumber < block.number, "ERC20Votes: block not yet mined");
+ return _checkpointsLookup(_checkpoints[account], blockNumber);
+ }
+
+ /**
+ * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
+ * It is but NOT the sum of all the delegated votes!
+ *
+ * Requirements:
+ *
+ * - `blockNumber` must have been already mined
+ */
+ function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
+ require(blockNumber < block.number, "ERC20Votes: block not yet mined");
+ return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
+ }
+
+ /**
+ * @dev Lookup a value in a list of (sorted) checkpoints.
+ */
+ function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
+ // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
+ //
+ // Initially we check if the block is recent to narrow the search range.
+ // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
+ // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
+ // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
+ // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
+ // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
+ // out of bounds (in which case we're looking too far in the past and the result is 0).
+ // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
+ // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
+ // the same.
+ uint256 length = ckpts.length;
+
+ uint256 low = 0;
+ uint256 high = length;
+
+ if (length > 5) {
+ uint256 mid = length - Math.sqrt(length);
+ if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
+ high = mid;
+ } else {
+ low = mid + 1;
+ }
+ }
+
+ while (low < high) {
+ uint256 mid = Math.average(low, high);
+ if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
+ high = mid;
+ } else {
+ low = mid + 1;
+ }
+ }
+
+ return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
+ }
+
+ /**
+ * @dev Delegate votes from the sender to `delegatee`.
+ */
+ function delegate(address delegatee) public virtual override {
+ _delegate(_msgSender(), delegatee);
+ }
+
+ /**
+ * @dev Delegates votes from signer to `delegatee`
+ */
+ function delegateBySig(
+ address delegatee,
+ uint256 nonce,
+ uint256 expiry,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) public virtual override {
+ require(block.timestamp <= expiry, "ERC20Votes: signature expired");
+ address signer = ECDSA.recover(
+ _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
+ v,
+ r,
+ s
+ );
+ require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
+ _delegate(signer, delegatee);
+ }
+
+ /**
+ * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
+ */
+ function _maxSupply() internal view virtual returns (uint224) {
+ return type(uint224).max;
+ }
+
+ /**
+ * @dev Snapshots the totalSupply after it has been increased.
+ */
+ function _mint(address account, uint256 amount) internal virtual override {
+ super._mint(account, amount);
+ require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
+
+ _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
+ }
+
+ /**
+ * @dev Snapshots the totalSupply after it has been decreased.
+ */
+ function _burn(address account, uint256 amount) internal virtual override {
+ super._burn(account, amount);
+
+ _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
+ }
+
+ /**
+ * @dev Move voting power when tokens are transferred.
+ *
+ * Emits a {IVotes-DelegateVotesChanged} event.
+ */
+ function _afterTokenTransfer(
+ address from,
+ address to,
+ uint256 amount
+ ) internal virtual override {
+ super._afterTokenTransfer(from, to, amount);
+
+ _moveVotingPower(delegates(from), delegates(to), amount);
+ }
+
+ /**
+ * @dev Change delegation for `delegator` to `delegatee`.
+ *
+ * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
+ */
+ function _delegate(address delegator, address delegatee) internal virtual {
+ address currentDelegate = delegates(delegator);
+ uint256 delegatorBalance = balanceOf(delegator);
+ _delegates[delegator] = delegatee;
+
+ emit DelegateChanged(delegator, currentDelegate, delegatee);
+
+ _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
+ }
+
+ function _moveVotingPower(
+ address src,
+ address dst,
+ uint256 amount
+ ) private {
+ if (src != dst && amount > 0) {
+ if (src != address(0)) {
+ (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
+ emit DelegateVotesChanged(src, oldWeight, newWeight);
+ }
+
+ if (dst != address(0)) {
+ (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
+ emit DelegateVotesChanged(dst, oldWeight, newWeight);
+ }
+ }
+ }
+
+ function _writeCheckpoint(
+ Checkpoint[] storage ckpts,
+ function(uint256, uint256) view returns (uint256) op,
+ uint256 delta
+ ) private returns (uint256 oldWeight, uint256 newWeight) {
+ uint256 pos = ckpts.length;
+
+ Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
+
+ oldWeight = oldCkpt.votes;
+ newWeight = op(oldWeight, delta);
+
+ if (pos > 0 && oldCkpt.fromBlock == block.number) {
+ _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
+ } else {
+ ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
+ }
+ }
+
+ function _add(uint256 a, uint256 b) private pure returns (uint256) {
+ return a + b;
+ }
+
+ function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
+ return a - b;
+ }
+
+ /**
+ * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+ */
+ function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
+ assembly {
+ mstore(0, ckpts.slot)
+ result.slot := add(keccak256(0, 0x20), pos)
+ }
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
+
+pragma solidity ^0.8.0;
+
+import "../IERC20.sol";
+
+/**
+ * @dev Interface for the optional metadata functions from the ERC20 standard.
+ *
+ * _Available since v4.1._
+ */
+interface IERC20Metadata is IERC20 {
+ /**
+ * @dev Returns the name of the token.
+ */
+ function name() external view returns (string memory);
+
+ /**
+ * @dev Returns the symbol of the token.
+ */
+ function symbol() external view returns (string memory);
+
+ /**
+ * @dev Returns the decimals places of the token.
+ */
+ function decimals() external view returns (uint8);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)
+
+pragma solidity ^0.8.0;
+
+import "./draft-IERC20Permit.sol";
+import "../ERC20.sol";
+import "../../../utils/cryptography/ECDSA.sol";
+import "../../../utils/cryptography/EIP712.sol";
+import "../../../utils/Counters.sol";
+
+/**
+ * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ *
+ * _Available since v3.4._
+ */
+abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
+ using Counters for Counters.Counter;
+
+ mapping(address => Counters.Counter) private _nonces;
+
+ // solhint-disable-next-line var-name-mixedcase
+ bytes32 private constant _PERMIT_TYPEHASH =
+ keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
+ /**
+ * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
+ * However, to ensure consistency with the upgradeable transpiler, we will continue
+ * to reserve a slot.
+ * @custom:oz-renamed-from _PERMIT_TYPEHASH
+ */
+ // solhint-disable-next-line var-name-mixedcase
+ bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
+
+ /**
+ * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
+ *
+ * It's a good idea to use the same `name` that is defined as the ERC20 token name.
+ */
+ constructor(string memory name) EIP712(name, "1") {}
+
+ /**
+ * @dev See {IERC20Permit-permit}.
+ */
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) public virtual override {
+ require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
+
+ bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
+
+ bytes32 hash = _hashTypedDataV4(structHash);
+
+ address signer = ECDSA.recover(hash, v, r, s);
+ require(signer == owner, "ERC20Permit: invalid signature");
+
+ _approve(owner, spender, value);
+ }
+
+ /**
+ * @dev See {IERC20Permit-nonces}.
+ */
+ function nonces(address owner) public view virtual override returns (uint256) {
+ return _nonces[owner].current();
+ }
+
+ /**
+ * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function DOMAIN_SEPARATOR() external view override returns (bytes32) {
+ return _domainSeparatorV4();
+ }
+
+ /**
+ * @dev "Consume a nonce": return the current value and increment.
+ *
+ * _Available since v4.1._
+ */
+ function _useNonce(address owner) internal virtual returns (uint256 current) {
+ Counters.Counter storage nonce = _nonces[owner];
+ current = nonce.current();
+ nonce.increment();
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ */
+interface IERC20Permit {
+ /**
+ * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+ * given ``owner``'s signed approval.
+ *
+ * IMPORTANT: The same issues {IERC20-approve} has related to transaction
+ * ordering also apply here.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ * - `deadline` must be a timestamp in the future.
+ * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+ * over the EIP712-formatted function arguments.
+ * - the signature must use ``owner``'s current nonce (see {nonces}).
+ *
+ * For more information on the signature format, see the
+ * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+ * section].
+ */
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+
+ /**
+ * @dev Returns the current nonce for `owner`. This value must be
+ * included whenever a signature is generated for {permit}.
+ *
+ * Every successful call to {permit} increases ``owner``'s nonce by one. This
+ * prevents a signature from being used multiple times.
+ */
+ function nonces(address owner) external view returns (uint256);
+
+ /**
+ * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function DOMAIN_SEPARATOR() external view returns (bytes32);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Context.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+ function _msgSender() internal view virtual returns (address) {
+ return msg.sender;
+ }
+
+ function _msgData() internal view virtual returns (bytes calldata) {
+ return msg.data;
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Counters.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @title Counters
+ * @author Matt Condon (@shrugs)
+ * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
+ * of elements in a mapping, issuing ERC721 ids, or counting request ids.
+ *
+ * Include with `using Counters for Counters.Counter;`
+ */
+library Counters {
+ struct Counter {
+ // This variable should never be directly accessed by users of the library: interactions must be restricted to
+ // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
+ // this feature: see https://github.com/ethereum/solidity/issues/4637
+ uint256 _value; // default: 0
+ }
+
+ function current(Counter storage counter) internal view returns (uint256) {
+ return counter._value;
+ }
+
+ function increment(Counter storage counter) internal {
+ unchecked {
+ counter._value += 1;
+ }
+ }
+
+ function decrement(Counter storage counter) internal {
+ uint256 value = counter._value;
+ require(value > 0, "Counter: decrement overflow");
+ unchecked {
+ counter._value = value - 1;
+ }
+ }
+
+ function reset(Counter storage counter) internal {
+ counter._value = 0;
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Strings.sol
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
+
+pragma solidity ^0.8.0;
+
+import "./math/Math.sol";
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+ bytes16 private constant _SYMBOLS = "0123456789abcdef";
+ uint8 private constant _ADDRESS_LENGTH = 20;
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+ */
+ function toString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ uint256 length = Math.log10(value) + 1;
+ string memory buffer = new string(length);
+ uint256 ptr;
+ /// @solidity memory-safe-assembly
+ assembly {
+ ptr := add(buffer, add(32, length))
+ }
+ while (true) {
+ ptr--;
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+ }
+ value /= 10;
+ if (value == 0) break;
+ }
+ return buffer;
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+ */
+ function toHexString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ return toHexString(value, Math.log256(value) + 1);
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+ */
+ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+ bytes memory buffer = new bytes(2 * length + 2);
+ buffer[0] = "0";
+ buffer[1] = "x";
+ for (uint256 i = 2 * length + 1; i > 1; --i) {
+ buffer[i] = _SYMBOLS[value & 0xf];
+ value >>= 4;
+ }
+ require(value == 0, "Strings: hex length insufficient");
+ return string(buffer);
+ }
+
+ /**
+ * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
+ */
+ function toHexString(address addr) internal pure returns (string memory) {
+ return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/ECDSA.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/ECDSA.sol
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
+
+pragma solidity ^0.8.0;
+
+import "../Strings.sol";
+
+/**
+ * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
+ *
+ * These functions can be used to verify that a message was signed by the holder
+ * of the private keys of a given address.
+ */
+library ECDSA {
+ enum RecoverError {
+ NoError,
+ InvalidSignature,
+ InvalidSignatureLength,
+ InvalidSignatureS,
+ InvalidSignatureV // Deprecated in v4.8
+ }
+
+ function _throwError(RecoverError error) private pure {
+ if (error == RecoverError.NoError) {
+ return; // no error: do nothing
+ } else if (error == RecoverError.InvalidSignature) {
+ revert("ECDSA: invalid signature");
+ } else if (error == RecoverError.InvalidSignatureLength) {
+ revert("ECDSA: invalid signature length");
+ } else if (error == RecoverError.InvalidSignatureS) {
+ revert("ECDSA: invalid signature 's' value");
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature` or error string. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {toEthSignedMessageHash} on it.
+ *
+ * Documentation for signature generation:
+ * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
+ * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
+ if (signature.length == 65) {
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+ // ecrecover takes the signature parameters, and the only way to get them
+ // currently is to use assembly.
+ /// @solidity memory-safe-assembly
+ assembly {
+ r := mload(add(signature, 0x20))
+ s := mload(add(signature, 0x40))
+ v := byte(0, mload(add(signature, 0x60)))
+ }
+ return tryRecover(hash, v, r, s);
+ } else {
+ return (address(0), RecoverError.InvalidSignatureLength);
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature`. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {toEthSignedMessageHash} on it.
+ */
+ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, signature);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
+ *
+ * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(
+ bytes32 hash,
+ bytes32 r,
+ bytes32 vs
+ ) internal pure returns (address, RecoverError) {
+ bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
+ uint8 v = uint8((uint256(vs) >> 255) + 27);
+ return tryRecover(hash, v, r, s);
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
+ *
+ * _Available since v4.2._
+ */
+ function recover(
+ bytes32 hash,
+ bytes32 r,
+ bytes32 vs
+ ) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, r, vs);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ *
+ * _Available since v4.3._
+ */
+ function tryRecover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address, RecoverError) {
+ // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
+ // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
+ // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
+ // signatures from current libraries generate a unique signature with an s-value in the lower half order.
+ //
+ // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
+ // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
+ // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
+ // these malleable signatures as well.
+ if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
+ return (address(0), RecoverError.InvalidSignatureS);
+ }
+
+ // If the signature is valid (and not malleable), return the signer address
+ address signer = ecrecover(hash, v, r, s);
+ if (signer == address(0)) {
+ return (address(0), RecoverError.InvalidSignature);
+ }
+
+ return (signer, RecoverError.NoError);
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ */
+ function recover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address) {
+ (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
+ _throwError(error);
+ return recovered;
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Message, created from a `hash`. This
+ * produces hash corresponding to the one signed with the
+ * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+ * JSON-RPC method as part of EIP-191.
+ *
+ * See {recover}.
+ */
+ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
+ // 32 is the length in bytes of hash,
+ // enforced by the type signature above
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Message, created from `s`. This
+ * produces hash corresponding to the one signed with the
+ * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+ * JSON-RPC method as part of EIP-191.
+ *
+ * See {recover}.
+ */
+ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
+ }
+
+ /**
+ * @dev Returns an Ethereum Signed Typed Data, created from a
+ * `domainSeparator` and a `structHash`. This produces hash corresponding
+ * to the one signed with the
+ * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
+ * JSON-RPC method as part of EIP-712.
+ *
+ * See {recover}.
+ */
+ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/EIP712.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/EIP712.sol
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
+
+pragma solidity ^0.8.0;
+
+import "./ECDSA.sol";
+
+/**
+ * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
+ *
+ * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
+ * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
+ * they need in their contracts using a combination of `abi.encode` and `keccak256`.
+ *
+ * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
+ * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
+ * ({_hashTypedDataV4}).
+ *
+ * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
+ * the chain id to protect against replay attacks on an eventual fork of the chain.
+ *
+ * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
+ * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
+ *
+ * _Available since v3.4._
+ */
+abstract contract EIP712 {
+ /* solhint-disable var-name-mixedcase */
+ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
+ // invalidate the cached domain separator if the chain id changes.
+ bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
+ uint256 private immutable _CACHED_CHAIN_ID;
+ address private immutable _CACHED_THIS;
+
+ bytes32 private immutable _HASHED_NAME;
+ bytes32 private immutable _HASHED_VERSION;
+ bytes32 private immutable _TYPE_HASH;
+
+ /* solhint-enable var-name-mixedcase */
+
+ /**
+ * @dev Initializes the domain separator and parameter caches.
+ *
+ * The meaning of `name` and `version` is specified in
+ * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
+ *
+ * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
+ * - `version`: the current major version of the signing domain.
+ *
+ * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
+ * contract upgrade].
+ */
+ constructor(string memory name, string memory version) {
+ bytes32 hashedName = keccak256(bytes(name));
+ bytes32 hashedVersion = keccak256(bytes(version));
+ bytes32 typeHash = keccak256(
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
+ );
+ _HASHED_NAME = hashedName;
+ _HASHED_VERSION = hashedVersion;
+ _CACHED_CHAIN_ID = block.chainid;
+ _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
+ _CACHED_THIS = address(this);
+ _TYPE_HASH = typeHash;
+ }
+
+ /**
+ * @dev Returns the domain separator for the current chain.
+ */
+ function _domainSeparatorV4() internal view returns (bytes32) {
+ if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
+ return _CACHED_DOMAIN_SEPARATOR;
+ } else {
+ return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
+ }
+ }
+
+ function _buildDomainSeparator(
+ bytes32 typeHash,
+ bytes32 nameHash,
+ bytes32 versionHash
+ ) private view returns (bytes32) {
+ return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
+ }
+
+ /**
+ * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
+ * function returns the hash of the fully encoded EIP712 message for this domain.
+ *
+ * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
+ *
+ * ```solidity
+ * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
+ * keccak256("Mail(address to,string contents)"),
+ * mailTo,
+ * keccak256(bytes(mailContents))
+ * )));
+ * address signer = ECDSA.recover(digest, signature);
+ * ```
+ */
+ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
+ return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/Math.sol
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+ enum Rounding {
+ Down, // Toward negative infinity
+ Up, // Toward infinity
+ Zero // Toward zero
+ }
+
+ /**
+ * @dev Returns the largest of two numbers.
+ */
+ function max(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a > b ? a : b;
+ }
+
+ /**
+ * @dev Returns the smallest of two numbers.
+ */
+ function min(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a < b ? a : b;
+ }
+
+ /**
+ * @dev Returns the average of two numbers. The result is rounded towards
+ * zero.
+ */
+ function average(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b) / 2 can overflow.
+ return (a & b) + (a ^ b) / 2;
+ }
+
+ /**
+ * @dev Returns the ceiling of the division of two numbers.
+ *
+ * This differs from standard division with `/` in that it rounds up instead
+ * of rounding down.
+ */
+ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b - 1) / b can overflow on addition, so we distribute.
+ return a == 0 ? 0 : (a - 1) / b + 1;
+ }
+
+ /**
+ * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
+ * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
+ * with further edits by Uniswap Labs also under MIT license.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator
+ ) internal pure returns (uint256 result) {
+ unchecked {
+ // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+ // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+ // variables such that product = prod1 * 2^256 + prod0.
+ uint256 prod0; // Least significant 256 bits of the product
+ uint256 prod1; // Most significant 256 bits of the product
+ assembly {
+ let mm := mulmod(x, y, not(0))
+ prod0 := mul(x, y)
+ prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+ }
+
+ // Handle non-overflow cases, 256 by 256 division.
+ if (prod1 == 0) {
+ return prod0 / denominator;
+ }
+
+ // Make sure the result is less than 2^256. Also prevents denominator == 0.
+ require(denominator > prod1);
+
+ ///////////////////////////////////////////////
+ // 512 by 256 division.
+ ///////////////////////////////////////////////
+
+ // Make division exact by subtracting the remainder from [prod1 prod0].
+ uint256 remainder;
+ assembly {
+ // Compute remainder using mulmod.
+ remainder := mulmod(x, y, denominator)
+
+ // Subtract 256 bit number from 512 bit number.
+ prod1 := sub(prod1, gt(remainder, prod0))
+ prod0 := sub(prod0, remainder)
+ }
+
+ // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
+ // See https://cs.stackexchange.com/q/138556/92363.
+
+ // Does not overflow because the denominator cannot be zero at this stage in the function.
+ uint256 twos = denominator & (~denominator + 1);
+ assembly {
+ // Divide denominator by twos.
+ denominator := div(denominator, twos)
+
+ // Divide [prod1 prod0] by twos.
+ prod0 := div(prod0, twos)
+
+ // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+ twos := add(div(sub(0, twos), twos), 1)
+ }
+
+ // Shift in bits from prod1 into prod0.
+ prod0 |= prod1 * twos;
+
+ // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+ // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+ // four bits. That is, denominator * inv = 1 mod 2^4.
+ uint256 inverse = (3 * denominator) ^ 2;
+
+ // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
+ // in modular arithmetic, doubling the correct bits in each step.
+ inverse *= 2 - denominator * inverse; // inverse mod 2^8
+ inverse *= 2 - denominator * inverse; // inverse mod 2^16
+ inverse *= 2 - denominator * inverse; // inverse mod 2^32
+ inverse *= 2 - denominator * inverse; // inverse mod 2^64
+ inverse *= 2 - denominator * inverse; // inverse mod 2^128
+ inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+ // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+ // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+ // is no longer required.
+ result = prod0 * inverse;
+ return result;
+ }
+ }
+
+ /**
+ * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator,
+ Rounding rounding
+ ) internal pure returns (uint256) {
+ uint256 result = mulDiv(x, y, denominator);
+ if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
+ result += 1;
+ }
+ return result;
+ }
+
+ /**
+ * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
+ *
+ * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+ */
+ function sqrt(uint256 a) internal pure returns (uint256) {
+ if (a == 0) {
+ return 0;
+ }
+
+ // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+ //
+ // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+ // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+ //
+ // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+ // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+ // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+ //
+ // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+ uint256 result = 1 << (log2(a) >> 1);
+
+ // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+ // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+ // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+ // into the expected uint128 result.
+ unchecked {
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ return min(result, a / result);
+ }
+ }
+
+ /**
+ * @notice Calculates sqrt(a), following the selected rounding direction.
+ */
+ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = sqrt(a);
+ return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 2, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 128;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 64;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 32;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 16;
+ }
+ if (value >> 8 > 0) {
+ value >>= 8;
+ result += 8;
+ }
+ if (value >> 4 > 0) {
+ value >>= 4;
+ result += 4;
+ }
+ if (value >> 2 > 0) {
+ value >>= 2;
+ result += 2;
+ }
+ if (value >> 1 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log2(value);
+ return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 10, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >= 10**64) {
+ value /= 10**64;
+ result += 64;
+ }
+ if (value >= 10**32) {
+ value /= 10**32;
+ result += 32;
+ }
+ if (value >= 10**16) {
+ value /= 10**16;
+ result += 16;
+ }
+ if (value >= 10**8) {
+ value /= 10**8;
+ result += 8;
+ }
+ if (value >= 10**4) {
+ value /= 10**4;
+ result += 4;
+ }
+ if (value >= 10**2) {
+ value /= 10**2;
+ result += 2;
+ }
+ if (value >= 10**1) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log10(value);
+ return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 256, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ *
+ * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+ */
+ function log256(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 16;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 8;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 4;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 2;
+ }
+ if (value >> 8 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log256(value);
+ return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
+ }
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/SafeCast.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/SafeCast.sol
@@ -0,0 +1,1136 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
+// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
+ * checks.
+ *
+ * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
+ * easily result in undesired exploitation or bugs, since developers usually
+ * assume that overflows raise errors. `SafeCast` restores this intuition by
+ * reverting the transaction when such an operation overflows.
+ *
+ * Using this library instead of the unchecked operations eliminates an entire
+ * class of bugs, so it's recommended to use it always.
+ *
+ * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
+ * all math on `uint256` and `int256` and then downcasting.
+ */
+library SafeCast {
+ /**
+ * @dev Returns the downcasted uint248 from uint256, reverting on
+ * overflow (when the input is greater than largest uint248).
+ *
+ * Counterpart to Solidity's `uint248` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 248 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint248(uint256 value) internal pure returns (uint248) {
+ require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
+ return uint248(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint240 from uint256, reverting on
+ * overflow (when the input is greater than largest uint240).
+ *
+ * Counterpart to Solidity's `uint240` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 240 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint240(uint256 value) internal pure returns (uint240) {
+ require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
+ return uint240(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint232 from uint256, reverting on
+ * overflow (when the input is greater than largest uint232).
+ *
+ * Counterpart to Solidity's `uint232` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 232 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint232(uint256 value) internal pure returns (uint232) {
+ require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
+ return uint232(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint224 from uint256, reverting on
+ * overflow (when the input is greater than largest uint224).
+ *
+ * Counterpart to Solidity's `uint224` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 224 bits
+ *
+ * _Available since v4.2._
+ */
+ function toUint224(uint256 value) internal pure returns (uint224) {
+ require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
+ return uint224(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint216 from uint256, reverting on
+ * overflow (when the input is greater than largest uint216).
+ *
+ * Counterpart to Solidity's `uint216` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 216 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint216(uint256 value) internal pure returns (uint216) {
+ require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
+ return uint216(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint208 from uint256, reverting on
+ * overflow (when the input is greater than largest uint208).
+ *
+ * Counterpart to Solidity's `uint208` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 208 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint208(uint256 value) internal pure returns (uint208) {
+ require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
+ return uint208(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint200 from uint256, reverting on
+ * overflow (when the input is greater than largest uint200).
+ *
+ * Counterpart to Solidity's `uint200` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 200 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint200(uint256 value) internal pure returns (uint200) {
+ require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
+ return uint200(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint192 from uint256, reverting on
+ * overflow (when the input is greater than largest uint192).
+ *
+ * Counterpart to Solidity's `uint192` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 192 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint192(uint256 value) internal pure returns (uint192) {
+ require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
+ return uint192(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint184 from uint256, reverting on
+ * overflow (when the input is greater than largest uint184).
+ *
+ * Counterpart to Solidity's `uint184` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 184 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint184(uint256 value) internal pure returns (uint184) {
+ require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
+ return uint184(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint176 from uint256, reverting on
+ * overflow (when the input is greater than largest uint176).
+ *
+ * Counterpart to Solidity's `uint176` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 176 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint176(uint256 value) internal pure returns (uint176) {
+ require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
+ return uint176(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint168 from uint256, reverting on
+ * overflow (when the input is greater than largest uint168).
+ *
+ * Counterpart to Solidity's `uint168` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 168 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint168(uint256 value) internal pure returns (uint168) {
+ require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
+ return uint168(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint160 from uint256, reverting on
+ * overflow (when the input is greater than largest uint160).
+ *
+ * Counterpart to Solidity's `uint160` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 160 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint160(uint256 value) internal pure returns (uint160) {
+ require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
+ return uint160(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint152 from uint256, reverting on
+ * overflow (when the input is greater than largest uint152).
+ *
+ * Counterpart to Solidity's `uint152` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 152 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint152(uint256 value) internal pure returns (uint152) {
+ require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
+ return uint152(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint144 from uint256, reverting on
+ * overflow (when the input is greater than largest uint144).
+ *
+ * Counterpart to Solidity's `uint144` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 144 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint144(uint256 value) internal pure returns (uint144) {
+ require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
+ return uint144(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint136 from uint256, reverting on
+ * overflow (when the input is greater than largest uint136).
+ *
+ * Counterpart to Solidity's `uint136` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 136 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint136(uint256 value) internal pure returns (uint136) {
+ require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
+ return uint136(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint128 from uint256, reverting on
+ * overflow (when the input is greater than largest uint128).
+ *
+ * Counterpart to Solidity's `uint128` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 128 bits
+ *
+ * _Available since v2.5._
+ */
+ function toUint128(uint256 value) internal pure returns (uint128) {
+ require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
+ return uint128(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint120 from uint256, reverting on
+ * overflow (when the input is greater than largest uint120).
+ *
+ * Counterpart to Solidity's `uint120` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 120 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint120(uint256 value) internal pure returns (uint120) {
+ require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
+ return uint120(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint112 from uint256, reverting on
+ * overflow (when the input is greater than largest uint112).
+ *
+ * Counterpart to Solidity's `uint112` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 112 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint112(uint256 value) internal pure returns (uint112) {
+ require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
+ return uint112(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint104 from uint256, reverting on
+ * overflow (when the input is greater than largest uint104).
+ *
+ * Counterpart to Solidity's `uint104` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 104 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint104(uint256 value) internal pure returns (uint104) {
+ require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
+ return uint104(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint96 from uint256, reverting on
+ * overflow (when the input is greater than largest uint96).
+ *
+ * Counterpart to Solidity's `uint96` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 96 bits
+ *
+ * _Available since v4.2._
+ */
+ function toUint96(uint256 value) internal pure returns (uint96) {
+ require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
+ return uint96(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint88 from uint256, reverting on
+ * overflow (when the input is greater than largest uint88).
+ *
+ * Counterpart to Solidity's `uint88` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 88 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint88(uint256 value) internal pure returns (uint88) {
+ require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
+ return uint88(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint80 from uint256, reverting on
+ * overflow (when the input is greater than largest uint80).
+ *
+ * Counterpart to Solidity's `uint80` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 80 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint80(uint256 value) internal pure returns (uint80) {
+ require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
+ return uint80(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint72 from uint256, reverting on
+ * overflow (when the input is greater than largest uint72).
+ *
+ * Counterpart to Solidity's `uint72` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 72 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint72(uint256 value) internal pure returns (uint72) {
+ require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
+ return uint72(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint64 from uint256, reverting on
+ * overflow (when the input is greater than largest uint64).
+ *
+ * Counterpart to Solidity's `uint64` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 64 bits
+ *
+ * _Available since v2.5._
+ */
+ function toUint64(uint256 value) internal pure returns (uint64) {
+ require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
+ return uint64(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint56 from uint256, reverting on
+ * overflow (when the input is greater than largest uint56).
+ *
+ * Counterpart to Solidity's `uint56` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 56 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint56(uint256 value) internal pure returns (uint56) {
+ require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
+ return uint56(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint48 from uint256, reverting on
+ * overflow (when the input is greater than largest uint48).
+ *
+ * Counterpart to Solidity's `uint48` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 48 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint48(uint256 value) internal pure returns (uint48) {
+ require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
+ return uint48(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint40 from uint256, reverting on
+ * overflow (when the input is greater than largest uint40).
+ *
+ * Counterpart to Solidity's `uint40` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 40 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint40(uint256 value) internal pure returns (uint40) {
+ require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
+ return uint40(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint32 from uint256, reverting on
+ * overflow (when the input is greater than largest uint32).
+ *
+ * Counterpart to Solidity's `uint32` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 32 bits
+ *
+ * _Available since v2.5._
+ */
+ function toUint32(uint256 value) internal pure returns (uint32) {
+ require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
+ return uint32(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint24 from uint256, reverting on
+ * overflow (when the input is greater than largest uint24).
+ *
+ * Counterpart to Solidity's `uint24` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 24 bits
+ *
+ * _Available since v4.7._
+ */
+ function toUint24(uint256 value) internal pure returns (uint24) {
+ require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
+ return uint24(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint16 from uint256, reverting on
+ * overflow (when the input is greater than largest uint16).
+ *
+ * Counterpart to Solidity's `uint16` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 16 bits
+ *
+ * _Available since v2.5._
+ */
+ function toUint16(uint256 value) internal pure returns (uint16) {
+ require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
+ return uint16(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint8 from uint256, reverting on
+ * overflow (when the input is greater than largest uint8).
+ *
+ * Counterpart to Solidity's `uint8` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 8 bits
+ *
+ * _Available since v2.5._
+ */
+ function toUint8(uint256 value) internal pure returns (uint8) {
+ require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
+ return uint8(value);
+ }
+
+ /**
+ * @dev Converts a signed int256 into an unsigned uint256.
+ *
+ * Requirements:
+ *
+ * - input must be greater than or equal to 0.
+ *
+ * _Available since v3.0._
+ */
+ function toUint256(int256 value) internal pure returns (uint256) {
+ require(value >= 0, "SafeCast: value must be positive");
+ return uint256(value);
+ }
+
+ /**
+ * @dev Returns the downcasted int248 from int256, reverting on
+ * overflow (when the input is less than smallest int248 or
+ * greater than largest int248).
+ *
+ * Counterpart to Solidity's `int248` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 248 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt248(int256 value) internal pure returns (int248 downcasted) {
+ downcasted = int248(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int240 from int256, reverting on
+ * overflow (when the input is less than smallest int240 or
+ * greater than largest int240).
+ *
+ * Counterpart to Solidity's `int240` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 240 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt240(int256 value) internal pure returns (int240 downcasted) {
+ downcasted = int240(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int232 from int256, reverting on
+ * overflow (when the input is less than smallest int232 or
+ * greater than largest int232).
+ *
+ * Counterpart to Solidity's `int232` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 232 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt232(int256 value) internal pure returns (int232 downcasted) {
+ downcasted = int232(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int224 from int256, reverting on
+ * overflow (when the input is less than smallest int224 or
+ * greater than largest int224).
+ *
+ * Counterpart to Solidity's `int224` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 224 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt224(int256 value) internal pure returns (int224 downcasted) {
+ downcasted = int224(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int216 from int256, reverting on
+ * overflow (when the input is less than smallest int216 or
+ * greater than largest int216).
+ *
+ * Counterpart to Solidity's `int216` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 216 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt216(int256 value) internal pure returns (int216 downcasted) {
+ downcasted = int216(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int208 from int256, reverting on
+ * overflow (when the input is less than smallest int208 or
+ * greater than largest int208).
+ *
+ * Counterpart to Solidity's `int208` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 208 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt208(int256 value) internal pure returns (int208 downcasted) {
+ downcasted = int208(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int200 from int256, reverting on
+ * overflow (when the input is less than smallest int200 or
+ * greater than largest int200).
+ *
+ * Counterpart to Solidity's `int200` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 200 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt200(int256 value) internal pure returns (int200 downcasted) {
+ downcasted = int200(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int192 from int256, reverting on
+ * overflow (when the input is less than smallest int192 or
+ * greater than largest int192).
+ *
+ * Counterpart to Solidity's `int192` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 192 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt192(int256 value) internal pure returns (int192 downcasted) {
+ downcasted = int192(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int184 from int256, reverting on
+ * overflow (when the input is less than smallest int184 or
+ * greater than largest int184).
+ *
+ * Counterpart to Solidity's `int184` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 184 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt184(int256 value) internal pure returns (int184 downcasted) {
+ downcasted = int184(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int176 from int256, reverting on
+ * overflow (when the input is less than smallest int176 or
+ * greater than largest int176).
+ *
+ * Counterpart to Solidity's `int176` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 176 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt176(int256 value) internal pure returns (int176 downcasted) {
+ downcasted = int176(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int168 from int256, reverting on
+ * overflow (when the input is less than smallest int168 or
+ * greater than largest int168).
+ *
+ * Counterpart to Solidity's `int168` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 168 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt168(int256 value) internal pure returns (int168 downcasted) {
+ downcasted = int168(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int160 from int256, reverting on
+ * overflow (when the input is less than smallest int160 or
+ * greater than largest int160).
+ *
+ * Counterpart to Solidity's `int160` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 160 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt160(int256 value) internal pure returns (int160 downcasted) {
+ downcasted = int160(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int152 from int256, reverting on
+ * overflow (when the input is less than smallest int152 or
+ * greater than largest int152).
+ *
+ * Counterpart to Solidity's `int152` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 152 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt152(int256 value) internal pure returns (int152 downcasted) {
+ downcasted = int152(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int144 from int256, reverting on
+ * overflow (when the input is less than smallest int144 or
+ * greater than largest int144).
+ *
+ * Counterpart to Solidity's `int144` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 144 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt144(int256 value) internal pure returns (int144 downcasted) {
+ downcasted = int144(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int136 from int256, reverting on
+ * overflow (when the input is less than smallest int136 or
+ * greater than largest int136).
+ *
+ * Counterpart to Solidity's `int136` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 136 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt136(int256 value) internal pure returns (int136 downcasted) {
+ downcasted = int136(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int128 from int256, reverting on
+ * overflow (when the input is less than smallest int128 or
+ * greater than largest int128).
+ *
+ * Counterpart to Solidity's `int128` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 128 bits
+ *
+ * _Available since v3.1._
+ */
+ function toInt128(int256 value) internal pure returns (int128 downcasted) {
+ downcasted = int128(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int120 from int256, reverting on
+ * overflow (when the input is less than smallest int120 or
+ * greater than largest int120).
+ *
+ * Counterpart to Solidity's `int120` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 120 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt120(int256 value) internal pure returns (int120 downcasted) {
+ downcasted = int120(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int112 from int256, reverting on
+ * overflow (when the input is less than smallest int112 or
+ * greater than largest int112).
+ *
+ * Counterpart to Solidity's `int112` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 112 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt112(int256 value) internal pure returns (int112 downcasted) {
+ downcasted = int112(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int104 from int256, reverting on
+ * overflow (when the input is less than smallest int104 or
+ * greater than largest int104).
+ *
+ * Counterpart to Solidity's `int104` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 104 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt104(int256 value) internal pure returns (int104 downcasted) {
+ downcasted = int104(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int96 from int256, reverting on
+ * overflow (when the input is less than smallest int96 or
+ * greater than largest int96).
+ *
+ * Counterpart to Solidity's `int96` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 96 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt96(int256 value) internal pure returns (int96 downcasted) {
+ downcasted = int96(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int88 from int256, reverting on
+ * overflow (when the input is less than smallest int88 or
+ * greater than largest int88).
+ *
+ * Counterpart to Solidity's `int88` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 88 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt88(int256 value) internal pure returns (int88 downcasted) {
+ downcasted = int88(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int80 from int256, reverting on
+ * overflow (when the input is less than smallest int80 or
+ * greater than largest int80).
+ *
+ * Counterpart to Solidity's `int80` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 80 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt80(int256 value) internal pure returns (int80 downcasted) {
+ downcasted = int80(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int72 from int256, reverting on
+ * overflow (when the input is less than smallest int72 or
+ * greater than largest int72).
+ *
+ * Counterpart to Solidity's `int72` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 72 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt72(int256 value) internal pure returns (int72 downcasted) {
+ downcasted = int72(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int64 from int256, reverting on
+ * overflow (when the input is less than smallest int64 or
+ * greater than largest int64).
+ *
+ * Counterpart to Solidity's `int64` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 64 bits
+ *
+ * _Available since v3.1._
+ */
+ function toInt64(int256 value) internal pure returns (int64 downcasted) {
+ downcasted = int64(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int56 from int256, reverting on
+ * overflow (when the input is less than smallest int56 or
+ * greater than largest int56).
+ *
+ * Counterpart to Solidity's `int56` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 56 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt56(int256 value) internal pure returns (int56 downcasted) {
+ downcasted = int56(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int48 from int256, reverting on
+ * overflow (when the input is less than smallest int48 or
+ * greater than largest int48).
+ *
+ * Counterpart to Solidity's `int48` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 48 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt48(int256 value) internal pure returns (int48 downcasted) {
+ downcasted = int48(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int40 from int256, reverting on
+ * overflow (when the input is less than smallest int40 or
+ * greater than largest int40).
+ *
+ * Counterpart to Solidity's `int40` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 40 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt40(int256 value) internal pure returns (int40 downcasted) {
+ downcasted = int40(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int32 from int256, reverting on
+ * overflow (when the input is less than smallest int32 or
+ * greater than largest int32).
+ *
+ * Counterpart to Solidity's `int32` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 32 bits
+ *
+ * _Available since v3.1._
+ */
+ function toInt32(int256 value) internal pure returns (int32 downcasted) {
+ downcasted = int32(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int24 from int256, reverting on
+ * overflow (when the input is less than smallest int24 or
+ * greater than largest int24).
+ *
+ * Counterpart to Solidity's `int24` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 24 bits
+ *
+ * _Available since v4.7._
+ */
+ function toInt24(int256 value) internal pure returns (int24 downcasted) {
+ downcasted = int24(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int16 from int256, reverting on
+ * overflow (when the input is less than smallest int16 or
+ * greater than largest int16).
+ *
+ * Counterpart to Solidity's `int16` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 16 bits
+ *
+ * _Available since v3.1._
+ */
+ function toInt16(int256 value) internal pure returns (int16 downcasted) {
+ downcasted = int16(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
+ }
+
+ /**
+ * @dev Returns the downcasted int8 from int256, reverting on
+ * overflow (when the input is less than smallest int8 or
+ * greater than largest int8).
+ *
+ * Counterpart to Solidity's `int8` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 8 bits
+ *
+ * _Available since v3.1._
+ */
+ function toInt8(int256 value) internal pure returns (int8 downcasted) {
+ downcasted = int8(value);
+ require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
+ }
+
+ /**
+ * @dev Converts an unsigned uint256 into a signed int256.
+ *
+ * Requirements:
+ *
+ * - input must be less than or equal to maxInt256.
+ *
+ * _Available since v3.0._
+ */
+ function toInt256(uint256 value) internal pure returns (int256) {
+ // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
+ require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
+ return int256(value);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/ZeppelinContract.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/ZeppelinContract.sol
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.9;
+
+import "./@openzeppelin/contracts/token/ERC20/ERC20.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
+import "./@openzeppelin/contracts/security/Pausable.sol";
+import "./@openzeppelin/contracts/access/Ownable.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";
+
+contract ZeppelinContract is ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint {
+ constructor()
+ ERC20("ZeppelinContract", "UNQ")
+ ERC20Permit("ZeppelinContract")
+ {}
+
+ function pause() public onlyOwner {
+ _pause();
+ }
+
+ function unpause() public onlyOwner {
+ _unpause();
+ }
+
+ function mint(address to, uint256 amount) public onlyOwner {
+ _mint(to, amount);
+ }
+
+ function _beforeTokenTransfer(address from, address to, uint256 amount)
+ internal
+ whenNotPaused
+ override
+ {
+ super._beforeTokenTransfer(from, to, amount);
+ }
+
+ // The following functions are overrides required by Solidity.
+
+ function _afterTokenTransfer(address from, address to, uint256 amount)
+ internal
+ override(ERC20, ERC20Votes)
+ {
+ super._afterTokenTransfer(from, to, amount);
+ }
+
+ function _mint(address to, uint256 amount)
+ internal
+ override(ERC20, ERC20Votes)
+ {
+ super._mint(to, amount);
+ }
+
+ function _burn(address account, uint256 amount)
+ internal
+ override(ERC20, ERC20Votes)
+ {
+ super._burn(account, amount);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.abidiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.abi
@@ -0,0 +1 @@
+[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"pos","type":"uint32"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint224","name":"votes","type":"uint224"}],"internalType":"struct ERC20Votes.Checkpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.bindiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.bin
@@ -0,0 +1 @@
+6101406040523480156200001257600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525080604051806040016040528060018152602001603160f81b8152506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b8152508160039081620000ad919062000269565b506004620000bc828262000269565b50506005805460ff1916905550620000d4336200016a565b815160209283012081519183019190912060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818801819052818301969096526060810194909452608080850193909352308483018190528151808603909301835260c094850190915281519190950120905291909152610120525062000335565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001ef57607f821691505b6020821081036200021057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200026457600081815260208120601f850160051c810160208610156200023f5750805b601f850160051c820191505b8181101562000260578281556001016200024b565b5050505b505050565b81516001600160401b03811115620002855762000285620001c4565b6200029d81620002968454620001da565b8462000216565b602080601f831160018114620002d55760008415620002bc5750858301515b600019600386901b1c1916600185901b17855562000260565b600085815260208120601f198616915b828110156200030657888601518255948401946001909101908401620002e5565b5085821015620003255787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e05161010051610120516125f06200038560003960006112ad015260006112fc015260006112d7015260006112300152600061125a0152600061128401526125f06000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806370a082311161011a5780639ab24eb0116100ad578063d505accf1161007c578063d505accf1461046a578063d9d98ce41461047d578063dd62ed3e14610490578063f1127ed8146104a3578063f2fde38b146104e057600080fd5b80639ab24eb01461041e578063a457c2d714610431578063a9059cbb14610444578063c3cda5201461045757600080fd5b80638456cb59116100e95780638456cb59146103e55780638da5cb5b146103ed5780638e539e8c1461040357806395d89b411461041657600080fd5b806370a082311461038e578063715018a6146103b757806379cc6790146103bf5780637ecebe00146103d257600080fd5b80633f4ba83a1161019d5780635c19a95c1161016c5780635c19a95c146103225780635c975abb146103355780635cffe9de14610340578063613255ab146103535780636fcfff451461036657600080fd5b80633f4ba83a146102ae57806340c10f19146102b857806342966c68146102cb578063587cde1e146102de57600080fd5b8063313ce567116101d9578063313ce567146102715780633644e5151461028057806339509351146102885780633a46b1a81461029b57600080fd5b806306fdde031461020b578063095ea7b31461022957806318160ddd1461024c57806323b872dd1461025e575b600080fd5b6102136104f3565b604051610220919061217e565b60405180910390f35b61023c6102373660046121e1565b610585565b6040519015158152602001610220565b6002545b604051908152602001610220565b61023c61026c36600461220d565b61059f565b60405160128152602001610220565b6102506105c3565b61023c6102963660046121e1565b6105d2565b6102506102a93660046121e1565b6105f4565b6102b6610673565b005b6102b66102c63660046121e1565b610685565b6102b66102d936600461224e565b61069b565b61030a6102ec366004612267565b6001600160a01b039081166000908152600860205260409020541690565b6040516001600160a01b039091168152602001610220565b6102b6610330366004612267565b6106a8565b60055460ff1661023c565b61023c61034e366004612284565b6106b2565b610250610361366004612267565b610896565b610379610374366004612267565b6108be565b60405163ffffffff9091168152602001610220565b61025061039c366004612267565b6001600160a01b031660009081526020819052604090205490565b6102b66108e0565b6102b66103cd3660046121e1565b6108f2565b6102506103e0366004612267565b610907565b6102b6610925565b60055461010090046001600160a01b031661030a565b61025061041136600461224e565b610935565b610213610991565b61025061042c366004612267565b6109a0565b61023c61043f3660046121e1565b610a27565b61023c6104523660046121e1565b610aa2565b6102b6610465366004612339565b610ab0565b6102b6610478366004612393565b610be6565b61025061048b3660046121e1565b610d4a565b61025061049e366004612401565b610dab565b6104b66104b136600461243a565b610dd6565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610220565b6102b66104ee366004612267565b610e5a565b60606003805461050290612471565b80601f016020809104026020016040519081016040528092919081815260200182805461052e90612471565b801561057b5780601f106105505761010080835404028352916020019161057b565b820191906000526020600020905b81548152906001019060200180831161055e57829003601f168201915b5050505050905090565b600033610593818585610ed0565b60019150505b92915050565b6000336105ad858285610ff4565b6105b885858561106e565b506001949350505050565b60006105cd611223565b905090565b6000336105938185856105e58383610dab565b6105ef91906124bb565b610ed0565b600043821061064a5760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064015b60405180910390fd5b6001600160a01b038316600090815260096020526040902061066c908361134a565b9392505050565b61067b611441565b6106836114a1565b565b61068d611441565b61069782826114f3565b5050565b6106a533826114fd565b50565b6106a53382611507565b60006106bd85610896565b8411156107205760405162461bcd60e51b815260206004820152602b60248201527f4552433230466c6173684d696e743a20616d6f756e742065786365656473206d60448201526a30bc233630b9b42637b0b760a91b6064820152608401610641565b600061072c8686610d4a565b905061073887866114f3565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038916906323e30c8b906107909033908b908b9088908c908c906004016124ce565b6020604051808303816000875af11580156107af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d3919061252a565b1461082c5760405162461bcd60e51b8152602060048201526024808201527f4552433230466c6173684d696e743a20696e76616c69642072657475726e2076604482015263616c756560e01b6064820152608401610641565b6000610842883061083d858a6124bb565b610ff4565b81158061085657506001600160a01b038116155b156108735761086e8861086984896124bb565b6114fd565b610888565b61087d88876114fd565b61088888828461106e565b506001979650505050505050565b60006001600160a01b03821630146108af576000610599565b60025461059990600019612543565b6001600160a01b03811660009081526009602052604081205461059990611580565b6108e8611441565b61068360006115e9565b6108fd823383610ff4565b61069782826114fd565b6001600160a01b038116600090815260066020526040812054610599565b61092d611441565b610683611643565b60004382106109865760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610641565b610599600a8361134a565b60606004805461050290612471565b6001600160a01b0381166000908152600960205260408120548015610a14576001600160a01b03831660009081526009602052604090206109e2600183612543565b815481106109f2576109f2612556565b60009182526020909120015464010000000090046001600160e01b0316610a17565b60005b6001600160e01b03169392505050565b60003381610a358286610dab565b905083811015610a955760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610641565b6105b88286868403610ed0565b60003361059381858561106e565b83421115610b005760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610641565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610b7a90610b729060a00160405160208183030381529060405280519060200120611680565b8585856116ce565b9050610b85816116f6565b8614610bd35760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610641565b610bdd8188611507565b50505050505050565b83421115610c365760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610641565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610c658c6116f6565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610cc082611680565b90506000610cd0828787876116ce565b9050896001600160a01b0316816001600160a01b031614610d335760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610641565b610d3e8a8a8a610ed0565b50505050505050505050565b60006001600160a01b0383163014610da45760405162461bcd60e51b815260206004820152601b60248201527f4552433230466c6173684d696e743a2077726f6e6720746f6b656e00000000006044820152606401610641565b600061066c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60408051808201909152600080825260208201526001600160a01b0383166000908152600960205260409020805463ffffffff8416908110610e1a57610e1a612556565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b610e62611441565b6001600160a01b038116610ec75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610641565b6106a5816115e9565b6001600160a01b038316610f325760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610641565b6001600160a01b038216610f935760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610641565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006110008484610dab565b90506000198114611068578181101561105b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610641565b6110688484848403610ed0565b50505050565b6001600160a01b0383166110d25760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610641565b6001600160a01b0382166111345760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610641565b61113f83838361171e565b6001600160a01b038316600090815260208190526040902054818110156111b75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610641565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361106884848461172b565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561127c57507f000000000000000000000000000000000000000000000000000000000000000046145b156112a657507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b8154600090818160058111156113a457600061136584611736565b61136f9085612543565b600088815260209020909150869082015463ffffffff161115611394578091506113a2565b61139f8160016124bb565b92505b505b808210156113f15760006113b8838361181e565b600088815260209020909150869082015463ffffffff1611156113dd578091506113eb565b6113e88160016124bb565b92505b506113a4565b801561142b5761141486611406600184612543565b600091825260209091200190565b5464010000000090046001600160e01b031661142e565b60005b6001600160e01b03169695505050505050565b6005546001600160a01b036101009091041633146106835760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610641565b6114a9611839565b6005805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6106978282611882565b610697828261190c565b6001600160a01b038281166000818152600860208181526040808420805485845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611068828483611924565b600063ffffffff8211156115e55760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610641565b5090565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61164b611a61565b6005805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114d63390565b600061059961168d611223565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006116df87878787611aa7565b915091506116ec81611b6b565b5095945050505050565b6001600160a01b03811660009081526006602052604090208054600181018255905b50919050565b611726611a61565b505050565b611726838383611cb5565b60008160000361174857506000919050565b6000600161175584611ce7565b901c6001901b9050600181848161176e5761176e61256c565b048201901c905060018184816117865761178661256c565b048201901c9050600181848161179e5761179e61256c565b048201901c905060018184816117b6576117b661256c565b048201901c905060018184816117ce576117ce61256c565b048201901c905060018184816117e6576117e661256c565b048201901c905060018184816117fe576117fe61256c565b048201901c905061066c818285816118185761181861256c565b04611d7b565b600061182d6002848418612582565b61066c908484166124bb565b60055460ff166106835760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610641565b61188c8282611d91565b6002546001600160e01b0310156118fe5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610641565b611068600a611e6483611e70565b6119168282611fc4565b611068600a61210983611e70565b816001600160a01b0316836001600160a01b0316141580156119465750600081115b15611726576001600160a01b038316156119d4576001600160a01b038316600090815260096020526040812081906119819061210985611e70565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516119c9929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611726576001600160a01b03821660009081526009602052604081208190611a0a90611e6485611e70565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611a52929190918252602082015260400190565b60405180910390a25050505050565b60055460ff16156106835760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610641565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611ade5750600090506003611b62565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611b32573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611b5b57600060019250925050611b62565b9150600090505b94509492505050565b6000816004811115611b7f57611b7f6125a4565b03611b875750565b6001816004811115611b9b57611b9b6125a4565b03611be85760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610641565b6002816004811115611bfc57611bfc6125a4565b03611c495760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610641565b6003816004811115611c5d57611c5d6125a4565b036106a55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610641565b6001600160a01b0383811660009081526008602052604080822054858416835291205461172692918216911683611924565b600080608083901c15611cfc57608092831c92015b604083901c15611d0e57604092831c92015b602083901c15611d2057602092831c92015b601083901c15611d3257601092831c92015b600883901c15611d4457600892831c92015b600483901c15611d5657600492831c92015b600283901c15611d6857600292831c92015b600183901c156105995760010192915050565b6000818310611d8a578161066c565b5090919050565b6001600160a01b038216611de75760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610641565b611df36000838361171e565b8060026000828254611e0591906124bb565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106976000838361172b565b600061066c82846124bb565b82546000908190818115611ebd57611e8d87611406600185612543565b60408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152611ed2565b60408051808201909152600080825260208201525b905080602001516001600160e01b03169350611ef284868863ffffffff16565b9250600082118015611f0a5750805163ffffffff1643145b15611f4f57611f1883612115565b611f2788611406600186612543565b80546001600160e01b03929092166401000000000263ffffffff909216919091179055611fba565b866040518060400160405280611f6443611580565b63ffffffff168152602001611f7886612115565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b6001600160a01b0382166120245760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610641565b6120308260008361171e565b6001600160a01b038216600090815260208190526040902054818110156120a45760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610641565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36117268360008461172b565b600061066c8284612543565b60006001600160e01b038211156115e55760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610641565b600060208083528351808285015260005b818110156121ab5785810183015185820160400152820161218f565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b03811681146106a557600080fd5b600080604083850312156121f457600080fd5b82356121ff816121cc565b946020939093013593505050565b60008060006060848603121561222257600080fd5b833561222d816121cc565b9250602084013561223d816121cc565b929592945050506040919091013590565b60006020828403121561226057600080fd5b5035919050565b60006020828403121561227957600080fd5b813561066c816121cc565b60008060008060006080868803121561229c57600080fd5b85356122a7816121cc565b945060208601356122b7816121cc565b935060408601359250606086013567ffffffffffffffff808211156122db57600080fd5b818801915088601f8301126122ef57600080fd5b8135818111156122fe57600080fd5b89602082850101111561231057600080fd5b9699959850939650602001949392505050565b803560ff8116811461233457600080fd5b919050565b60008060008060008060c0878903121561235257600080fd5b863561235d816121cc565b9550602087013594506040870135935061237960608801612323565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a0312156123ae57600080fd5b87356123b9816121cc565b965060208801356123c9816121cc565b955060408801359450606088013593506123e560808901612323565b925060a0880135915060c0880135905092959891949750929550565b6000806040838503121561241457600080fd5b823561241f816121cc565b9150602083013561242f816121cc565b809150509250929050565b6000806040838503121561244d57600080fd5b8235612458816121cc565b9150602083013563ffffffff8116811461242f57600080fd5b600181811c9082168061248557607f821691505b60208210810361171857634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610599576105996124a5565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60006020828403121561253c57600080fd5b5051919050565b81810381811115610599576105996124a5565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60008261259f57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fdfea264697066735822122057e08ed799a9773c2de4d8c40122801fc9994042a2e3e3ac01e5aa1c384b1c4b64736f6c63430008110033
\ No newline at end of file
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/README.mddiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/README.md
@@ -0,0 +1,12 @@
+# OpenZeppelin Contracts
+
+The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
+
+They are not meant to be edited.
+
+The originals can be found on [GitHub] and [npm].
+
+[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
+[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
+
+Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/access/Ownable.sol
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../utils/Context.sol";
+
+/**
+ * @dev Contract module which provides a basic access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership}.
+ *
+ * This module is used through inheritance. It will make available the modifier
+ * `onlyOwner`, which can be applied to your functions to restrict their use to
+ * the owner.
+ */
+abstract contract Ownable is Context {
+ address private _owner;
+
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
+
+ /**
+ * @dev Initializes the contract setting the deployer as the initial owner.
+ */
+ constructor() {
+ _transferOwnership(_msgSender());
+ }
+
+ /**
+ * @dev Throws if called by any account other than the owner.
+ */
+ modifier onlyOwner() {
+ _checkOwner();
+ _;
+ }
+
+ /**
+ * @dev Returns the address of the current owner.
+ */
+ function owner() public view virtual returns (address) {
+ return _owner;
+ }
+
+ /**
+ * @dev Throws if the sender is not the owner.
+ */
+ function _checkOwner() internal view virtual {
+ require(owner() == _msgSender(), "Ownable: caller is not the owner");
+ }
+
+ /**
+ * @dev Leaves the contract without owner. It will not be possible to call
+ * `onlyOwner` functions anymore. Can only be called by the current owner.
+ *
+ * NOTE: Renouncing ownership will leave the contract without an owner,
+ * thereby removing any functionality that is only available to the owner.
+ */
+ function renounceOwnership() public virtual onlyOwner {
+ _transferOwnership(address(0));
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Can only be called by the current owner.
+ */
+ function transferOwnership(address newOwner) public virtual onlyOwner {
+ require(newOwner != address(0), "Ownable: new owner is the zero address");
+ _transferOwnership(newOwner);
+ }
+
+ /**
+ * @dev Transfers ownership of the contract to a new account (`newOwner`).
+ * Internal function without access restriction.
+ */
+ function _transferOwnership(address newOwner) internal virtual {
+ address oldOwner = _owner;
+ _owner = newOwner;
+ emit OwnershipTransferred(oldOwner, newOwner);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/ERC721.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/ERC721.sol
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC721.sol";
+import "./IERC721Receiver.sol";
+import "./extensions/IERC721Metadata.sol";
+import "../../utils/Address.sol";
+import "../../utils/Context.sol";
+import "../../utils/Strings.sol";
+import "../../utils/introspection/ERC165.sol";
+
+/**
+ * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
+ * the Metadata extension, but not including the Enumerable extension, which is available separately as
+ * {ERC721Enumerable}.
+ */
+contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
+ using Address for address;
+ using Strings for uint256;
+
+ // Token name
+ string private _name;
+
+ // Token symbol
+ string private _symbol;
+
+ // Mapping from token ID to owner address
+ mapping(uint256 => address) private _owners;
+
+ // Mapping owner address to token count
+ mapping(address => uint256) private _balances;
+
+ // Mapping from token ID to approved address
+ mapping(uint256 => address) private _tokenApprovals;
+
+ // Mapping from owner to operator approvals
+ mapping(address => mapping(address => bool)) private _operatorApprovals;
+
+ /**
+ * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
+ */
+ constructor(string memory name_, string memory symbol_) {
+ _name = name_;
+ _symbol = symbol_;
+ }
+
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
+ return
+ interfaceId == type(IERC721).interfaceId ||
+ interfaceId == type(IERC721Metadata).interfaceId ||
+ super.supportsInterface(interfaceId);
+ }
+
+ /**
+ * @dev See {IERC721-balanceOf}.
+ */
+ function balanceOf(address owner) public view virtual override returns (uint256) {
+ require(owner != address(0), "ERC721: address zero is not a valid owner");
+ return _balances[owner];
+ }
+
+ /**
+ * @dev See {IERC721-ownerOf}.
+ */
+ function ownerOf(uint256 tokenId) public view virtual override returns (address) {
+ address owner = _ownerOf(tokenId);
+ require(owner != address(0), "ERC721: invalid token ID");
+ return owner;
+ }
+
+ /**
+ * @dev See {IERC721Metadata-name}.
+ */
+ function name() public view virtual override returns (string memory) {
+ return _name;
+ }
+
+ /**
+ * @dev See {IERC721Metadata-symbol}.
+ */
+ function symbol() public view virtual override returns (string memory) {
+ return _symbol;
+ }
+
+ /**
+ * @dev See {IERC721Metadata-tokenURI}.
+ */
+ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
+ _requireMinted(tokenId);
+
+ string memory baseURI = _baseURI();
+ return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
+ }
+
+ /**
+ * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
+ * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
+ * by default, can be overridden in child contracts.
+ */
+ function _baseURI() internal view virtual returns (string memory) {
+ return "";
+ }
+
+ /**
+ * @dev See {IERC721-approve}.
+ */
+ function approve(address to, uint256 tokenId) public virtual override {
+ address owner = ERC721.ownerOf(tokenId);
+ require(to != owner, "ERC721: approval to current owner");
+
+ require(
+ _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
+ "ERC721: approve caller is not token owner or approved for all"
+ );
+
+ _approve(to, tokenId);
+ }
+
+ /**
+ * @dev See {IERC721-getApproved}.
+ */
+ function getApproved(uint256 tokenId) public view virtual override returns (address) {
+ _requireMinted(tokenId);
+
+ return _tokenApprovals[tokenId];
+ }
+
+ /**
+ * @dev See {IERC721-setApprovalForAll}.
+ */
+ function setApprovalForAll(address operator, bool approved) public virtual override {
+ _setApprovalForAll(_msgSender(), operator, approved);
+ }
+
+ /**
+ * @dev See {IERC721-isApprovedForAll}.
+ */
+ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
+ return _operatorApprovals[owner][operator];
+ }
+
+ /**
+ * @dev See {IERC721-transferFrom}.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) public virtual override {
+ //solhint-disable-next-line max-line-length
+ require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
+
+ _transfer(from, to, tokenId);
+ }
+
+ /**
+ * @dev See {IERC721-safeTransferFrom}.
+ */
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) public virtual override {
+ safeTransferFrom(from, to, tokenId, "");
+ }
+
+ /**
+ * @dev See {IERC721-safeTransferFrom}.
+ */
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) public virtual override {
+ require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
+ _safeTransfer(from, to, tokenId, data);
+ }
+
+ /**
+ * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
+ * are aware of the ERC721 protocol to prevent tokens from being forever locked.
+ *
+ * `data` is additional data, it has no specified format and it is sent in call to `to`.
+ *
+ * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
+ * implement alternative mechanisms to perform token transfer, such as signature-based.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must exist and be owned by `from`.
+ * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+ *
+ * Emits a {Transfer} event.
+ */
+ function _safeTransfer(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) internal virtual {
+ _transfer(from, to, tokenId);
+ require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
+ }
+
+ /**
+ * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
+ */
+ function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
+ return _owners[tokenId];
+ }
+
+ /**
+ * @dev Returns whether `tokenId` exists.
+ *
+ * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
+ *
+ * Tokens start existing when they are minted (`_mint`),
+ * and stop existing when they are burned (`_burn`).
+ */
+ function _exists(uint256 tokenId) internal view virtual returns (bool) {
+ return _ownerOf(tokenId) != address(0);
+ }
+
+ /**
+ * @dev Returns whether `spender` is allowed to manage `tokenId`.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ */
+ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
+ address owner = ERC721.ownerOf(tokenId);
+ return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
+ }
+
+ /**
+ * @dev Safely mints `tokenId` and transfers it to `to`.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must not exist.
+ * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+ *
+ * Emits a {Transfer} event.
+ */
+ function _safeMint(address to, uint256 tokenId) internal virtual {
+ _safeMint(to, tokenId, "");
+ }
+
+ /**
+ * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
+ * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
+ */
+ function _safeMint(
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) internal virtual {
+ _mint(to, tokenId);
+ require(
+ _checkOnERC721Received(address(0), to, tokenId, data),
+ "ERC721: transfer to non ERC721Receiver implementer"
+ );
+ }
+
+ /**
+ * @dev Mints `tokenId` and transfers it to `to`.
+ *
+ * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
+ *
+ * Requirements:
+ *
+ * - `tokenId` must not exist.
+ * - `to` cannot be the zero address.
+ *
+ * Emits a {Transfer} event.
+ */
+ function _mint(address to, uint256 tokenId) internal virtual {
+ require(to != address(0), "ERC721: mint to the zero address");
+ require(!_exists(tokenId), "ERC721: token already minted");
+
+ _beforeTokenTransfer(address(0), to, tokenId, 1);
+
+ // Check that tokenId was not minted by `_beforeTokenTransfer` hook
+ require(!_exists(tokenId), "ERC721: token already minted");
+
+ unchecked {
+ // Will not overflow unless all 2**256 token ids are minted to the same owner.
+ // Given that tokens are minted one by one, it is impossible in practice that
+ // this ever happens. Might change if we allow batch minting.
+ // The ERC fails to describe this case.
+ _balances[to] += 1;
+ }
+
+ _owners[tokenId] = to;
+
+ emit Transfer(address(0), to, tokenId);
+
+ _afterTokenTransfer(address(0), to, tokenId, 1);
+ }
+
+ /**
+ * @dev Destroys `tokenId`.
+ * The approval is cleared when the token is burned.
+ * This is an internal function that does not check if the sender is authorized to operate on the token.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ *
+ * Emits a {Transfer} event.
+ */
+ function _burn(uint256 tokenId) internal virtual {
+ address owner = ERC721.ownerOf(tokenId);
+
+ _beforeTokenTransfer(owner, address(0), tokenId, 1);
+
+ // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
+ owner = ERC721.ownerOf(tokenId);
+
+ // Clear approvals
+ delete _tokenApprovals[tokenId];
+
+ unchecked {
+ // Cannot overflow, as that would require more tokens to be burned/transferred
+ // out than the owner initially received through minting and transferring in.
+ _balances[owner] -= 1;
+ }
+ delete _owners[tokenId];
+
+ emit Transfer(owner, address(0), tokenId);
+
+ _afterTokenTransfer(owner, address(0), tokenId, 1);
+ }
+
+ /**
+ * @dev Transfers `tokenId` from `from` to `to`.
+ * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
+ *
+ * Requirements:
+ *
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must be owned by `from`.
+ *
+ * Emits a {Transfer} event.
+ */
+ function _transfer(
+ address from,
+ address to,
+ uint256 tokenId
+ ) internal virtual {
+ require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
+ require(to != address(0), "ERC721: transfer to the zero address");
+
+ _beforeTokenTransfer(from, to, tokenId, 1);
+
+ // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
+ require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
+
+ // Clear approvals from the previous owner
+ delete _tokenApprovals[tokenId];
+
+ unchecked {
+ // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
+ // `from`'s balance is the number of token held, which is at least one before the current
+ // transfer.
+ // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
+ // all 2**256 token ids to be minted, which in practice is impossible.
+ _balances[from] -= 1;
+ _balances[to] += 1;
+ }
+ _owners[tokenId] = to;
+
+ emit Transfer(from, to, tokenId);
+
+ _afterTokenTransfer(from, to, tokenId, 1);
+ }
+
+ /**
+ * @dev Approve `to` to operate on `tokenId`
+ *
+ * Emits an {Approval} event.
+ */
+ function _approve(address to, uint256 tokenId) internal virtual {
+ _tokenApprovals[tokenId] = to;
+ emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
+ }
+
+ /**
+ * @dev Approve `operator` to operate on all of `owner` tokens
+ *
+ * Emits an {ApprovalForAll} event.
+ */
+ function _setApprovalForAll(
+ address owner,
+ address operator,
+ bool approved
+ ) internal virtual {
+ require(owner != operator, "ERC721: approve to caller");
+ _operatorApprovals[owner][operator] = approved;
+ emit ApprovalForAll(owner, operator, approved);
+ }
+
+ /**
+ * @dev Reverts if the `tokenId` has not been minted yet.
+ */
+ function _requireMinted(uint256 tokenId) internal view virtual {
+ require(_exists(tokenId), "ERC721: invalid token ID");
+ }
+
+ /**
+ * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
+ * The call is not executed if the target address is not a contract.
+ *
+ * @param from address representing the previous owner of the given token ID
+ * @param to target address that will receive the tokens
+ * @param tokenId uint256 ID of the token to be transferred
+ * @param data bytes optional data to send along with the call
+ * @return bool whether the call correctly returned the expected magic value
+ */
+ function _checkOnERC721Received(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) private returns (bool) {
+ if (to.isContract()) {
+ try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
+ return retval == IERC721Receiver.onERC721Received.selector;
+ } catch (bytes memory reason) {
+ if (reason.length == 0) {
+ revert("ERC721: transfer to non ERC721Receiver implementer");
+ } else {
+ /// @solidity memory-safe-assembly
+ assembly {
+ revert(add(32, reason), mload(reason))
+ }
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
+ * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
+ *
+ * Calling conditions:
+ *
+ * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
+ * - When `from` is zero, the tokens will be minted for `to`.
+ * - When `to` is zero, ``from``'s tokens will be burned.
+ * - `from` and `to` are never both zero.
+ * - `batchSize` is non-zero.
+ *
+ * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+ */
+ function _beforeTokenTransfer(
+ address from,
+ address to,
+ uint256, /* firstTokenId */
+ uint256 batchSize
+ ) internal virtual {
+ if (batchSize > 1) {
+ if (from != address(0)) {
+ _balances[from] -= batchSize;
+ }
+ if (to != address(0)) {
+ _balances[to] += batchSize;
+ }
+ }
+ }
+
+ /**
+ * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
+ * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
+ *
+ * Calling conditions:
+ *
+ * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
+ * - When `from` is zero, the tokens were minted for `to`.
+ * - When `to` is zero, ``from``'s tokens were burned.
+ * - `from` and `to` are never both zero.
+ * - `batchSize` is non-zero.
+ *
+ * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+ */
+ function _afterTokenTransfer(
+ address from,
+ address to,
+ uint256 firstTokenId,
+ uint256 batchSize
+ ) internal virtual {}
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721.sol
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
+
+pragma solidity ^0.8.0;
+
+import "../../utils/introspection/IERC165.sol";
+
+/**
+ * @dev Required interface of an ERC721 compliant contract.
+ */
+interface IERC721 is IERC165 {
+ /**
+ * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+
+ /**
+ * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
+ */
+ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+
+ /**
+ * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
+ */
+ event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+
+ /**
+ * @dev Returns the number of tokens in ``owner``'s account.
+ */
+ function balanceOf(address owner) external view returns (uint256 balance);
+
+ /**
+ * @dev Returns the owner of the `tokenId` token.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ */
+ function ownerOf(uint256 tokenId) external view returns (address owner);
+
+ /**
+ * @dev Safely transfers `tokenId` token from `from` to `to`.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must exist and be owned by `from`.
+ * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
+ * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+ *
+ * Emits a {Transfer} event.
+ */
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes calldata data
+ ) external;
+
+ /**
+ * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
+ * are aware of the ERC721 protocol to prevent tokens from being forever locked.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must exist and be owned by `from`.
+ * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
+ * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+ *
+ * Emits a {Transfer} event.
+ */
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /**
+ * @dev Transfers `tokenId` token from `from` to `to`.
+ *
+ * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
+ * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
+ * understand this adds an external call which potentially creates a reentrancy vulnerability.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `tokenId` token must be owned by `from`.
+ * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /**
+ * @dev Gives permission to `to` to transfer `tokenId` token to another account.
+ * The approval is cleared when the token is transferred.
+ *
+ * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
+ *
+ * Requirements:
+ *
+ * - The caller must own the token or be an approved operator.
+ * - `tokenId` must exist.
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address to, uint256 tokenId) external;
+
+ /**
+ * @dev Approve or remove `operator` as an operator for the caller.
+ * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
+ *
+ * Requirements:
+ *
+ * - The `operator` cannot be the caller.
+ *
+ * Emits an {ApprovalForAll} event.
+ */
+ function setApprovalForAll(address operator, bool _approved) external;
+
+ /**
+ * @dev Returns the account approved for `tokenId` token.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ */
+ function getApproved(uint256 tokenId) external view returns (address operator);
+
+ /**
+ * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
+ *
+ * See {setApprovalForAll}
+ */
+ function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721Receiver.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @title ERC721 token receiver interface
+ * @dev Interface for any contract that wants to support safeTransfers
+ * from ERC721 asset contracts.
+ */
+interface IERC721Receiver {
+ /**
+ * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
+ * by `operator` from `from`, this function is called.
+ *
+ * It must return its Solidity selector to confirm the token transfer.
+ * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
+ *
+ * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
+ */
+ function onERC721Received(
+ address operator,
+ address from,
+ uint256 tokenId,
+ bytes calldata data
+ ) external returns (bytes4);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+import "../../../utils/Context.sol";
+
+/**
+ * @title ERC721 Burnable Token
+ * @dev ERC721 Token that can be burned (destroyed).
+ */
+abstract contract ERC721Burnable is Context, ERC721 {
+ /**
+ * @dev Burns `tokenId`. See {ERC721-_burn}.
+ *
+ * Requirements:
+ *
+ * - The caller must own `tokenId` or be an approved operator.
+ */
+ function burn(uint256 tokenId) public virtual {
+ //solhint-disable-next-line max-line-length
+ require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
+ _burn(tokenId);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+import "./IERC721Enumerable.sol";
+
+/**
+ * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
+ * enumerability of all the token ids in the contract as well as all token ids owned by each
+ * account.
+ */
+abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
+ // Mapping from owner to list of owned token IDs
+ mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
+
+ // Mapping from token ID to index of the owner tokens list
+ mapping(uint256 => uint256) private _ownedTokensIndex;
+
+ // Array with all token ids, used for enumeration
+ uint256[] private _allTokens;
+
+ // Mapping from token id to position in the allTokens array
+ mapping(uint256 => uint256) private _allTokensIndex;
+
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
+ return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
+ }
+
+ /**
+ * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
+ */
+ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
+ require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
+ return _ownedTokens[owner][index];
+ }
+
+ /**
+ * @dev See {IERC721Enumerable-totalSupply}.
+ */
+ function totalSupply() public view virtual override returns (uint256) {
+ return _allTokens.length;
+ }
+
+ /**
+ * @dev See {IERC721Enumerable-tokenByIndex}.
+ */
+ function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
+ require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
+ return _allTokens[index];
+ }
+
+ /**
+ * @dev See {ERC721-_beforeTokenTransfer}.
+ */
+ function _beforeTokenTransfer(
+ address from,
+ address to,
+ uint256 firstTokenId,
+ uint256 batchSize
+ ) internal virtual override {
+ super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
+
+ if (batchSize > 1) {
+ // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
+ revert("ERC721Enumerable: consecutive transfers not supported");
+ }
+
+ uint256 tokenId = firstTokenId;
+
+ if (from == address(0)) {
+ _addTokenToAllTokensEnumeration(tokenId);
+ } else if (from != to) {
+ _removeTokenFromOwnerEnumeration(from, tokenId);
+ }
+ if (to == address(0)) {
+ _removeTokenFromAllTokensEnumeration(tokenId);
+ } else if (to != from) {
+ _addTokenToOwnerEnumeration(to, tokenId);
+ }
+ }
+
+ /**
+ * @dev Private function to add a token to this extension's ownership-tracking data structures.
+ * @param to address representing the new owner of the given token ID
+ * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
+ */
+ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
+ uint256 length = ERC721.balanceOf(to);
+ _ownedTokens[to][length] = tokenId;
+ _ownedTokensIndex[tokenId] = length;
+ }
+
+ /**
+ * @dev Private function to add a token to this extension's token tracking data structures.
+ * @param tokenId uint256 ID of the token to be added to the tokens list
+ */
+ function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
+ _allTokensIndex[tokenId] = _allTokens.length;
+ _allTokens.push(tokenId);
+ }
+
+ /**
+ * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
+ * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
+ * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
+ * This has O(1) time complexity, but alters the order of the _ownedTokens array.
+ * @param from address representing the previous owner of the given token ID
+ * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
+ */
+ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
+ // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
+ // then delete the last slot (swap and pop).
+
+ uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
+ uint256 tokenIndex = _ownedTokensIndex[tokenId];
+
+ // When the token to delete is the last token, the swap operation is unnecessary
+ if (tokenIndex != lastTokenIndex) {
+ uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
+
+ _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
+ _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
+ }
+
+ // This also deletes the contents at the last position of the array
+ delete _ownedTokensIndex[tokenId];
+ delete _ownedTokens[from][lastTokenIndex];
+ }
+
+ /**
+ * @dev Private function to remove a token from this extension's token tracking data structures.
+ * This has O(1) time complexity, but alters the order of the _allTokens array.
+ * @param tokenId uint256 ID of the token to be removed from the tokens list
+ */
+ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
+ // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
+ // then delete the last slot (swap and pop).
+
+ uint256 lastTokenIndex = _allTokens.length - 1;
+ uint256 tokenIndex = _allTokensIndex[tokenId];
+
+ // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
+ // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
+ // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
+ uint256 lastTokenId = _allTokens[lastTokenIndex];
+
+ _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
+ _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
+
+ // This also deletes the contents at the last position of the array
+ delete _allTokensIndex[tokenId];
+ _allTokens.pop();
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+
+/**
+ * @dev ERC721 token with storage based token URI management.
+ */
+abstract contract ERC721URIStorage is ERC721 {
+ using Strings for uint256;
+
+ // Optional mapping for token URIs
+ mapping(uint256 => string) private _tokenURIs;
+
+ /**
+ * @dev See {IERC721Metadata-tokenURI}.
+ */
+ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
+ _requireMinted(tokenId);
+
+ string memory _tokenURI = _tokenURIs[tokenId];
+ string memory base = _baseURI();
+
+ // If there is no base URI, return the token URI.
+ if (bytes(base).length == 0) {
+ return _tokenURI;
+ }
+ // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
+ if (bytes(_tokenURI).length > 0) {
+ return string(abi.encodePacked(base, _tokenURI));
+ }
+
+ return super.tokenURI(tokenId);
+ }
+
+ /**
+ * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
+ *
+ * Requirements:
+ *
+ * - `tokenId` must exist.
+ */
+ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
+ require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
+ _tokenURIs[tokenId] = _tokenURI;
+ }
+
+ /**
+ * @dev See {ERC721-_burn}. This override additionally checks to see if a
+ * token-specific URI was set for the token, and if so, it deletes the token URI from
+ * the storage mapping.
+ */
+ function _burn(uint256 tokenId) internal virtual override {
+ super._burn(tokenId);
+
+ if (bytes(_tokenURIs[tokenId]).length != 0) {
+ delete _tokenURIs[tokenId];
+ }
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../IERC721.sol";
+
+/**
+ * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
+ * @dev See https://eips.ethereum.org/EIPS/eip-721
+ */
+interface IERC721Enumerable is IERC721 {
+ /**
+ * @dev Returns the total amount of tokens stored by the contract.
+ */
+ function totalSupply() external view returns (uint256);
+
+ /**
+ * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
+ * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
+ */
+ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
+
+ /**
+ * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
+ * Use along with {totalSupply} to enumerate all tokens.
+ */
+ function tokenByIndex(uint256 index) external view returns (uint256);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
+
+pragma solidity ^0.8.0;
+
+import "../IERC721.sol";
+
+/**
+ * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+ * @dev See https://eips.ethereum.org/EIPS/eip-721
+ */
+interface IERC721Metadata is IERC721 {
+ /**
+ * @dev Returns the token collection name.
+ */
+ function name() external view returns (string memory);
+
+ /**
+ * @dev Returns the token collection symbol.
+ */
+ function symbol() external view returns (string memory);
+
+ /**
+ * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
+ */
+ function tokenURI(uint256 tokenId) external view returns (string memory);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Address.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Address.sol
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+pragma solidity ^0.8.1;
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev Returns true if `account` is a contract.
+ *
+ * [IMPORTANT]
+ * ====
+ * It is unsafe to assume that an address for which this function returns
+ * false is an externally-owned account (EOA) and not a contract.
+ *
+ * Among others, `isContract` will return false for the following
+ * types of addresses:
+ *
+ * - an externally-owned account
+ * - a contract in construction
+ * - an address where a contract will be created
+ * - an address where a contract lived, but was destroyed
+ * ====
+ *
+ * [IMPORTANT]
+ * ====
+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
+ *
+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+ * constructor.
+ * ====
+ */
+ function isContract(address account) internal view returns (bool) {
+ // This method relies on extcodesize/address.code.length, which returns 0
+ // for contracts in construction, since the code is only stored at the end
+ // of the constructor execution.
+
+ return account.code.length > 0;
+ }
+
+ /**
+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+ * `recipient`, forwarding all available gas and reverting on errors.
+ *
+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
+ * imposed by `transfer`, making them unable to receive funds via
+ * `transfer`. {sendValue} removes this limitation.
+ *
+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+ *
+ * IMPORTANT: because control is transferred to `recipient`, care must be
+ * taken to not create reentrancy vulnerabilities. Consider using
+ * {ReentrancyGuard} or the
+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ require(address(this).balance >= amount, "Address: insufficient balance");
+
+ (bool success, ) = recipient.call{value: amount}("");
+ require(success, "Address: unable to send value, recipient may have reverted");
+ }
+
+ /**
+ * @dev Performs a Solidity function call using a low level `call`. A
+ * plain `call` is an unsafe replacement for a function call: use this
+ * function instead.
+ *
+ * If `target` reverts with a revert reason, it is bubbled up by this
+ * function (like regular Solidity function calls).
+ *
+ * Returns the raw returned data. To convert to the expected return value,
+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+ *
+ * Requirements:
+ *
+ * - `target` must be a contract.
+ * - calling `target` with `data` must not revert.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+ * `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but also transferring `value` wei to `target`.
+ *
+ * Requirements:
+ *
+ * - the calling contract must have an ETH balance of at least `value`.
+ * - the called Solidity function must be `payable`.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value
+ ) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+ * with `errorMessage` as a fallback revert reason when `target` reverts.
+ *
+ * _Available since v3.1._
+ */
+ function functionCallWithValue(
+ address target,
+ bytes memory data,
+ uint256 value,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ require(address(this).balance >= value, "Address: insufficient balance for call");
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ return functionStaticCall(target, data, "Address: low-level static call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a static call.
+ *
+ * _Available since v3.3._
+ */
+ function functionStaticCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+ * but performing a delegate call.
+ *
+ * _Available since v3.4._
+ */
+ function functionDelegateCall(
+ address target,
+ bytes memory data,
+ string memory errorMessage
+ ) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+ *
+ * _Available since v4.8._
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal view returns (bytes memory) {
+ if (success) {
+ if (returndata.length == 0) {
+ // only check isContract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ require(isContract(target), "Address: call to non-contract");
+ }
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+ * revert reason or using the provided one.
+ *
+ * _Available since v4.3._
+ */
+ function verifyCallResult(
+ bool success,
+ bytes memory returndata,
+ string memory errorMessage
+ ) internal pure returns (bytes memory) {
+ if (success) {
+ return returndata;
+ } else {
+ _revert(returndata, errorMessage);
+ }
+ }
+
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
+ // Look for revert reason and bubble it up if present
+ if (returndata.length > 0) {
+ // The easiest way to bubble the revert reason is using memory via assembly
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert(errorMessage);
+ }
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Context.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+ function _msgSender() internal view virtual returns (address) {
+ return msg.sender;
+ }
+
+ function _msgData() internal view virtual returns (bytes calldata) {
+ return msg.data;
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Counters.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @title Counters
+ * @author Matt Condon (@shrugs)
+ * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
+ * of elements in a mapping, issuing ERC721 ids, or counting request ids.
+ *
+ * Include with `using Counters for Counters.Counter;`
+ */
+library Counters {
+ struct Counter {
+ // This variable should never be directly accessed by users of the library: interactions must be restricted to
+ // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
+ // this feature: see https://github.com/ethereum/solidity/issues/4637
+ uint256 _value; // default: 0
+ }
+
+ function current(Counter storage counter) internal view returns (uint256) {
+ return counter._value;
+ }
+
+ function increment(Counter storage counter) internal {
+ unchecked {
+ counter._value += 1;
+ }
+ }
+
+ function decrement(Counter storage counter) internal {
+ uint256 value = counter._value;
+ require(value > 0, "Counter: decrement overflow");
+ unchecked {
+ counter._value = value - 1;
+ }
+ }
+
+ function reset(Counter storage counter) internal {
+ counter._value = 0;
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Strings.sol
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
+
+pragma solidity ^0.8.0;
+
+import "./math/Math.sol";
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+ bytes16 private constant _SYMBOLS = "0123456789abcdef";
+ uint8 private constant _ADDRESS_LENGTH = 20;
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+ */
+ function toString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ uint256 length = Math.log10(value) + 1;
+ string memory buffer = new string(length);
+ uint256 ptr;
+ /// @solidity memory-safe-assembly
+ assembly {
+ ptr := add(buffer, add(32, length))
+ }
+ while (true) {
+ ptr--;
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+ }
+ value /= 10;
+ if (value == 0) break;
+ }
+ return buffer;
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+ */
+ function toHexString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ return toHexString(value, Math.log256(value) + 1);
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+ */
+ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+ bytes memory buffer = new bytes(2 * length + 2);
+ buffer[0] = "0";
+ buffer[1] = "x";
+ for (uint256 i = 2 * length + 1; i > 1; --i) {
+ buffer[i] = _SYMBOLS[value & 0xf];
+ value >>= 4;
+ }
+ require(value == 0, "Strings: hex length insufficient");
+ return string(buffer);
+ }
+
+ /**
+ * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
+ */
+ function toHexString(address addr) internal pure returns (string memory) {
+ return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/ERC165.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/ERC165.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC165.sol";
+
+/**
+ * @dev Implementation of the {IERC165} interface.
+ *
+ * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
+ * for the additional interface id that will be supported. For example:
+ *
+ * ```solidity
+ * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
+ * }
+ * ```
+ *
+ * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
+ */
+abstract contract ERC165 is IERC165 {
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return interfaceId == type(IERC165).interfaceId;
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/IERC165.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/IERC165.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC165 standard, as defined in the
+ * https://eips.ethereum.org/EIPS/eip-165[EIP].
+ *
+ * Implementers can declare support of contract interfaces, which can then be
+ * queried by others ({ERC165Checker}).
+ *
+ * For an implementation, see {ERC165}.
+ */
+interface IERC165 {
+ /**
+ * @dev Returns true if this contract implements the interface defined by
+ * `interfaceId`. See the corresponding
+ * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
+ * to learn more about how these ids are created.
+ *
+ * This function call must use less than 30 000 gas.
+ */
+ function supportsInterface(bytes4 interfaceId) external view returns (bool);
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/math/Math.sol
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+ enum Rounding {
+ Down, // Toward negative infinity
+ Up, // Toward infinity
+ Zero // Toward zero
+ }
+
+ /**
+ * @dev Returns the largest of two numbers.
+ */
+ function max(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a > b ? a : b;
+ }
+
+ /**
+ * @dev Returns the smallest of two numbers.
+ */
+ function min(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a < b ? a : b;
+ }
+
+ /**
+ * @dev Returns the average of two numbers. The result is rounded towards
+ * zero.
+ */
+ function average(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b) / 2 can overflow.
+ return (a & b) + (a ^ b) / 2;
+ }
+
+ /**
+ * @dev Returns the ceiling of the division of two numbers.
+ *
+ * This differs from standard division with `/` in that it rounds up instead
+ * of rounding down.
+ */
+ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b - 1) / b can overflow on addition, so we distribute.
+ return a == 0 ? 0 : (a - 1) / b + 1;
+ }
+
+ /**
+ * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
+ * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
+ * with further edits by Uniswap Labs also under MIT license.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator
+ ) internal pure returns (uint256 result) {
+ unchecked {
+ // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+ // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+ // variables such that product = prod1 * 2^256 + prod0.
+ uint256 prod0; // Least significant 256 bits of the product
+ uint256 prod1; // Most significant 256 bits of the product
+ assembly {
+ let mm := mulmod(x, y, not(0))
+ prod0 := mul(x, y)
+ prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+ }
+
+ // Handle non-overflow cases, 256 by 256 division.
+ if (prod1 == 0) {
+ return prod0 / denominator;
+ }
+
+ // Make sure the result is less than 2^256. Also prevents denominator == 0.
+ require(denominator > prod1);
+
+ ///////////////////////////////////////////////
+ // 512 by 256 division.
+ ///////////////////////////////////////////////
+
+ // Make division exact by subtracting the remainder from [prod1 prod0].
+ uint256 remainder;
+ assembly {
+ // Compute remainder using mulmod.
+ remainder := mulmod(x, y, denominator)
+
+ // Subtract 256 bit number from 512 bit number.
+ prod1 := sub(prod1, gt(remainder, prod0))
+ prod0 := sub(prod0, remainder)
+ }
+
+ // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
+ // See https://cs.stackexchange.com/q/138556/92363.
+
+ // Does not overflow because the denominator cannot be zero at this stage in the function.
+ uint256 twos = denominator & (~denominator + 1);
+ assembly {
+ // Divide denominator by twos.
+ denominator := div(denominator, twos)
+
+ // Divide [prod1 prod0] by twos.
+ prod0 := div(prod0, twos)
+
+ // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+ twos := add(div(sub(0, twos), twos), 1)
+ }
+
+ // Shift in bits from prod1 into prod0.
+ prod0 |= prod1 * twos;
+
+ // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+ // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+ // four bits. That is, denominator * inv = 1 mod 2^4.
+ uint256 inverse = (3 * denominator) ^ 2;
+
+ // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
+ // in modular arithmetic, doubling the correct bits in each step.
+ inverse *= 2 - denominator * inverse; // inverse mod 2^8
+ inverse *= 2 - denominator * inverse; // inverse mod 2^16
+ inverse *= 2 - denominator * inverse; // inverse mod 2^32
+ inverse *= 2 - denominator * inverse; // inverse mod 2^64
+ inverse *= 2 - denominator * inverse; // inverse mod 2^128
+ inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+ // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+ // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+ // is no longer required.
+ result = prod0 * inverse;
+ return result;
+ }
+ }
+
+ /**
+ * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+ */
+ function mulDiv(
+ uint256 x,
+ uint256 y,
+ uint256 denominator,
+ Rounding rounding
+ ) internal pure returns (uint256) {
+ uint256 result = mulDiv(x, y, denominator);
+ if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
+ result += 1;
+ }
+ return result;
+ }
+
+ /**
+ * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
+ *
+ * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+ */
+ function sqrt(uint256 a) internal pure returns (uint256) {
+ if (a == 0) {
+ return 0;
+ }
+
+ // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+ //
+ // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+ // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+ //
+ // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+ // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+ // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+ //
+ // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+ uint256 result = 1 << (log2(a) >> 1);
+
+ // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+ // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+ // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+ // into the expected uint128 result.
+ unchecked {
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ return min(result, a / result);
+ }
+ }
+
+ /**
+ * @notice Calculates sqrt(a), following the selected rounding direction.
+ */
+ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = sqrt(a);
+ return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 2, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 128;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 64;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 32;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 16;
+ }
+ if (value >> 8 > 0) {
+ value >>= 8;
+ result += 8;
+ }
+ if (value >> 4 > 0) {
+ value >>= 4;
+ result += 4;
+ }
+ if (value >> 2 > 0) {
+ value >>= 2;
+ result += 2;
+ }
+ if (value >> 1 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log2(value);
+ return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 10, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >= 10**64) {
+ value /= 10**64;
+ result += 64;
+ }
+ if (value >= 10**32) {
+ value /= 10**32;
+ result += 32;
+ }
+ if (value >= 10**16) {
+ value /= 10**16;
+ result += 16;
+ }
+ if (value >= 10**8) {
+ value /= 10**8;
+ result += 8;
+ }
+ if (value >= 10**4) {
+ value /= 10**4;
+ result += 4;
+ }
+ if (value >= 10**2) {
+ value /= 10**2;
+ result += 2;
+ }
+ if (value >= 10**1) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log10(value);
+ return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 256, rounded down, of a positive value.
+ * Returns 0 if given 0.
+ *
+ * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+ */
+ function log256(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 16;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 8;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 4;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 2;
+ }
+ if (value >> 8 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log256(value);
+ return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
+ }
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/ZeppelinContract.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/ZeppelinContract.sol
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.9;
+
+import "./@openzeppelin/contracts/token/ERC721/ERC721.sol";
+import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
+import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
+import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
+import "./@openzeppelin/contracts/access/Ownable.sol";
+import "./@openzeppelin/contracts/utils/Counters.sol";
+
+contract ZeppelinContract is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Burnable, Ownable {
+ using Counters for Counters.Counter;
+
+ Counters.Counter private _tokenIdCounter;
+
+ constructor() ERC721("ZeppelinContract", "UNQ") {}
+
+ function _baseURI() internal pure override returns (string memory) {
+ return "test";
+ }
+
+ function safeMint(address to, string memory uri) public onlyOwner {
+ uint256 tokenId = _tokenIdCounter.current();
+ _tokenIdCounter.increment();
+ _safeMint(to, tokenId);
+ _setTokenURI(tokenId, uri);
+ }
+
+ // The following functions are overrides required by Solidity.
+
+ function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
+ internal
+ override(ERC721, ERC721Enumerable)
+ {
+ super._beforeTokenTransfer(from, to, tokenId, batchSize);
+ }
+
+ function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
+ super._burn(tokenId);
+ }
+
+ function tokenURI(uint256 tokenId)
+ public
+ view
+ override(ERC721, ERC721URIStorage)
+ returns (string memory)
+ {
+ return super.tokenURI(tokenId);
+ }
+
+ function supportsInterface(bytes4 interfaceId)
+ public
+ view
+ override(ERC721, ERC721Enumerable)
+ returns (bool)
+ {
+ return super.supportsInterface(interfaceId);
+ }
+}
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.abidiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.abi
@@ -0,0 +1 @@
+[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"string","name":"uri","type":"string"}],"name":"safeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.bindiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.bin
@@ -0,0 +1 @@
+60806040523480156200001157600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b815250816000908162000068919062000195565b50600162000077828262000195565b505050620000946200008e6200009a60201b60201c565b6200009e565b62000261565b3390565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200011b57607f821691505b6020821081036200013c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019057600081815260208120601f850160051c810160208610156200016b5750805b601f850160051c820191505b818110156200018c5782815560010162000177565b5050505b505050565b81516001600160401b03811115620001b157620001b1620000f0565b620001c981620001c2845462000106565b8462000142565b602080601f831160018114620002015760008415620001e85750858301515b600019600386901b1c1916600185901b1785556200018c565b600085815260208120601f198616915b82811015620002325788860151825594840194600190910190840162000211565b5085821015620002515787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611f0d80620002716000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80636352211e116100b8578063a22cb4651161007c578063a22cb46514610271578063b88d4fde14610284578063c87b56dd14610297578063d204c45e146102aa578063e985e9c5146102bd578063f2fde38b146102f957600080fd5b80636352211e1461022a57806370a082311461023d578063715018a6146102505780638da5cb5b1461025857806395d89b411461026957600080fd5b806323b872dd116100ff57806323b872dd146101cb5780632f745c59146101de57806342842e0e146101f157806342966c68146102045780634f6ccce71461021757600080fd5b806301ffc9a71461013c57806306fdde0314610164578063081812fc14610179578063095ea7b3146101a457806318160ddd146101b9575b600080fd5b61014f61014a3660046118ab565b61030c565b60405190151581526020015b60405180910390f35b61016c61031d565b60405161015b9190611918565b61018c61018736600461192b565b6103af565b6040516001600160a01b03909116815260200161015b565b6101b76101b2366004611960565b6103d6565b005b6008545b60405190815260200161015b565b6101b76101d936600461198a565b6104f0565b6101bd6101ec366004611960565b610522565b6101b76101ff36600461198a565b6105b8565b6101b761021236600461192b565b6105d3565b6101bd61022536600461192b565b610604565b61018c61023836600461192b565b610697565b6101bd61024b3660046119c6565b6106f7565b6101b761077d565b600b546001600160a01b031661018c565b61016c610791565b6101b761027f3660046119e1565b6107a0565b6101b7610292366004611aa9565b6107af565b61016c6102a536600461192b565b6107e7565b6101b76102b8366004611b25565b6107f2565b61014f6102cb366004611b87565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6101b76103073660046119c6565b610829565b60006103178261089f565b92915050565b60606000805461032c90611bba565b80601f016020809104026020016040519081016040528092919081815260200182805461035890611bba565b80156103a55780601f1061037a576101008083540402835291602001916103a5565b820191906000526020600020905b81548152906001019060200180831161038857829003601f168201915b5050505050905090565b60006103ba826108c4565b506000908152600460205260409020546001600160a01b031690565b60006103e182610697565b9050806001600160a01b0316836001600160a01b0316036104535760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061046f575061046f81336102cb565b6104e15760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161044a565b6104eb8383610923565b505050565b6104fb335b82610991565b6105175760405162461bcd60e51b815260040161044a90611bf4565b6104eb838383610a10565b600061052d836106f7565b821061058f5760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b606482015260840161044a565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6104eb838383604051806020016040528060008152506107af565b6105dc336104f5565b6105f85760405162461bcd60e51b815260040161044a90611bf4565b61060181610b81565b50565b600061060f60085490565b82106106725760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b606482015260840161044a565b6008828154811061068557610685611c41565b90600052602060002001549050919050565b6000818152600260205260408120546001600160a01b0316806103175760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b60006001600160a01b0382166107615760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161044a565b506001600160a01b031660009081526003602052604090205490565b610785610b8a565b61078f6000610be4565b565b60606001805461032c90611bba565b6107ab338383610c36565b5050565b6107b93383610991565b6107d55760405162461bcd60e51b815260040161044a90611bf4565b6107e184848484610d04565b50505050565b606061031782610d37565b6107fa610b8a565b6000610805600c5490565b9050610815600c80546001019055565b61081f8382610e4b565b6104eb8183610e65565b610831610b8a565b6001600160a01b0381166108965760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161044a565b61060181610be4565b60006001600160e01b0319821663780e9d6360e01b1480610317575061031782610ef8565b6000818152600260205260409020546001600160a01b03166106015760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061095882610697565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061099d83610697565b9050806001600160a01b0316846001600160a01b031614806109e457506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80610a085750836001600160a01b03166109fd846103af565b6001600160a01b0316145b949350505050565b826001600160a01b0316610a2382610697565b6001600160a01b031614610a495760405162461bcd60e51b815260040161044a90611c57565b6001600160a01b038216610aab5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161044a565b610ab88383836001610f48565b826001600160a01b0316610acb82610697565b6001600160a01b031614610af15760405162461bcd60e51b815260040161044a90611c57565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61060181610f54565b600b546001600160a01b0316331461078f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161044a565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b031603610c975760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161044a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b610d0f848484610a10565b610d1b84848484610f94565b6107e15760405162461bcd60e51b815260040161044a90611c9c565b6060610d42826108c4565b6000828152600a602052604081208054610d5b90611bba565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8790611bba565b8015610dd45780601f10610da957610100808354040283529160200191610dd4565b820191906000526020600020905b815481529060010190602001808311610db757829003601f168201915b505050505090506000610dfe6040805180820190915260048152631d195cdd60e21b602082015290565b90508051600003610e10575092915050565b815115610e42578082604051602001610e2a929190611cee565b60405160208183030381529060405292505050919050565b610a0884611095565b6107ab828260405180602001604052806000815250611115565b6000828152600260205260409020546001600160a01b0316610ee05760405162461bcd60e51b815260206004820152602e60248201527f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b606482015260840161044a565b6000828152600a602052604090206104eb8282611d6b565b60006001600160e01b031982166380ac58cd60e01b1480610f2957506001600160e01b03198216635b5e139f60e01b145b8061031757506301ffc9a760e01b6001600160e01b0319831614610317565b6107e184848484611148565b610f5d81611288565b6000818152600a602052604090208054610f7690611bba565b159050610601576000818152600a6020526040812061060191611847565b60006001600160a01b0384163b1561108a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610fd8903390899088908890600401611e2b565b6020604051808303816000875af1925050508015611013575060408051601f3d908101601f1916820190925261101091810190611e68565b60015b611070573d808015611041576040519150601f19603f3d011682016040523d82523d6000602084013e611046565b606091505b5080516000036110685760405162461bcd60e51b815260040161044a90611c9c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610a08565b506001949350505050565b60606110a0826108c4565b60006110c36040805180820190915260048152631d195cdd60e21b602082015290565b905060008151116110e3576040518060200160405280600081525061110e565b806110ed8461132b565b6040516020016110fe929190611cee565b6040516020818303038152906040525b9392505050565b61111f83836113be565b61112c6000848484610f94565b6104eb5760405162461bcd60e51b815260040161044a90611c9c565b61115484848484611557565b60018111156111c35760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b606482015260840161044a565b816001600160a01b03851661121f5761121a81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611242565b836001600160a01b0316856001600160a01b0316146112425761124285826115df565b6001600160a01b03841661125e576112598161167c565b611281565b846001600160a01b0316846001600160a01b03161461128157611281848261172b565b5050505050565b600061129382610697565b90506112a3816000846001610f48565b6112ac82610697565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b606060006113388361176f565b600101905060008167ffffffffffffffff81111561135857611358611a1d565b6040519080825280601f01601f191660200182016040528015611382576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461138c57509392505050565b6001600160a01b0382166114145760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161044a565b6000818152600260205260409020546001600160a01b0316156114795760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b611487600083836001610f48565b6000818152600260205260409020546001600160a01b0316156114ec5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60018111156107e1576001600160a01b0384161561159d576001600160a01b03841660009081526003602052604081208054839290611597908490611e9b565b90915550505b6001600160a01b038316156107e1576001600160a01b038316600090815260036020526040812080548392906115d4908490611eae565b909155505050505050565b600060016115ec846106f7565b6115f69190611e9b565b600083815260076020526040902054909150808214611649576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b60085460009061168e90600190611e9b565b600083815260096020526040812054600880549394509092849081106116b6576116b6611c41565b9060005260206000200154905080600883815481106116d7576116d7611c41565b600091825260208083209091019290925582815260099091526040808220849055858252812055600880548061170f5761170f611ec1565b6001900381819060005260206000200160009055905550505050565b6000611736836106f7565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106117ae5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106117da576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106117f857662386f26fc10000830492506010015b6305f5e1008310611810576305f5e100830492506008015b612710831061182457612710830492506004015b60648310611836576064830492506002015b600a83106103175760010192915050565b50805461185390611bba565b6000825580601f10611863575050565b601f01602090049060005260206000209081019061060191905b80821115611891576000815560010161187d565b5090565b6001600160e01b03198116811461060157600080fd5b6000602082840312156118bd57600080fd5b813561110e81611895565b60005b838110156118e35781810151838201526020016118cb565b50506000910152565b600081518084526119048160208601602086016118c8565b601f01601f19169290920160200192915050565b60208152600061110e60208301846118ec565b60006020828403121561193d57600080fd5b5035919050565b80356001600160a01b038116811461195b57600080fd5b919050565b6000806040838503121561197357600080fd5b61197c83611944565b946020939093013593505050565b60008060006060848603121561199f57600080fd5b6119a884611944565b92506119b660208501611944565b9150604084013590509250925092565b6000602082840312156119d857600080fd5b61110e82611944565b600080604083850312156119f457600080fd5b6119fd83611944565b915060208301358015158114611a1257600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611a4e57611a4e611a1d565b604051601f8501601f19908116603f01168101908282118183101715611a7657611a76611a1d565b81604052809350858152868686011115611a8f57600080fd5b858560208301376000602087830101525050509392505050565b60008060008060808587031215611abf57600080fd5b611ac885611944565b9350611ad660208601611944565b925060408501359150606085013567ffffffffffffffff811115611af957600080fd5b8501601f81018713611b0a57600080fd5b611b1987823560208401611a33565b91505092959194509250565b60008060408385031215611b3857600080fd5b611b4183611944565b9150602083013567ffffffffffffffff811115611b5d57600080fd5b8301601f81018513611b6e57600080fd5b611b7d85823560208401611a33565b9150509250929050565b60008060408385031215611b9a57600080fd5b611ba383611944565b9150611bb160208401611944565b90509250929050565b600181811c90821680611bce57607f821691505b602082108103611bee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60008351611d008184602088016118c8565b835190830190611d148183602088016118c8565b01949350505050565b601f8211156104eb57600081815260208120601f850160051c81016020861015611d445750805b601f850160051c820191505b81811015611d6357828155600101611d50565b505050505050565b815167ffffffffffffffff811115611d8557611d85611a1d565b611d9981611d938454611bba565b84611d1d565b602080601f831160018114611dce5760008415611db65750858301515b600019600386901b1c1916600185901b178555611d63565b600085815260208120601f198616915b82811015611dfd57888601518255948401946001909101908401611dde565b5085821015611e1b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611e5e908301846118ec565b9695505050505050565b600060208284031215611e7a57600080fd5b815161110e81611895565b634e487b7160e01b600052601160045260246000fd5b8181038181111561031757610317611e85565b8082018082111561031757610317611e85565b634e487b7160e01b600052603160045260246000fdfea26469706673582212207960bc65d7484ab1502ccdc352c91f0fb91535a525cf99e1b6392e242548279a64736f6c63430008110033
\ No newline at end of file
js-packages/scripts/benchmarks/utils/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/benchmarks/utils/types.ts
@@ -0,0 +1,62 @@
+export interface IFeeGas {
+ fee?: number | bigint,
+ gas?: number | bigint,
+ substrate?: number,
+ zeppelin?: {
+ fee: number | bigint,
+ gas: number | bigint,
+ }
+
+}
+export interface IFeeGasCsv extends IFeeGasVm {
+ function: string,
+}
+export interface IFeeGasVm{
+ ethFee?: number | bigint,
+ ethGas?: number | bigint,
+ substrate?: number,
+ zeppelinFee?: number | bigint,
+ zeppelinGas?: number | bigint
+}
+export interface IFunctionFee {
+ [name: string]: IFeeGas
+}
+
+
+export abstract class FunctionFeeVM {
+ [name: string]: IFeeGasVm
+
+ static toCsv(model: FunctionFeeVM): IFeeGasCsv[]{
+ const res: IFeeGasCsv[] = [];
+ Object.keys(model).forEach(key => {
+ res.push({
+ function: key,
+ ethFee: model[key].ethFee,
+ ethGas: model[key].ethGas,
+ substrate: model[key].substrate,
+ zeppelinFee: model[key].zeppelinFee,
+ zeppelinGas: model[key].zeppelinGas,
+ });
+ });
+ return res;
+ }
+ static fromModel(model: IFunctionFee): FunctionFeeVM {
+ const res: FunctionFeeVM = {};
+
+ Object.keys(model).forEach(key => {
+ res[key] = {};
+ if(model[key].fee && model[key].gas) {
+ res[key].ethFee = model[key].fee;
+ res[key].ethGas = model[key].gas;
+ }
+ if(model[key].substrate)
+ res[key].substrate = model[key].substrate;
+ if(model[key].zeppelin) {
+ res[key].zeppelinFee = model[key].zeppelin?.fee;
+ res[key].zeppelinGas = model[key].zeppelin?.gas;
+ }
+ });
+
+ return res;
+ }
+}
\ No newline at end of file
js-packages/scripts/calibrate.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/calibrate.ts
@@ -0,0 +1,318 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
+import {EthUniqueHelper} from '@unique/tests//eth/util/playgrounds/unique.dev.js';
+
+class Fract {
+ static ZERO = new Fract(0n);
+ constructor(public readonly a: bigint, public readonly b: bigint = 1n) {
+ if(b === 0n) throw new Error('division by zero');
+ if(b < 0n) throw new Error('missing normalization');
+ }
+
+ mul(other: Fract) {
+ return new Fract(this.a * other.a, this.b * other.b).optimize();
+ }
+
+ div(other: Fract) {
+ return this.mul(other.inv());
+ }
+
+ plus(other: Fract) {
+ if(this.b === other.b) {
+ return new Fract(this.a + other.a, this.b);
+ }
+ return new Fract(this.a * other.b + other.a * this.b, this.b * other.b).optimize();
+ }
+
+ minus(other: Fract) {
+ return this.plus(other.neg());
+ }
+
+ neg() {
+ return new Fract(-this.a, this.b);
+ }
+ inv() {
+ if(this.a < 0) {
+ return new Fract(-this.b, -this.a);
+ } else {
+ return new Fract(this.b, this.a);
+ }
+ }
+
+ optimize() {
+ function gcd(x: bigint, y: bigint) {
+ if(x < 0n)
+ x = -x;
+ if(y < 0n)
+ y = -y;
+ while(y) {
+ const t = y;
+ y = x % y;
+ x = t;
+ }
+ return x;
+ }
+ const v = gcd(this.a, this.b);
+ return new Fract(this.a / v, this.b / v);
+ }
+
+ toBigInt() {
+ return this.a / this.b;
+ }
+ toNumber() {
+ const v = this.optimize();
+ return Number(v.a) / Number(v.b);
+ }
+ toString() {
+ const v = this.optimize();
+ return `${v.a} / ${v.b}`;
+ }
+
+ lt(other: Fract) {
+ return this.a * other.b < other.a * this.b;
+ }
+ eq(other: Fract) {
+ return this.a * other.b === other.a * this.b;
+ }
+
+ sqrt() {
+ if(this.a < 0n) {
+ throw new Error('square root of negative numbers is not supported');
+ }
+
+ if(this.lt(new Fract(2n))) {
+ return this;
+ }
+
+ function newtonIteration(n: Fract, x0: Fract): Fract {
+ const x1 = rpn(n, x0, '/', x0, '+', new Fract(2n), '/');
+ if(x0.eq(x1) || x0.eq(x1.minus(new Fract(1n)))) {
+ return x0;
+ }
+ return newtonIteration(n, x1);
+ }
+
+ return newtonIteration(this, new Fract(1n));
+ }
+}
+
+type Op = Fract | '+' | '-' | '*' | '/' | 'dup' | Op[];
+function rpn(...ops: (Op)[]) {
+ const stack: Fract[] = [];
+ for(const op of ops) {
+ if(op instanceof Fract) {
+ stack.push(op);
+ } else if(op === '+') {
+ if(stack.length < 2)
+ throw new Error('stack underflow');
+ const b = stack.pop()!;
+ const a = stack.pop()!;
+ stack.push(a.plus(b));
+ } else if(op === '*') {
+ if(stack.length < 2)
+ throw new Error('stack underflow');
+ const b = stack.pop()!;
+ const a = stack.pop()!;
+ stack.push(a.mul(b));
+ } else if(op === '-') {
+ if(stack.length < 2)
+ throw new Error('stack underflow');
+ const b = stack.pop()!;
+ const a = stack.pop()!;
+ stack.push(a.minus(b));
+ } else if(op === '/') {
+ if(stack.length < 2)
+ throw new Error('stack underflow');
+ const b = stack.pop()!;
+ const a = stack.pop()!;
+ stack.push(a.div(b));
+ } else if(op === 'dup') {
+ if(stack.length < 1)
+ throw new Error('stack underflow');
+ const a = stack.pop()!;
+ stack.push(a);
+ stack.push(a);
+ } else if(Array.isArray(op)) {
+ stack.push(rpn(...op));
+ } else {
+ throw new Error(`unknown operand: ${op}`);
+ }
+ }
+ if(stack.length != 1)
+ throw new Error('one element should be left on stack');
+ return stack[0]!;
+}
+
+function linearRegression(points: { x: Fract, y: Fract }[]) {
+ let sumxy = Fract.ZERO;
+ let sumx = Fract.ZERO;
+ let sumy = Fract.ZERO;
+ let sumx2 = Fract.ZERO;
+ const n = points.length;
+ for(let i = 0; i < n; i++) {
+ const p = points[i];
+ sumxy = rpn(p.x, p.y, '*', sumxy, '+');
+ sumx = sumx.plus(p.x);
+ sumy = sumy.plus(p.y);
+ sumx2 = rpn(p.x, p.x, '*', sumx2, '+');
+ }
+
+ const nb = new Fract(BigInt(n));
+
+ const a = rpn(
+ [nb, sumxy, '*', sumx, sumy, '*', '-'],
+ [nb, sumx2, '*', sumx, sumx, '*', '-'],
+ '/',
+ );
+ const b = rpn(
+ [sumy, a, sumx, '*', '-'],
+ nb,
+ '/',
+ );
+
+ return {a, b};
+}
+
+const hypothesisLinear = (a: Fract, b: Fract) => (x: Fract) => rpn(x, a, '*', b, '+');
+
+// function error(points: { x: Fract, y: Fract }[], hypothesis: (a: Fract) => Fract) {
+// return points.map(p => {
+// const v = hypothesis(p.x);
+// const vv = p.y;
+
+// return rpn(v, vv, '-', 'dup', '*');
+// }).reduce((a, b) => a.plus(b), Fract.ZERO).sqrt().div(new Fract(BigInt(points.length)));
+// }
+
+async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>) {
+ const alice = await privateKey('//Alice');
+ const bob = await privateKey('//Bob');
+ const dataPoints = [];
+
+ {
+ const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+ await token.transfer(alice, {Substrate: bob.address});
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+
+ console.log(`\t[NFT transfer] Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+ }
+
+ const api = helper.getApi();
+ const base = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt();
+ for(let i = -5; i < 5; i++) {
+ await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(base + base / 1000n * BigInt(i))));
+
+ const coefficient = new Fract((await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt());
+ const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+ await token.transfer(alice, {Substrate: bob.address});
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+
+ const transferPrice = new Fract(aliceBalanceBefore - aliceBalanceAfter);
+
+ dataPoints.push({x: transferPrice, y: coefficient});
+ }
+ const {a, b} = linearRegression(dataPoints);
+
+ const hyp = hypothesisLinear(a, b);
+ // console.log(`\t[NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`);
+
+ // 0.1 UNQ
+ const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(1n, 10n), '*'));
+ await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toBigInt())));
+
+ {
+ const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+ await token.transfer(alice, {Substrate: bob.address});
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+
+ console.log(`\t[NFT transfer] Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+ }
+}
+
+async function calibrateMinGasPrice(helper: EthUniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>) {
+ const alice = await privateKey('//Alice');
+ const caller = await helper.eth.createAccountWithBalance(alice);
+ const receiver = helper.eth.createAccount();
+ const dataPoints = [];
+
+ {
+ const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+ const token = await collection.mintToken(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
+
+ console.log(`\t[ETH NFT transfer] Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+ }
+
+ const api = helper.getApi();
+ // const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt();
+ const base = (await api.query.configuration.minGasPriceOverride() as any).toBigInt();
+ for(let i = -8; i < 8; i++) {
+ const gasPrice = base + base / 100000n * BigInt(i);
+ const gasPriceStr = '0x' + gasPrice.toString(16);
+ await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(gasPrice)));
+
+ const coefficient = new Fract((await api.query.configuration.minGasPriceOverride() as any).toBigInt());
+ const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+ const token = await collection.mintToken(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ const transferPrice = new Fract(await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS})));
+
+ dataPoints.push({x: transferPrice, y: coefficient});
+ }
+
+ const {a, b} = linearRegression(dataPoints);
+
+ const hyp = hypothesisLinear(a, b);
+ // console.log(`\t[ETH NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`);
+
+ // 0.15 UNQ
+ const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(15n, 100n), '*'));
+ await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toBigInt())));
+
+ {
+ const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+ const token = await collection.mintToken(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
+
+ console.log(`\t[ETH NFT transfer] Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+ }
+}
+
+// eslint-disable-next-line @typescript-eslint/no-floating-promises
+(async () => {
+ await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
+ // Subsequent runs reduce error, as price line is not actually straight, this is a curve
+
+ const iterations = 3;
+
+ console.log('[Calibrate WeightToFee]');
+ for(let i = 0; i < iterations; i++) {
+ await calibrateWeightToFee(helper, privateKey);
+ }
+
+ console.log();
+
+ console.log('[Calibrate MinGasPrice]');
+ for(let i = 0; i < iterations; i++) {
+ await calibrateMinGasPrice(helper, privateKey);
+ }
+ });
+})();
js-packages/scripts/calibrateApply.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/calibrateApply.ts
@@ -0,0 +1,40 @@
+import {readFile, writeFile} from 'fs/promises';
+import path from 'path';
+import {makeNames, usingPlaygrounds} from '@unique/tests/util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+const formatNumber = (num: string): string => num.split('').reverse().join('').replace(/([0-9]{3})/g, '$1_').split('').reverse().join('').replace(/^_/, '');
+
+(async () => {
+ let weightToFeeCoefficientOverride: string;
+ let minGasPriceOverride: string;
+ await usingPlaygrounds(async (helpers, _privateKey) => {
+ weightToFeeCoefficientOverride = (await helpers.getApi().query.configuration.weightToFeeCoefficientOverride() as any).toBigInt().toString();
+ minGasPriceOverride = (await helpers.getApi().query.configuration.minGasPriceOverride() as any).toBigInt().toString();
+ });
+ const constantsFile = path.resolve(dirname, '../../primitives/common/src/constants.rs');
+ let constants = (await readFile(constantsFile)).toString();
+
+ let weight2feeFound = false;
+ constants = constants.replace(/(\/\*<weight2fee>\*\/)[0-9_]+(\/\*<\/weight2fee>\*\/)/, (_f, p, s) => {
+ weight2feeFound = true;
+ return p+formatNumber(weightToFeeCoefficientOverride)+s;
+ });
+ if(!weight2feeFound) {
+ throw new Error('failed to find weight2fee marker in source code');
+ }
+
+ let minGasPriceFound = false;
+ constants = constants.replace(/(\/\*<mingasprice>\*\/)[0-9_]+(\/\*<\/mingasprice>\*\/)/, (_f, p, s) => {
+ minGasPriceFound = true;
+ return p+formatNumber(minGasPriceOverride)+s;
+ });
+ if(!minGasPriceFound) {
+ throw new Error('failed to find mingasprice marker in source code');
+ }
+
+ await writeFile(constantsFile, constants);
+})().catch(e => {
+ console.log(e.stack);
+});
js-packages/scripts/fetchMetadata.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/fetchMetadata.ts
@@ -0,0 +1,40 @@
+import {writeFile} from 'fs/promises';
+import {join} from 'path';
+import {exit} from 'process';
+import {fileURLToPath} from 'url';
+
+// TODO: Extract metadata statically with chainql.
+const url = process.env.RELAY_OPAL_HTTP_URL || process.env.RELAY_QUARTZ_HTTP_URL || process.env.RELAY_UNIQUE_HTTP_URL || process.env.RELAY_SAPPHIRE_HTTP_URL || 'http://127.0.0.1:9944';
+
+const srcDir = fileURLToPath(new URL('.', import.meta.url));
+
+for(let i = 0; i < 10; i++) {
+ try {
+ console.log(`Trying to fetch metadata, retry ${i + 1}/${10}`);
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ redirect: 'follow',
+ body: JSON.stringify({
+ jsonrpc: '2.0',
+ id: '1',
+ method: 'state_getMetadata',
+ params: [],
+ }),
+ });
+ const json = await response.json();
+ const output = join(srcDir, 'metadata.json');
+ console.log(`Received response, saving to ${output}`);
+ await writeFile(output, JSON.stringify(json));
+ exit(0);
+ } catch (e) {
+ console.error('Failed to request metadata:');
+ console.error(e);
+ console.error('Waiting 1 minute');
+ await new Promise(res => setTimeout(res, 60 * 1000));
+ }
+}
+console.error('Out of retries');
+exit(1);
js-packages/scripts/generateEnv.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generateEnv.ts
@@ -0,0 +1,87 @@
+import {ApiPromise, WsProvider} from '@polkadot/api';
+import {readFile} from 'fs/promises';
+import {join} from 'path';
+import {makeNames} from '@unique/tests/util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+async function fetchVersion(chain: string): Promise<string> {
+ const api = await ApiPromise.create({provider: new WsProvider(chain)});
+ const last = (await api.query.system.lastRuntimeUpgrade()).toJSON();
+ await api.disconnect();
+ return (last as any).specVersion.toString();
+}
+
+function setVar(env: string, key: string, value: string): string {
+ let found = false;
+ const newEnv = env.replace(new RegExp(`${key}=.+?\n`), () => {
+ found = true;
+ return `${key}=${value}\n`;
+ });
+ if(!found) throw new Error(`env key "${key}" is not found`);
+ return newEnv;
+}
+
+// Fetch and format version string
+async function ff(url: string, regex: RegExp, rep: string | ((substring: string, ...params:any[]) => string)): Promise<string> {
+ const ver = await fetchVersion(url);
+ if(ver.match(regex) === null)
+ throw new Error(`bad regex for ${url}`);
+ return ver.replace(regex, rep as any);
+}
+function fixupUnique(version: string): string {
+ if(version === 'release-v930033')
+ return 'release-v930033-fix-gas-price';
+ if(version === 'release-v930034')
+ return 'release-v930034-fix-gas-price';
+ return version;
+}
+
+(async () => {
+ let env = (await readFile(join(dirname, '../../.env'))).toString();
+ await Promise.all([
+ ff('wss://rpc.polkadot.io/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'POLKADOT_MAINNET_BRANCH', v)),
+ ff('wss://statemint-rpc.polkadot.io/', /^(....)$/, 'release-parachains-v$1').then(v => env = setVar(env, 'STATEMINT_BUILD_BRANCH', v)),
+ ff('wss://acala-rpc-0.aca-api.network/', /^(.)(..)(.)$/, '$1.$2.$3').then(v => env = setVar(env, 'ACALA_BUILD_BRANCH', v)),
+ ff('wss://wss.api.moonbeam.network/', /^(....)$/, 'runtime-$1').then(v => env = setVar(env, 'MOONBEAM_BUILD_BRANCH', v)),
+ ff('wss://ws.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'UNIQUE_MAINNET_BRANCH', fixupUnique(v))),
+
+ ff('wss://kusama-rpc.polkadot.io/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'KUSAMA_MAINNET_BRANCH', v)),
+ ff('wss://statemine-rpc.polkadot.io/', /^(....)$/, 'release-parachains-v$1').then(v => env = setVar(env, 'STATEMINE_BUILD_BRANCH', v)),
+ ff('wss://karura-rpc-0.aca-api.network/', /^(.)(..)(.)$/, 'release-karura-$1.$2.$3').then(v => env = setVar(env, 'KARURA_BUILD_BRANCH', v)),
+ ff('wss://wss.api.moonriver.moonbeam.network/', /^(....)$/, 'runtime-$1').then(v => env = setVar(env, 'MOONRIVER_BUILD_BRANCH', v)),
+ ff('wss://ws-quartz.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'QUARTZ_MAINNET_BRANCH', fixupUnique(v))),
+
+ ff('wss://ws-westend.unique.network/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'UNIQUEWEST_MAINNET_BRANCH', v)),
+ ff('wss://westmint-rpc.polkadot.io/', /^(....)$/, 'parachains-v$1').then(v => env = setVar(env, 'WESTMINT_BUILD_BRANCH', v)),
+ ff('wss://ws-opal.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'OPAL_MAINNET_BRANCH', fixupUnique(v))),
+
+ ff('wss://ws-eastend.unique.network/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'UNIQUEEAST_MAINNET_BRANCH', v)),
+ ff('wss://ws-sapphire.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'SAPPHIRE_MAINNET_BRANCH', fixupUnique(v))),
+
+ ff('wss://rpc.astar.network/', /^(.+)$/, (_, r) => {
+ switch (r) {
+ case '55': return 'v5.3.0';
+ case '57': return 'v5.4.0';
+ case '61': return 'v5.11.0';
+ case '66': return 'v5.18.0';
+ default: throw new Error('unknown astar branch for runtime ' + r);
+ }
+ }).then(v => env = setVar(env, 'ASTAR_BUILD_BRANCH', v)),
+ ff('wss://shiden.api.onfinality.io/public-ws', /^(.+)$/, (_, r) => {
+ switch (r) {
+ case '90': return 'v4.49.0';
+ case '96': return 'v5.4.0';
+ case '100': return 'v5.10.0';
+ case '104': return 'v5.15.0';
+ case '106': return 'v5.18.0';
+ default: throw new Error('unknown shiden branch for runtime ' + r);
+ }
+ }).then(v => env = setVar(env, 'SHIDEN_BUILD_BRANCH', v)),
+ ]);
+ console.log(env);
+})().catch(e => {
+ console.error('Fatal');
+ console.error(e.stack);
+ process.exit(1);
+});
js-packages/scripts/generate_types/functions.shdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/functions.sh
@@ -0,0 +1,4 @@
+
+function do_rpc {
+ curl -s --header "Content-Type: application/json" -XPOST --data "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"$1\",\"params\":[$2]}" "$RPC_URL"
+}
js-packages/scripts/generate_types/generate_types_package.shdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/generate_types_package.sh
@@ -0,0 +1,208 @@
+#!/usr/bin/env bash
+
+# 2001 - cat file | cmd is fancier than cmd < file in most cases
+# 2002 - bash replacement patterns are awful
+# shellcheck disable=SC2001,SC2002
+set -eux
+
+DIR=$(realpath "$(dirname "$0")")
+TEMPLATE=$DIR/types_template
+GIT_REPO=git@github.com:UniqueNetwork/unique-types-js.git
+
+. "$DIR/functions.sh"
+
+usage() {
+ echo "Usage: [RPC_URL=http://localhost:9944] $0 <--rc|--release> [--force] [--push] [--rpc-url=http://localhost:9944]" 1>&2
+ exit 1
+}
+
+rc=
+release=
+force=
+push=
+
+for i in "$@"; do
+case $i in
+ --rc)
+ rc=1
+ if test "$release"; then usage; fi
+ ;;
+ --release)
+ release=1
+ if test "$rc"; then usage; fi
+ ;;
+ --force)
+ force=1
+ ;;
+ --push)
+ push=1
+ ;;
+ --rpc-url=*)
+ RPC_URL=${i#*=}
+ ;;
+ *)
+ usage
+ ;;
+esac
+done
+
+if test \( ! \( "$rc" -o "$release" \) \) -o \( "${RPC_URL=}" = "" \); then
+ usage
+elif test "$rc"; then
+ echo "Rc build"
+else
+ echo "Release build"
+fi
+
+cd "$DIR/../../"
+yarn polkadot-types
+
+version=$(do_rpc state_getRuntimeVersion "")
+spec_version=$(echo "$version" | jq -r .result.specVersion)
+spec_name=$(echo "$version" | jq -r .result.specName)
+echo "Spec version: $spec_version, name: $spec_name"
+
+case $spec_name in
+ opal)
+ package_name=@unique-nft/opal-testnet-types
+ repo_branch=opal-testnet
+ repo_tag=$repo_branch
+ ;;
+ sapphire)
+ package_name=@unique-nft/sapphire-mainnet-types
+ repo_branch=sapphire-mainnet
+ repo_tag=$repo_branch
+ ;;
+ quartz)
+ package_name=@unique-nft/quartz-mainnet-types
+ repo_branch=quartz-mainnet
+ repo_tag=$repo_branch
+ ;;
+ unique)
+ package_name=@unique-nft/unique-mainnet-types
+ repo_branch=master
+ repo_tag=unique-mainnet
+ ;;
+ *)
+ echo "unknown spec name: $spec_name"
+ exit 1
+ ;;
+esac
+
+if test "$rc" = 1; then
+ if test "$spec_name" != "opal"; then
+ echo "rc types can only be based on opal spec"
+ exit 1
+ fi
+ package_name=@unique-nft/rc-types
+ repo_branch=rc
+ repo_tag=$repo_branch
+fi
+
+package_version=${spec_version:0:4}.$(echo "${spec_version:4:4}" | sed 's/^0*//').
+last_patch=NEVER
+for tag in $(git ls-remote -t --refs $GIT_REPO | cut -f 2 | sort -r); do
+ tag_prefix=refs/tags/$repo_tag-v$package_version
+ if [[ $tag == $tag_prefix* ]]; then
+ last_patch=${tag#"$tag_prefix"}
+ break;
+ fi
+done
+echo "Package version: ${package_version}X, name: $package_name"
+echo "Last published: $package_version$last_patch"
+
+if test "$last_patch" = "NEVER"; then
+ new_package_version=${package_version}0
+else
+ new_package_version=${package_version}$((last_patch+1))
+fi
+package_version=${package_version}$last_patch
+echo "New package version: $new_package_version"
+
+pjsapi_ver=^$(cat "$DIR/../package.json" | jq -r '.dependencies."@polkadot/api"' | sed -e "s/^\^//")
+tsnode_ver=^$(cat "$DIR/../package.json" | jq -r '.devDependencies."ts-node"' | sed -e "s/^\^//")
+ts_ver=^$(cat "$DIR/../package.json" | jq -r '.devDependencies."typescript"' | sed -e "s/^\^//")
+
+gen=$(mktemp -d)
+pushd "$gen"
+git clone $GIT_REPO -b $repo_branch --depth 1 .
+if test "$last_patch" != "NEVER"; then
+ git reset --hard "$repo_tag-v$package_version"
+fi
+git rm -r "*"
+popd
+
+# Using old package_version here, becaue we first check if
+# there is any difference between generated and already uplaoded types
+cat "$TEMPLATE/package.json" \
+| jq '.private = false' - \
+| jq ".name = \"$package_name\"" - \
+| jq ".version = \"$package_version\"" - \
+| jq ".peerDependencies.\"@polkadot/api\" = \"$pjsapi_ver\"" - \
+| jq ".peerDependencies.\"@polkadot/types\" = \"$pjsapi_ver\"" - \
+| jq ".devDependencies.\"@polkadot/api\" = \"$pjsapi_ver\"" - \
+| jq ".devDependencies.\"@polkadot/types\" = \"$pjsapi_ver\"" - \
+| jq ".devDependencies.\"ts-node\" = \"$tsnode_ver\"" - \
+| jq ".devDependencies.\"typescript\" = \"$ts_ver\"" - \
+> "$gen/package.json"
+for file in .gitignore .npmignore README.md tsconfig.json; do
+ cp "$TEMPLATE/$file" "$gen/"
+done
+package_name_replacement=$(printf '%s\n' "$package_name" | sed -e 's/[\/&]/\\&/g')
+sed -i "s/PKGNAME/$package_name_replacement/" "$gen/README.md"
+
+rsync -ar --exclude .gitignore types/ "$gen"
+for file in "$gen"/augment-* "$gen"/**/types.ts "$gen/registry.ts"; do
+ sed -i '1s;^;//@ts-nocheck\n;' "$file"
+done
+
+pushd "$gen"
+git add .
+popd
+
+pushd "$gen"
+if git diff --quiet HEAD && test ! "$force"; then
+ echo "no changes detected"
+ exit 0
+fi
+popd
+
+mv "$gen/package.json" "$gen/package.old.json"
+cat "$gen/package.old.json" \
+| jq ".version = \"$new_package_version\"" - \
+> "$gen/package.json"
+rm "$gen/package.old.json"
+pushd "$gen"
+git add package.json
+popd
+
+echo "package.json contents:"
+cat "$gen/package.json"
+echo "overall diff:"
+pushd "$gen"
+git status
+git diff HEAD || true
+popd
+
+# This check is only active if running in interactive terminal
+if [ -t 0 ]; then
+ read -p "Is everything ok at $gen [y/n]? " -n 1 -r
+ echo
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+ echo "Aborting!"
+ exit 1
+ fi
+fi
+
+pushd "$gen"
+yarn
+yarn prepublish
+git commit -m "chore: upgrade types to v$new_package_version"
+git tag --force "$repo_tag-v$new_package_version"
+if test "$push" = 1; then
+ git push --tags --force -u origin HEAD
+else
+ echo "--push not given, origin repo left intact"
+ echo "To publish manually, go to $gen, and run \"git push --tags --force -u origin HEAD\""
+fi
+popd
js-packages/scripts/generate_types/types_template/.gitignorediffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/types_template/.gitignore
@@ -0,0 +1,5 @@
+*.js
+*.map
+*.d.ts
+/node_modules
+metadata.json
js-packages/scripts/generate_types/types_template/.npmignorediffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/types_template/.npmignore
@@ -0,0 +1 @@
+/src
js-packages/scripts/generate_types/types_template/README.mddiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/types_template/README.md
@@ -0,0 +1,31 @@
+# PKGNAME
+
+Unique network api types
+
+Do not edit by hand, those types are generated automatically, and definitions are located in chain repo
+
+## Using types
+
+Install library:
+
+```bash
+yarn add --dev PKGNAME
+```
+
+Replace polkadot.js types with our chain types adding corresponding path override to the tsconfig `compilerOptions.paths` section:
+
+```json
+// in tsconfig.json
+{
+ "compilerOptions": {
+ "paths": {
+ "@polkadot/types/lookup": ["node_modules/PKGNAME/types-lookup"]
+ }
+ }
+}
+```
+
+Since polkadot v7 api augmentations not loaded by default, in every file, where you need to access `api.tx`, `api.query`, `api.rpc`, etc; you should explicitly import corresponding augmentation before any other `polkadot.js` related import:
+```
+import 'PKGNAME/augment-api';
+```
js-packages/scripts/generate_types/types_template/package.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/types_template/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "TODO",
+ "private": true,
+ "version": "TODO",
+ "main": "index.js",
+ "repository": "git@github.com:UniqueNetwork/unique-types-js.git",
+ "homepage": "https://unique.network/",
+ "license": "MIT",
+ "scripts": {
+ "prepublish": "tsc -d"
+ },
+ "peerDependencies": {
+ "@polkadot/api": "TODO",
+ "@polkadot/types": "TODO"
+ },
+ "devDependencies": {
+ "@polkadot/api": "TODO",
+ "@polkadot/types": "TODO",
+ "ts-node": "TODO",
+ "typescript": "TODO"
+ }
+}
js-packages/scripts/generate_types/types_template/tsconfig.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/types_template/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "exclude": [
+ "node_modules",
+ "node_modules/**/*",
+ "../node_modules/**/*",
+ "**/node_modules/**/*"
+ ],
+ "compilerOptions": {
+ "target": "ES2020",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "outDir": ".",
+ "rootDir": ".",
+ "strict": true,
+ "paths": {
+ },
+ "skipLibCheck": true,
+ },
+ "include": [
+ "**/*",
+ ],
+ "lib": [
+ "es2017"
+ ],
+}
js-packages/scripts/generate_types/wait_for_first_block.shdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/generate_types/wait_for_first_block.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+DIR=$(dirname "$0")
+
+. "$DIR/functions.sh"
+
+last_block_id=0
+block_id=0
+function get_block {
+ block_id_hex=$(do_rpc chain_getHeader | jq -r .result.number)
+ block_id=$((block_id_hex))
+ echo Id = $block_id
+}
+
+function had_new_block {
+ last_block_id=$block_id
+ get_block
+ if (( last_block_id != 0 && block_id > last_block_id )); then
+ return 0
+ fi
+ return 1
+}
+
+function reset_check {
+ last_block_id=0
+ block_id=0
+}
+
+while ! had_new_block; do
+ echo "Waiting for next block..."
+ sleep 12
+done
+reset_check
+
+echo "Chain is running, but lets wait for another block after a minute, to avoid startup flakiness."
+sleep 60
+
+while ! had_new_block; do
+ echo "Waiting for another block..."
+ sleep 12
+done
+
+echo "Chain is running!"
js-packages/scripts/proposefasttrack.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/proposefasttrack.ts
@@ -0,0 +1,42 @@
+import {ApiPromise, WsProvider} from '@polkadot/api';
+import {blake2AsHex} from '@polkadot/util-crypto';
+
+async function main() {
+ const networkUrl = process.argv[2];
+
+ const wsProvider = new WsProvider(networkUrl);
+ const api = await ApiPromise.create({provider: wsProvider});
+
+ const externalDemocracyProposal = (await api.query.democracy.nextExternal() as any).unwrap()[0];
+
+ let proposalHash;
+ if(externalDemocracyProposal.isInline) {
+ proposalHash = blake2AsHex(externalDemocracyProposal.asInline, 256);
+ } else if(externalDemocracyProposal.isLegacy) {
+ proposalHash = externalDemocracyProposal.asLegacy.toJSON().hash;
+ } else {
+ proposalHash = externalDemocracyProposal.asLookup.toJSON().hash;
+ }
+
+ const voringPeriod = 7200;
+ const delay = 10;
+
+ const democracyFastTrack = api.tx.democracy.fastTrack(proposalHash, voringPeriod, delay);
+
+ const techCommThreshold = ((await api.query.technicalCommittee.members()).toJSON() as any[]).length;
+ const techCommProposal = api.tx.technicalCommittee.propose(
+ techCommThreshold,
+ democracyFastTrack.method.toHex(),
+ democracyFastTrack.encodedLength,
+ );
+
+ const encodedCall = techCommProposal.method.toHex();
+
+ console.log('-----------------');
+ console.log('Fast Track Proposal: ', `https://polkadot.js.org/apps/?rpc=${networkUrl}#/extrinsics/decode/${encodedCall}`);
+ console.log('-----------------');
+
+ await api.disconnect();
+}
+
+await main();
js-packages/scripts/proposeupgrade.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/proposeupgrade.ts
@@ -0,0 +1,53 @@
+import {ApiPromise, WsProvider} from '@polkadot/api';
+import {blake2AsHex} from '@polkadot/util-crypto';
+import {readFileSync} from 'fs';
+
+async function main() {
+ const networkUrl = process.argv[2];
+ const wasmFile = process.argv[3];
+
+ const wsProvider = new WsProvider(networkUrl);
+ const api = await ApiPromise.create({provider: wsProvider});
+
+ const wasmFileBytes = readFileSync(wasmFile);
+ const wasmFileHash = blake2AsHex(wasmFileBytes, 256);
+
+ const authorizeUpgrade = api.tx.parachainSystem.authorizeUpgrade(wasmFileHash, true);
+ const enableMaintenance = api.tx.maintenance.enable();
+
+ const councilMembers = (await api.query.council.members()).toJSON() as any[];
+ const councilProposalThreshold = Math.floor(councilMembers.length / 2) + 1;
+
+ const democracyProposalContent = api.tx.utility.batchAll([
+ authorizeUpgrade.method.toHex(),
+ enableMaintenance.method.toHex(),
+ ]).method.toHex();
+
+ const democracyProposalHash = blake2AsHex(democracyProposalContent, 256);
+ const democracyProposalPreimage = api.tx.preimage.notePreimage(democracyProposalContent).method.toHex();
+
+ const democracyProposal = api.tx.democracy.externalProposeDefault({
+ Legacy: democracyProposalHash,
+ });
+
+ const councilProposal = api.tx.council.propose(
+ councilProposalThreshold,
+ democracyProposal,
+ democracyProposal.method.encodedLength,
+ ).method.toHex();
+
+ const proposeUpgradeBatch = api.tx.utility.batchAll([
+ democracyProposalPreimage,
+ councilProposal,
+ ]);
+
+ const encodedCall = proposeUpgradeBatch.method.toHex();
+
+ console.log('-----------------');
+ console.log('Upgrade Proposal: ', `https://polkadot.js.org/apps/?rpc=${networkUrl}#/extrinsics/decode/${encodedCall}`);
+ console.log('-----------------');
+
+ await api.disconnect();
+}
+
+await main();
js-packages/scripts/src/benchmarks/mintFee/index.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/mintFee/index.ts
+++ /dev/null
@@ -1,399 +0,0 @@
-import {usingEthPlaygrounds} from '@unique/tests/src/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/src/eth/util/playgrounds/unique.dev.js';
-import {readFile} from 'fs/promises';
-import type {ICrossAccountId} from '@unique/playgrounds/src/types.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {UniqueNFTCollection} from '@unique/playgrounds/src/unique.js';
-import {Contract} from 'web3-eth-contract';
-import {createObjectCsvWriter} from 'csv-writer';
-import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from '../utils/common.js';
-import {makeNames} from '@unique/tests/src/util/index.js';
-import type {ContractImports} from '@unique/tests/src/eth/util/playgrounds/types.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-export const CONTRACT_IMPORT: ContractImports[] = [
- {
- fsPath: `${dirname}/../../../../tests/src/eth/api/CollectionHelpers.sol`,
- solPath: 'eth/api/CollectionHelpers.sol',
- },
- {
- fsPath: `${dirname}/../../../../tests/src/eth/api/ContractHelpers.sol`,
- solPath: 'eth/api/ContractHelpers.sol',
- },
- {
- fsPath: `${dirname}/../../../../tests/src/eth/api/UniqueRefungibleToken.sol`,
- solPath: 'eth/api/UniqueRefungibleToken.sol',
- },
- {
- fsPath: `${dirname}/../../../../tests/src/eth/api/UniqueRefungible.sol`,
- solPath: 'eth/api/UniqueRefungible.sol',
- },
- {
- fsPath: `${dirname}/../../../../tests/src/eth/api/UniqueNFT.sol`,
- solPath: 'eth/api/UniqueNFT.sol',
- },
-];
-
-interface IBenchmarkResultForProp {
- propertiesNumber: number;
- substrateFee: number;
- ethFee: number;
- ethBulkFee: number;
- ethMintCrossFee: number;
- evmProxyContractFee: number;
- evmProxyContractBulkFee: number;
-}
-
-const main = async () => {
- const benchmarks = [
- 'substrateFee',
- 'ethFee',
- 'ethBulkFee',
- 'ethMintCrossFee',
- 'evmProxyContractFee',
- 'evmProxyContractBulkFee',
- ];
- const headers = [
- 'propertiesNumber',
- ...benchmarks,
- ];
-
-
- const csvWriter = createObjectCsvWriter({
- path: 'properties.csv',
- header: headers,
- });
-
- await usingEthPlaygrounds(async (helper, privateKey) => {
- const CONTRACT_SOURCE = (
- await readFile(`${dirname}/proxyContract.sol`)
- ).toString();
-
- const donor = await privateKey('//Alice'); // Seed from account with balance on this network
- const ethSigner = await helper.eth.createAccountWithBalance(donor);
-
- const contract = await helper.ethContract.deployByCode(
- ethSigner,
- 'ProxyMint',
- CONTRACT_SOURCE,
- CONTRACT_IMPORT,
- );
-
- const fees = await benchMintFee(helper, privateKey, contract);
- console.log('Minting without properties');
- console.table(fees);
-
- const result: IBenchmarkResultForProp[] = [];
- const csvResult: IBenchmarkResultForProp[] = [];
-
- for(let i = 1; i <= 20; i++) {
- const benchResult = await benchMintWithProperties(helper, privateKey, contract, {
- propertiesNumber: i,
- }) as any;
-
- csvResult.push(benchResult);
-
- const minFee = Math.min(...(benchmarks.map(x => benchResult[x])));
- for(const key of benchmarks) {
- const keyPercent = Math.round((benchResult[key] / minFee) * 100);
- benchResult[key] = `${benchResult[key]} (${keyPercent}%)`;
- }
-
- result.push(benchResult);
- }
-
- await csvWriter.writeRecords(csvResult);
-
- console.log('Minting with properties');
- console.table(result, headers);
- });
-};
-
-main()
- .then(() => process.exit(0))
- .catch((e) => {
- console.log(e);
- process.exit(1);
- });
-
-
-
-async function benchMintFee(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- proxyContract: Contract,
-): Promise<{
- substrateFee: number;
- ethFee: number;
- evmProxyContractFee: number;
-}> {
- const donor = await privateKey('//Alice');
- const substrateReceiver = await privateKey('//Bob');
- const ethSigner = await helper.eth.createAccountWithBalance(donor);
-
- const nominal = helper.balance.getOneTokenNominal();
-
- await helper.eth.transferBalanceFromSubstrate(
- donor,
- proxyContract.options.address,
- 100n,
- );
-
- const collection = (await createCollectionForBenchmarks(
- 'nft',
- helper,
- privateKey,
- ethSigner,
- proxyContract.options.address,
- PERMISSIONS,
- )) as UniqueNFTCollection;
-
- const substrateFee = await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),
- );
-
- const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionContract = await helper.ethNativeContract.collection(
- collectionEthAddress,
- 'nft',
- );
-
- const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);
-
- const encodedCall = collectionContract.methods
- .mint(receiverEthAddress)
- .encodeABI();
-
- const ethFee = await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- async () => {
- await helper.eth.sendEVM(
- donor,
- collectionContract.options.address,
- encodedCall,
- '0',
- );
- },
- );
-
- const evmProxyContractFee = await helper.arrange.calculcateFee(
- {Ethereum: ethSigner},
- async () => {
- await proxyContract.methods
- .mintToSubstrate(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- substrateReceiver.addressRaw,
- )
- .send({from: ethSigner});
- },
- );
-
- return {
- substrateFee: convertToTokens(substrateFee, nominal),
- ethFee: convertToTokens(ethFee, nominal),
- evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),
- };
-}
-
-async function benchMintWithProperties(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- proxyContract: Contract,
- setup: { propertiesNumber: number },
-): Promise<IBenchmarkResultForProp> {
- const donor = await privateKey('//Alice'); // Seed from account with balance on this network
- const ethSigner = await helper.eth.createAccountWithBalance(donor);
-
- const susbstrateReceiver = await privateKey('//Bob');
- const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);
-
- const nominal = helper.balance.getOneTokenNominal();
-
- const substrateFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Substrate: donor.address},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- await collection.mintToken(
- donor,
- {Substrate: susbstrateReceiver.address},
- PROPERTIES.slice(0, setup.propertiesNumber).map((p) => ({key: p.key, value: Buffer.from(p.value).toString()})),
- );
- },
- );
-
- const ethFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Substrate: donor.address},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- undefined,
- true,
- );
-
- const subTokenId = await evmContract.methods.nextTokenId().call();
-
- let encodedCall = evmContract.methods
- .mint(receiverEthAddress)
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
-
- for(const val of PROPERTIES.slice(0, setup.propertiesNumber)) {
- encodedCall = await evmContract.methods
- .setProperty(subTokenId, val.key, Buffer.from(val.value))
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
- }
- },
- );
-
- const ethBulkFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Substrate: donor.address},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- );
-
- const subTokenId = await evmContract.methods.nextTokenId().call();
-
- let encodedCall = evmContract.methods
- .mint(receiverEthAddress)
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
-
- encodedCall = await evmContract.methods
- .setProperties(
- subTokenId,
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
- },
- );
-
- const ethMintCrossFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Ethereum: ethSigner},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- );
-
- await evmContract.methods.mintCross(
- helper.ethCrossAccount.fromAddress(receiverEthAddress),
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .send({from: ethSigner});
- },
- );
-
- const proxyContractFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Ethereum: ethSigner},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- await proxyContract.methods
- .mintToSubstrateWithProperty(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- susbstrateReceiver.addressRaw,
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .send({from: ethSigner});
- },
- );
-
- const proxyContractBulkFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Ethereum: ethSigner},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- await proxyContract.methods
- .mintToSubstrateBulkProperty(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- susbstrateReceiver.addressRaw,
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .send({from: ethSigner});
- },
- );
-
- return {
- propertiesNumber: setup.propertiesNumber,
- substrateFee: convertToTokens(substrateFee, nominal),
- ethFee: convertToTokens(ethFee, nominal),
- ethBulkFee: convertToTokens(ethBulkFee, nominal),
- ethMintCrossFee: convertToTokens(ethMintCrossFee, nominal),
- evmProxyContractFee: convertToTokens(proxyContractFee, nominal),
- evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),
- };
-}
-
-async function calculateFeeNftMintWithProperties(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- payer: ICrossAccountId,
- ethSigner: string,
- proxyContractAddress: string,
- calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,
-): Promise<bigint> {
- const collection = (await createCollectionForBenchmarks(
- 'nft',
- helper,
- privateKey,
- ethSigner,
- proxyContractAddress,
- PERMISSIONS,
- )) as UniqueNFTCollection;
- return helper.arrange.calculcateFee(payer, async () => {
- await calculatedCall(collection);
- });
-}
-
-
-
js-packages/scripts/src/benchmarks/mintFee/proxyContract.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/mintFee/proxyContract.sol
+++ /dev/null
@@ -1,153 +0,0 @@
-// SPDX-License-Identifier: Apache License
-pragma solidity >=0.8.0;
-import {CollectionHelpers} from "eth/api/CollectionHelpers.sol";
-import {ContractHelpers} from "eth/api/ContractHelpers.sol";
-import {UniqueRefungibleToken} from "eth/api/UniqueRefungibleToken.sol";
-import {UniqueRefungible, Collection, CrossAddress as RftCrossAccountId, Property as RftProperty} from "eth/api/UniqueRefungible.sol";
-import {UniqueNFT, CrossAddress as NftCrossAccountId, Property as NftProperty} from "eth/api/UniqueNFT.sol";
-
-struct Property {
- string key;
- bytes value;
-}
-
-interface SoftDeprecatedMethods {
- /// @notice Set token property value.
- /// @dev Throws error if `msg.sender` has no permission to edit the property.
- /// @param tokenId ID of the token.
- /// @param key Property key.
- /// @param value Property value.
- /// @dev EVM selector for this function is: 0x1752d67b,
- /// or in textual repr: setProperty(uint256,string,bytes)
- function setProperty(
- uint256 tokenId,
- string memory key,
- bytes memory value
- ) external;
-}
-
-interface BenchUniqueRefungible is UniqueRefungible, SoftDeprecatedMethods {}
-interface BenchUniqueNFT is UniqueNFT, SoftDeprecatedMethods {}
-
-
-
-contract ProxyMint {
- bytes32 constant REFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("ReFungible"));
- bytes32 constant NONFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("NFT"));
-
- modifier checkRestrictions(address _collection) {
- Collection commonContract = Collection(_collection);
- require(
- commonContract.isOwnerOrAdminCross(RftCrossAccountId(msg.sender, 0)),
- "Only collection admin/owner can call this method"
- );
- _;
- }
-
- /// @dev This emits when a mint to a substrate address has been made.
- event MintToSub(address _toEth, uint256 _toSub, address _collection, uint256 _tokenId);
-
- function mintToSubstrate(address _collection, uint256 _substrateReceiver) external checkRestrictions(_collection) {
- Collection commonContract = Collection(_collection);
- bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
- uint256 tokenId;
-
- if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
- UniqueRefungible rftCollection = UniqueRefungible(_collection);
-
- tokenId = rftCollection.mint(address(this));
-
- rftCollection.transferFromCross(
- RftCrossAccountId(address(this), 0),
- RftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
- UniqueNFT nftCollection = UniqueNFT(_collection);
- tokenId = nftCollection.mint(address(this));
-
- nftCollection.transferFromCross(
- NftCrossAccountId(address(this), 0),
- NftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else {
- revert("Wrong collection type. Works only with NFT or RFT");
- }
-
- emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
- }
-
- function mintToSubstrateWithProperty(
- address _collection,
- uint256 _substrateReceiver,
- Property[] calldata _properties
- ) external checkRestrictions(_collection) {
- uint256 propertiesLength = _properties.length;
- require(propertiesLength > 0, "Properies is empty");
-
- Collection commonContract = Collection(_collection);
- bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
- uint256 tokenId;
-
- if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
- BenchUniqueRefungible rftCollection = BenchUniqueRefungible(_collection);
- tokenId = rftCollection.nextTokenId();
- rftCollection.mint(address(this));
-
- for (uint256 i = 0; i < propertiesLength; ++i) {
- rftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);
- }
- rftCollection.transferFromCross(
- RftCrossAccountId(address(this), 0),
- RftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
- BenchUniqueNFT nftCollection = BenchUniqueNFT(_collection);
- tokenId = nftCollection.mint(address(this));
- for (uint256 i = 0; i < propertiesLength; ++i) {
- nftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);
- }
- nftCollection.transferFromCross(
- NftCrossAccountId(address(this), 0),
- NftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else {
- revert("Wrong collection type. Works only with NFT or RFT");
- }
-
- emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
- }
-
- function mintToSubstrateBulkProperty(
- address _collection,
- uint256 _substrateReceiver,
- NftProperty[] calldata _properties
- ) external checkRestrictions(_collection) {
- uint256 propertiesLength = _properties.length;
- require(propertiesLength > 0, "Properies is empty");
-
- Collection commonContract = Collection(_collection);
- bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
- uint256 tokenId;
-
- if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {} else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
- UniqueNFT nftCollection = UniqueNFT(_collection);
- tokenId = nftCollection.mint(address(this));
-
- nftCollection.setProperties(tokenId, _properties);
-
- nftCollection.transferFromCross(
- NftCrossAccountId(address(this), 0),
- NftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else {
- revert("Wrong collection type. Works only with NFT or RFT");
- }
-
- emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
- }
-}
js-packages/scripts/src/benchmarks/nesting/ABIGEN/RMRKNestableMintable.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/ABIGEN/RMRKNestableMintable.ts
+++ /dev/null
@@ -1,354 +0,0 @@
-/* Autogenerated file. Do not edit manually. */
-/* tslint:disable */
-/* eslint-disable */
-
-import type BN from "bn.js";
-import type { ContractOptions } from "web3-eth-contract";
-import type { EventLog } from "web3-core";
-import type { EventEmitter } from "events";
-import type {
- Callback,
- NonPayableTransactionObject,
- BlockType,
- ContractEventLog,
- BaseContract,
-} from "./types.js";
-
-export interface EventOptions {
- filter?: object;
- fromBlock?: BlockType;
- topics?: string[];
-}
-
-export type AllChildrenRejected = ContractEventLog<{
- tokenId: string;
- 0: string;
-}>;
-export type Approval = ContractEventLog<{
- owner: string;
- approved: string;
- tokenId: string;
- 0: string;
- 1: string;
- 2: string;
-}>;
-export type ApprovalForAll = ContractEventLog<{
- owner: string;
- operator: string;
- approved: boolean;
- 0: string;
- 1: string;
- 2: boolean;
-}>;
-export type ChildAccepted = ContractEventLog<{
- tokenId: string;
- childIndex: string;
- childAddress: string;
- childId: string;
- 0: string;
- 1: string;
- 2: string;
- 3: string;
-}>;
-export type ChildProposed = ContractEventLog<{
- tokenId: string;
- childIndex: string;
- childAddress: string;
- childId: string;
- 0: string;
- 1: string;
- 2: string;
- 3: string;
-}>;
-export type ChildTransferred = ContractEventLog<{
- tokenId: string;
- childIndex: string;
- childAddress: string;
- childId: string;
- fromPending: boolean;
- toZero: boolean;
- 0: string;
- 1: string;
- 2: string;
- 3: string;
- 4: boolean;
- 5: boolean;
-}>;
-export type NestTransfer = ContractEventLog<{
- from: string;
- to: string;
- fromTokenId: string;
- toTokenId: string;
- tokenId: string;
- 0: string;
- 1: string;
- 2: string;
- 3: string;
- 4: string;
-}>;
-export type Transfer = ContractEventLog<{
- from: string;
- to: string;
- tokenId: string;
- 0: string;
- 1: string;
- 2: string;
-}>;
-
-export interface RMRKNestableMintable extends BaseContract {
- constructor(
- jsonInterface: any[],
- address?: string,
- options?: ContractOptions
- ): RMRKNestableMintable;
- clone(): RMRKNestableMintable;
- methods: {
- RMRK_INTERFACE(): NonPayableTransactionObject<string>;
-
- VERSION(): NonPayableTransactionObject<string>;
-
- acceptChild(
- parentId: number | string | BN,
- childIndex: number | string | BN,
- childAddress: string,
- childId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- addChild(
- parentId: number | string | BN,
- childId: number | string | BN,
- data: string | number[]
- ): NonPayableTransactionObject<void>;
-
- approve(
- to: string,
- tokenId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- balanceOf(owner: string): NonPayableTransactionObject<string>;
-
- "burn(uint256)"(
- tokenId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- "burn(uint256,uint256)"(
- tokenId: number | string | BN,
- maxChildrenBurns: number | string | BN
- ): NonPayableTransactionObject<string>;
-
- childOf(
- parentId: number | string | BN,
- index: number | string | BN
- ): NonPayableTransactionObject<[string, string]>;
-
- childrenOf(
- parentId: number | string | BN
- ): NonPayableTransactionObject<[string, string][]>;
-
- directOwnerOf(tokenId: number | string | BN): NonPayableTransactionObject<{
- 0: string;
- 1: string;
- 2: boolean;
- }>;
-
- getApproved(
- tokenId: number | string | BN
- ): NonPayableTransactionObject<string>;
-
- isApprovedForAll(
- owner: string,
- operator: string
- ): NonPayableTransactionObject<boolean>;
-
- mint(
- to: string,
- tokenId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- name(): NonPayableTransactionObject<string>;
-
- nestMint(
- to: string,
- tokenId: number | string | BN,
- destinationId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- nestTransfer(
- to: string,
- tokenId: number | string | BN,
- destinationId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- nestTransferFrom(
- from: string,
- to: string,
- tokenId: number | string | BN,
- destinationId: number | string | BN,
- data: string | number[]
- ): NonPayableTransactionObject<void>;
-
- onERC721Received(
- _operator: string,
- _from: string,
- _tokenId: number | string | BN,
- _data: string | number[]
- ): NonPayableTransactionObject<string>;
-
- ownerOf(tokenId: number | string | BN): NonPayableTransactionObject<string>;
-
- pendingChildOf(
- parentId: number | string | BN,
- index: number | string | BN
- ): NonPayableTransactionObject<[string, string]>;
-
- pendingChildrenOf(
- parentId: number | string | BN
- ): NonPayableTransactionObject<[string, string][]>;
-
- rejectAllChildren(
- tokenId: number | string | BN,
- maxRejections: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- safeMint(to: string): NonPayableTransactionObject<void>;
-
- "safeTransferFrom(address,address,uint256)"(
- from: string,
- to: string,
- tokenId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- "safeTransferFrom(address,address,uint256,bytes)"(
- from: string,
- to: string,
- tokenId: number | string | BN,
- data: string | number[]
- ): NonPayableTransactionObject<void>;
-
- setApprovalForAll(
- operator: string,
- approved: boolean
- ): NonPayableTransactionObject<void>;
-
- supportsInterface(
- interfaceId: string | number[]
- ): NonPayableTransactionObject<boolean>;
-
- symbol(): NonPayableTransactionObject<string>;
-
- transfer(
- to: string,
- tokenId: number | string | BN
- ): NonPayableTransactionObject<void>;
-
- transferChild(
- tokenId: number | string | BN,
- to: string,
- destinationId: number | string | BN,
- childIndex: number | string | BN,
- childAddress: string,
- childId: number | string | BN,
- isPending: boolean,
- data: string | number[]
- ): NonPayableTransactionObject<void>;
-
- transferFrom(
- from: string,
- to: string,
- tokenId: number | string | BN
- ): NonPayableTransactionObject<void>;
- };
- events: {
- AllChildrenRejected(cb?: Callback<AllChildrenRejected>): EventEmitter;
- AllChildrenRejected(
- options?: EventOptions,
- cb?: Callback<AllChildrenRejected>
- ): EventEmitter;
-
- Approval(cb?: Callback<Approval>): EventEmitter;
- Approval(options?: EventOptions, cb?: Callback<Approval>): EventEmitter;
-
- ApprovalForAll(cb?: Callback<ApprovalForAll>): EventEmitter;
- ApprovalForAll(
- options?: EventOptions,
- cb?: Callback<ApprovalForAll>
- ): EventEmitter;
-
- ChildAccepted(cb?: Callback<ChildAccepted>): EventEmitter;
- ChildAccepted(
- options?: EventOptions,
- cb?: Callback<ChildAccepted>
- ): EventEmitter;
-
- ChildProposed(cb?: Callback<ChildProposed>): EventEmitter;
- ChildProposed(
- options?: EventOptions,
- cb?: Callback<ChildProposed>
- ): EventEmitter;
-
- ChildTransferred(cb?: Callback<ChildTransferred>): EventEmitter;
- ChildTransferred(
- options?: EventOptions,
- cb?: Callback<ChildTransferred>
- ): EventEmitter;
-
- NestTransfer(cb?: Callback<NestTransfer>): EventEmitter;
- NestTransfer(
- options?: EventOptions,
- cb?: Callback<NestTransfer>
- ): EventEmitter;
-
- Transfer(cb?: Callback<Transfer>): EventEmitter;
- Transfer(options?: EventOptions, cb?: Callback<Transfer>): EventEmitter;
-
- allEvents(options?: EventOptions, cb?: Callback<EventLog>): EventEmitter;
- };
-
- once(event: "AllChildrenRejected", cb: Callback<AllChildrenRejected>): void;
- once(
- event: "AllChildrenRejected",
- options: EventOptions,
- cb: Callback<AllChildrenRejected>
- ): void;
-
- once(event: "Approval", cb: Callback<Approval>): void;
- once(event: "Approval", options: EventOptions, cb: Callback<Approval>): void;
-
- once(event: "ApprovalForAll", cb: Callback<ApprovalForAll>): void;
- once(
- event: "ApprovalForAll",
- options: EventOptions,
- cb: Callback<ApprovalForAll>
- ): void;
-
- once(event: "ChildAccepted", cb: Callback<ChildAccepted>): void;
- once(
- event: "ChildAccepted",
- options: EventOptions,
- cb: Callback<ChildAccepted>
- ): void;
-
- once(event: "ChildProposed", cb: Callback<ChildProposed>): void;
- once(
- event: "ChildProposed",
- options: EventOptions,
- cb: Callback<ChildProposed>
- ): void;
-
- once(event: "ChildTransferred", cb: Callback<ChildTransferred>): void;
- once(
- event: "ChildTransferred",
- options: EventOptions,
- cb: Callback<ChildTransferred>
- ): void;
-
- once(event: "NestTransfer", cb: Callback<NestTransfer>): void;
- once(
- event: "NestTransfer",
- options: EventOptions,
- cb: Callback<NestTransfer>
- ): void;
-
- once(event: "Transfer", cb: Callback<Transfer>): void;
- once(event: "Transfer", options: EventOptions, cb: Callback<Transfer>): void;
-}
js-packages/scripts/src/benchmarks/nesting/ABIGEN/index.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/ABIGEN/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-/* Autogenerated file. Do not edit manually. */
-/* tslint:disable */
-/* eslint-disable */
-export type { RMRKNestableMintable } from "./RMRKNestableMintable.js";
js-packages/scripts/src/benchmarks/nesting/ABIGEN/types.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/ABIGEN/types.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Autogenerated file. Do not edit manually. */
-/* tslint:disable */
-/* eslint-disable */
-import type BN from "bn.js";
-import type { EventEmitter } from "events";
-import type { EventLog, PromiEvent, TransactionReceipt } from "web3-core";
-import type { Contract } from "web3-eth-contract";
-
-export interface EstimateGasOptions {
- from?: string;
- gas?: number;
- value?: number | string | BN;
-}
-
-export interface EventOptions {
- filter?: object;
- fromBlock?: BlockType;
- topics?: string[];
-}
-
-export type Callback<T> = (error: Error, result: T) => void;
-export interface ContractEventLog<T> extends EventLog {
- returnValues: T;
-}
-export interface ContractEventEmitter<T> extends EventEmitter {
- on(event: "connected", listener: (subscriptionId: string) => void): this;
- on(
- event: "data" | "changed",
- listener: (event: ContractEventLog<T>) => void
- ): this;
- on(event: "error", listener: (error: Error) => void): this;
-}
-
-export interface NonPayableTx {
- nonce?: string | number | BN;
- chainId?: string | number | BN;
- from?: string;
- to?: string;
- data?: string;
- gas?: string | number | BN;
- maxPriorityFeePerGas?: string | number | BN;
- maxFeePerGas?: string | number | BN;
- gasPrice?: string | number | BN;
-}
-
-export interface PayableTx extends NonPayableTx {
- value?: string | number | BN;
-}
-
-export interface NonPayableTransactionObject<T> {
- arguments: any[];
- call(tx?: NonPayableTx, block?: BlockType): Promise<T>;
- send(tx?: NonPayableTx): PromiEvent<TransactionReceipt>;
- estimateGas(tx?: NonPayableTx): Promise<number>;
- encodeABI(): string;
-}
-
-export interface PayableTransactionObject<T> {
- arguments: any[];
- call(tx?: PayableTx, block?: BlockType): Promise<T>;
- send(tx?: PayableTx): PromiEvent<TransactionReceipt>;
- estimateGas(tx?: PayableTx): Promise<number>;
- encodeABI(): string;
-}
-
-export type BlockType =
- | "latest"
- | "pending"
- | "genesis"
- | "earliest"
- | number
- | BN;
-export type BaseContract = Omit<Contract, "clone" | "once">;
js-packages/scripts/src/benchmarks/nesting/RMRKNestableMintable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/RMRKNestableMintable.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.18;
-
-import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol";
-import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
-
-contract RMRKNestableMintable is RMRKNestable, IERC721Receiver {
- uint256 private _counter;
-
- constructor() RMRKNestable("RMRK", "nesting") {
- _counter = 1;
- }
-
- function safeMint(address to) external {
- _safeMint(to, _counter, "");
- _counter++;
- }
-
- function mint(address to, uint256 tokenId) external {
- _mint(to, tokenId, "");
- }
-
- function nestMint(address to, uint256 tokenId, uint256 destinationId) external {
- _nestMint(to, tokenId, destinationId, "");
- }
-
- function nestTransfer(address to, uint256 tokenId, uint256 destinationId) public virtual {
- nestTransferFrom(_msgSender(), to, tokenId, destinationId, "");
- }
-
- function transfer(address to, uint256 tokenId) public virtual {
- transferFrom(_msgSender(), to, tokenId);
- }
-
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes calldata _data
- ) external returns (bytes4) {
- return IERC721Receiver.onERC721Received.selector;
- }
-}
js-packages/scripts/src/benchmarks/nesting/abigen.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/abigen.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import {runTypeChain, glob, DEFAULT_FLAGS} from 'typechain';
-
-
-async function main() {
- const cwd = process.cwd();
-
- // find all files matching the glob
- const allFiles = glob(cwd, ['./ABI/*.abi']);
-
- await runTypeChain({
- cwd,
- filesToProcess: allFiles,
- allFiles,
- outDir: 'ABIGEN',
- target: 'web3-v1',
- flags: {...DEFAULT_FLAGS, alwaysGenerateOverloads: true, tsNocheck: false},
- });
-}
-
-main().catch(console.error);
\ No newline at end of file
js-packages/scripts/src/benchmarks/nesting/index.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/index.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-import {usingEthPlaygrounds} from '@unique/tests/src/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/src/eth/util/playgrounds/unique.dev.js';
-import {readFile} from 'fs/promises';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Contract} from 'web3-eth-contract';
-import {convertToTokens} from '../utils/common.js';
-import {makeNames} from '@unique/tests/src/util/index.js';
-import type {ContractImports} from '@unique/tests/src/eth/util/playgrounds/types.js';
-import type {RMRKNestableMintable} from './ABIGEN/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-export const CONTRACT_IMPORT: ContractImports[] = [
- {
- fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,
- solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,
- solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,
- solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,
- solPath: '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
- solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,
- solPath: '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Address.sol`,
- solPath: '@openzeppelin/contracts/utils/Address.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
- solPath: '@openzeppelin/contracts/utils/Context.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
- solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,
- solPath: '@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol',
- },
- {
- fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,
- solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol',
- },
- {
- fsPath: `${dirname}/RMRKNestableMintable.sol`,
- solPath: 'RMRKNestableMintable.sol',
- },
-];
-
-
-const main = async () => {
-
- await usingEthPlaygrounds(async (helper, privateKey) => {
-
- const donor = await privateKey('//Alice'); // Seed from account with balance on this network
-
- const eth = await measureEth(helper, donor);
- const sub = await measureSub(helper, donor);
- const rmrk = await measureRMRK(helper, donor);
- console.table({susbtrate: sub, eth: eth, rmrk: rmrk});
- });
-};
-
-async function measureRMRK(helper: EthUniqueHelper, donor: IKeyringPair) {
- const CONTRACT_SOURCE = (
- await readFile(`${dirname}/RMRKNestableMintable.sol`)
- ).toString();
- const RELAYER_SOURCE = (await readFile(`${dirname}/relayer.sol`)).toString();
-
- const ethSigner = await helper.eth.createAccountWithBalance(donor);
-
- const contract = await helper.ethContract.deployByCode(
- ethSigner,
- 'RMRKNestableMintable',
- CONTRACT_SOURCE,
- CONTRACT_IMPORT,
- 5000000,
- );
-
- const relayer = await helper.ethContract.deployByCode(
- ethSigner,
- 'Relayer',
- RELAYER_SOURCE,
- CONTRACT_IMPORT,
- 5000000,
- [contract.options.address],
- );
-
- const relayerAddress = relayer.options.address;
-
- const rmrk = contract as any as RMRKNestableMintable;
- const createTokenFor = async (receiver: string) => {
- const tokenReceipt = await rmrk.methods.safeMint(receiver).send({from: ethSigner});
- return tokenReceipt.events!['Transfer'].returnValues.tokenId as number;
- };
-
-
- const nestId = await createTokenFor(ethSigner);
- const outerCollectionNestedId = 10;
- const contractOwnedNestId = await createTokenFor(relayerAddress);
- const nextTokenId = contractOwnedNestId + 1;
-
- const nestTransfer = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
- const addChildData = rmrk.methods.addChild(nestId, outerCollectionNestedId, []).encodeABI();
- await relayer.methods.relay(addChildData).send({from: ethSigner});
- await rmrk.methods.acceptChild(nestId, 0, relayerAddress, outerCollectionNestedId).send({from: ethSigner});
- });
-
-
- const nestMint = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
- const nestMintData = rmrk.methods.nestMint(rmrk.options.address, nextTokenId, contractOwnedNestId).encodeABI();
- await relayer.methods.relay(nestMintData).send({from: ethSigner});
- const acceptNestedToken = rmrk.methods.acceptChild(contractOwnedNestId, 0, rmrk.options.address, nextTokenId).encodeABI();
- await relayer.methods.relay(acceptNestedToken).send({from: ethSigner});
- });
-
-
- const unnestToken = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
- const unnestData = rmrk.methods.transferChild(contractOwnedNestId, ethSigner, 0, 0, rmrk.options.address, nextTokenId, false, []).encodeABI();
- await relayer.methods.relay(unnestData).send({from: ethSigner});
- });
-
- return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
-}
-
-async function measureEth(helper: EthUniqueHelper, donor: IKeyringPair) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, contract} = await createNestingCollection(helper, owner);
-
- // Create a token to be nested to
- const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
-
- // Create a nested token
- const nestMint = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
- await contract.methods.mint(targetNftTokenAddress).send({from: owner});
- });
-
- // Create a token to be nested and nest
- const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const nestedTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
-
- const nestTransfer = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
- await contract.methods.transfer(targetNftTokenAddress, nestedTokenId).send({from: owner});
- });
-
- const unnestToken = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {
- await contract.methods.transferFrom(targetNftTokenAddress, owner, nestedTokenId).send({from: owner});
- });
- return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
-}
-
-async function measureSub(helper: EthUniqueHelper, donor: IKeyringPair) {
-
- const [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
-
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
-
-
- const collectionForNesting = await helper.nft.mintCollection(bob);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true},
- });
-
- const nestMint = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
- await (collectionForNesting.mintToken(bob, targetTokenBob.nestingAccount()));
- });
-
- const nestedToken2 = await collectionForNesting.mintToken(bob);
- const nestTransfer = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
- await nestedToken2.nest(bob, targetTokenBob);
- });
-
- const unnestToken = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {
- await nestedToken2.transferFrom(bob, targetTokenBob.nestingAccount(), {Substrate: bob.address});
- });
-
- return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};
-}
-
-
-const createNestingCollection = async (
- helper: EthUniqueHelper,
- owner: string,
-): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- await contract.methods.setCollectionNesting(true).send({from: owner});
-
- return {collectionId, collectionAddress, contract};
-};
-
-main()
- .then(() => process.exit(0))
- .catch((e) => {
- console.log(e);
- process.exit(1);
- });
-
-
-
-
-
-
js-packages/scripts/src/benchmarks/nesting/relayer.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/nesting/relayer.sol
+++ /dev/null
@@ -1,18 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.18;
-
-import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
-import "./RMRKNestableMintable.sol";
-
-contract Relayer is RMRKNestableMintable {
- address _receiver;
-
- constructor(address recevier) {
- _receiver = recevier;
- }
-
- function relay(bytes calldata payload) external {
- (bool succes, bytes memory _returnData) = address(_receiver).call(payload);
- require(succes);
- }
-}
js-packages/scripts/src/benchmarks/opsFee/index.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/opsFee/index.ts
+++ /dev/null
@@ -1,892 +0,0 @@
-import {usingEthPlaygrounds} from '@unique/tests/src/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/src/eth/util/playgrounds/unique.dev.js';
-import {readFile} from 'fs/promises';
-import {CollectionLimitField, CreateCollectionData, TokenPermissionField} from '@unique/tests/src/eth/util/playgrounds/types.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {UniqueFTCollection, UniqueNFTCollection} from '@unique/playgrounds/src/unique.js';
-import {Contract} from 'web3-eth-contract';
-import {createObjectCsvWriter} from 'csv-writer';
-import {FunctionFeeVM} from '../utils/types.js';
-import type {IFunctionFee} from '../utils/types.js';
-import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES, SUBS_PROPERTIES} from '../utils/common.js';
-import {makeNames} from '@unique/tests/src/util/index.js';
-
-
-const {dirname} = makeNames(import.meta.url);
-
-const main = async () => {
-
- const headers = [
- 'function',
- 'ethFee',
- 'ethGas',
- 'substrate',
- 'zeppelinFee',
- 'zeppelinGas',
- ];
-
- const csvWriter20 = createObjectCsvWriter({
- path: 'erc20.csv',
- header: headers,
- });
-
- const csvWriter721 = createObjectCsvWriter({
- path: 'erc721.csv',
- header: headers,
- });
-
- await usingEthPlaygrounds(async (helper, privateKey) => {
- console.log('\n ERC20 ops fees');
- const erc20 = FunctionFeeVM.fromModel(await erc20CalculateFeeGas(helper, privateKey));
- console.table(erc20);
- await csvWriter20.writeRecords(FunctionFeeVM.toCsv(erc20));
-
- console.log('\n ERC721 ops fees');
- const erc721 = FunctionFeeVM.fromModel(await erc721CalculateFeeGas(helper, privateKey));
- console.table(erc721);
-
- await csvWriter721.writeRecords(FunctionFeeVM.toCsv(erc721));
- });
-};
-
-main()
- .then(() => process.exit(0))
- .catch((e) => {
- console.log(e);
- process.exit(1);
- });
-
-async function erc721CalculateFeeGas(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
-): Promise<IFunctionFee> {
- const res: IFunctionFee = {};
- const donor = await privateKey('//Alice');
- const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
- const ethSigner = await helper.eth.createAccountWithBalance(donor);
- const ethReceiver = await helper.eth.createAccountWithBalance(donor);
- const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);
- const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);
- const collection = (await createCollectionForBenchmarks(
- 'nft',
- helper,
- privateKey,
- ethSigner,
- null,
- PERMISSIONS,
- )) as UniqueNFTCollection;
-
- const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
- let zeppelelinContract: Contract | null = null;
- const ZEPPELIN_OBJECT = '0x' + (await readFile(`${dirname}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.bin`)).toString();
- const ZEPPELIN_ABI = JSON.parse((await readFile(`${dirname}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.abi`)).toString());
-
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- ethSigner,
- true,
- );
-
- res['createCollection'] = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => helperContract.methods.createNFTCollection('test','test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
- );
-
- res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.nft.mintCollection(
- donor,
- {name: 'test', description: 'test', tokenPrefix: 'test'},
- ),
- )));
-
- res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- async () => {
- zeppelelinContract = await helper.ethContract.deployByAbi(
- ethSigner,
- ZEPPELIN_ABI,
- ZEPPELIN_OBJECT,
- );
- },
- );
-
- res['mint'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mint(ethSigner).send(),
- );
-
- res['mint'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.safeMint(ethSigner, '').send({from: ethSigner}),
- );
-
- res['mintCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintCross(crossSigner, []).send(),
- );
-
- res['mint'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(
- donor,
- {Substrate: donor.address},
- ),
- )));
-
- res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintMultipleTokens(donor, [{
- owner: {Substrate: donor.address},
- }]),
- )));
-
- res['mintWithTokenURI'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),
- );
-
- res['mintWithTokenURI'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(
- donor,
- {Ethereum: ethSigner},
- [{key: 'URI', value: 'Test URI'}],
- ),
- )));
-
- res['mintWithTokenURI'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.safeMint(ethSigner, 'Test URI').send({from: ethSigner}),
- );
-
- res['setProperties'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setProperties(1, PROPERTIES.slice(0,1)).send(),
- );
-
- res['deleteProperties'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.deleteProperties(1, [PROPERTIES[0].key]).send(),
- );
-
- res['setProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setTokenProperties(
- donor,
- 1,
- SUBS_PROPERTIES.slice(0, 1),
- ),
- )));
-
- res['deleteProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.deleteTokenProperties(
- donor,
- 1,
- SUBS_PROPERTIES.slice(0, 1)
- .map(p => p.key),
- ),
- )));
-
- res['transfer'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transfer(ethReceiver, 1).send(),
- );
-
- res['safeTransferFrom*'] = {
- zeppelin:
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.safeTransferFrom(ethSigner, ethReceiver, 0).send({from: ethSigner}),
- ),
- };
-
- res['transferCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
- );
-
- res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transferToken(
- donor,
- 3,
- {Substrate: subReceiver.address},
- ),
- )));
- await collection.approveToken(subReceiver, 3, {Substrate: donor.address});
-
- res['transferFrom*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
- );
-
- res['transferFrom*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
- );
-
-
- res['transferFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
- );
-
- res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transferTokenFrom(donor, 3, {Substrate: subReceiver.address}, {Substrate: donor.address}),
- )));
-
- res['burn'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.burn(1).send(),
- );
-
- res['burn'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.burnToken(donor, 3),
- )));
-
- res['approve*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approve(ethReceiver, 2).send(),
- );
-
- res['approve*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.approve(ethReceiver, 0).send({from: ethSigner}),
- );
-
- res['approveCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approveCross(crossReceiver, 2).send(),
- );
-
- res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.approveToken(donor, 4, {Substrate: subReceiver.address}),
- )));
-
- res['setApprovalForAll*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setApprovalForAll(ethReceiver, true).send(),
- );
-
- res['setApprovalForAll*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.setApprovalForAll(ethReceiver, true).send({from: ethSigner}),
- );
-
- res['setApprovalForAll*'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.nft.setAllowanceForAll(donor, collection.collectionId, {Substrate: subReceiver.address}, true),
- )));
-
- res['burnFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),
- );
-
- res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.burnTokenFrom(subReceiver, 4, {Substrate: donor.address}),
- )));
-
- res['setTokenPropertyPermissions'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setTokenPropertyPermissions([
- ['url', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).send(),
- );
-
- res['setTokenPropertyPermissions'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setTokenPropertyPermissions(donor, [{key: 'url', permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- }}]),
- )));
-
- res['setCollectionSponsorCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),
- );
-
- res['confirmCollectionSponsorship'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),
- );
-
- res['removeCollectionSponsor'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.removeCollectionSponsor().send(),
- );
-
- res['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setSponsor(donor, subReceiver.address),
- )));
-
- res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.confirmSponsorship(subReceiver),
- )));
-
- res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeSponsor(donor),
- )));
-
- res['setCollectionProperties'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),
- );
-
- res['deleteCollectionProperties'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),
- );
- res['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => ({key: p.key, value: p.value.toString()}))),
- )));
-
- res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => p.key)),
- )));
-
- res['setCollectionLimit'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
- );
-
- res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
- )));
-
- const {collectionAddress} = await helper.eth.createCollection(ethSigner, new CreateCollectionData('A', 'B', 'C', 'nft')).send();
- const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);
-
-
- res['addCollectionAdminCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),
- );
-
- res['removeCollectionAdminCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),
- );
-
- res['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- res['setCollectionNesting'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionNesting(true).send(),
- );
-
- res['setCollectionNesting[]'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),
- );
-
- res['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.disableNesting(donor),
- )));
-
- res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(
- donor,
- {
- nesting: {
- tokenOwner: true,
- restricted: [collection.collectionId],
- },
- },
- ),
- )));
-
- res['setCollectionAccess'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionAccess(1).send(),
- );
-
- res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {access: 'AllowList'}),
- )));
-
- res['addToCollectionAllowListCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),
- );
-
- res['removeFromCollectionAllowListCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),
- );
-
- res['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['setCollectionMintMode'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionMintMode(true).send(),
- );
-
- res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {mintMode: false}),
- )));
-
- res['changeCollectionOwnerCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
- );
-
- res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.changeOwner(donor, subReceiver.address),
- )));
-
- return res;
-}
-
-async function erc20CalculateFeeGas(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
-
-): Promise<IFunctionFee> {
- const res: IFunctionFee = {};
- const donor = await privateKey('//Alice');
- const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
- const ethSigner = await helper.eth.createAccountWithBalance(donor);
- const ethReceiver = await helper.eth.createAccountWithBalance(donor);
- const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);
- const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);
- const collection = (await createCollectionForBenchmarks(
- 'ft',
- helper,
- privateKey,
- ethSigner,
- null,
- PERMISSIONS,
- )) as UniqueFTCollection;
-
- const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
- let zeppelelinContract: Contract | null = null;
- const ZEPPELIN_OBJECT = '0x' + (await readFile(`${dirname}/../utils/openZeppelin/ERC20/bin/ZeppelinContract.bin`)).toString();
- const ZEPPELIN_ABI = JSON.parse((await readFile(`${dirname}/../utils/openZeppelin/ERC20/bin/ZeppelinContract.abi`)).toString());
-
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'ft',
- ethSigner,
- true,
- );
-
- res['createCollection'] = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => helperContract.methods.createFTCollection('test', 18,'test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
- );
-
- res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.ft.mintCollection(
- donor,
- {name: 'test', description: 'test', tokenPrefix: 'test'},
- 18,
- ),
- )));
-
- res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- async () => {
- zeppelelinContract = await helper.ethContract.deployByAbi(
- ethSigner,
- ZEPPELIN_ABI,
- ZEPPELIN_OBJECT,
- );
- },
- );
-
- res['mint'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mint(ethSigner, 1).send(),
- );
-
- res['mint'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.mint(ethSigner, 1).send(),
- );
-
- res['mintCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintCross(crossSigner, 1).send(),
- );
-
- res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mint(
- donor,
- 10n,
- {Substrate: donor.address},
- ),
- )));
-
- res['mintBulk'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintBulk([{to: ethSigner, amount: 1}]).send(),
- );
-
- res['mintBulk'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.executeExtrinsic(donor, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
- Fungible: new Map([
- [JSON.stringify({Ethereum: ethSigner}), 1],
- ]),
- }], true),
- )));
-
- res['transfer*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transfer(ethReceiver, 1).send(),
- );
-
- res['transfer*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.transfer(ethReceiver, 1).send(),
- );
-
- res['transferCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
- );
-
- res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transfer(
- donor,
- {Substrate: subReceiver.address},
- 1n,
- ),
- )));
- await collection.approveTokens(subReceiver, {Substrate: donor.address}, 1n);
-
- res['transferFrom*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
- );
-
- await zeppelelinContract!.methods.approve(ethSigner, 10).send({from: ethReceiver});
-
- res['transferFrom*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 1).send({from: ethSigner}),
- );
-
- res['transferFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
- );
-
- res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transferFrom(donor, {Substrate: subReceiver.address}, {Substrate: donor.address}, 1n),
- )));
-
-
- res['burnTokens'] = {fee: 0n, gas: 0n};
- res['burnTokens'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.burnTokens(donor, 1n),
- )));
-
-
- res['approve*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approve(ethReceiver, 2).send(),
- );
-
- res['approve*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.approve(ethReceiver, 10).send(),
- );
-
- res['approveCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approveCross(crossReceiver, 2).send(),
- );
-
- res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.approveTokens(donor, {Substrate: subReceiver.address}, 1n),
- )));
-
- res['burnFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.burnFromCross(crossSigner, 1).send({from:ethReceiver}),
- );
-
- res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.burnTokensFrom(subReceiver, {Substrate: donor.address}, 1n),
- )));
-
- res['setCollectionSponsorCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),
- );
-
- res['confirmCollectionSponsorship'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),
- );
-
- res['removeCollectionSponsor'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.removeCollectionSponsor().send(),
- );
-
- res['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setSponsor(donor, subReceiver.address),
- )));
-
- res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.confirmSponsorship(subReceiver),
- )));
-
- res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeSponsor(donor),
- )));
-
- res['setCollectionProperties'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),
- );
-
- res['deleteCollectionProperties'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),
- );
- res['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => ({key: p.key, value: p.value.toString()}))),
- )));
-
- res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => p.key)),
- )));
-
- res['setCollectionLimit'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
- );
-
- res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
- )));
-
- const {collectionAddress} = await helper.eth.createCollection(ethSigner, new CreateCollectionData('A', 'B', 'C', 'nft')).send();
- const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);
-
-
- res['addCollectionAdminCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),
- );
-
- res['removeCollectionAdminCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),
- );
-
- res['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- res['setCollectionNesting'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionNesting(true).send(),
- );
-
- res['setCollectionNesting[]'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),
- );
-
- res['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.disableNesting(donor),
- )));
-
- res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(
- donor,
- {
- nesting: {
- tokenOwner: true,
- restricted: [collection.collectionId],
- },
- },
- ),
- )));
-
- res['setCollectionAccess'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionAccess(1).send(),
- );
-
- res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {access: 'AllowList'}),
- )));
-
- res['addToCollectionAllowListCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),
- );
-
- res['removeFromCollectionAllowListCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),
- );
-
- res['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['setCollectionMintMode'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionMintMode(true).send(),
- );
-
- res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {mintMode: false}),
- )));
-
- res['changeCollectionOwnerCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
- );
-
- res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.changeOwner(donor, subReceiver.address),
- )));
-
- return res;
-}
js-packages/scripts/src/benchmarks/utils/common.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/common.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import {EthUniqueHelper} from '@unique/tests/src/eth/util/playgrounds/unique.dev.js';
-import {UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/src/unique.js';
-import type {ITokenPropertyPermission, TCollectionMode} from '@unique/playgrounds/src/types.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-export const PROPERTIES = Array(40)
- .fill(0)
- .map((_, i) => ({
- key: `key_${i}`,
- value: Uint8Array.from(Buffer.from(`value_${i}`)),
- }));
-
-export const SUBS_PROPERTIES = Array(40)
- .fill(0)
- .map((_, i) => ({
- key: `key_${i}`,
- value: `value_${i}`,
- }));
-
-export const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => ({
- key: p.key,
- permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
-}));
-
-export function convertToTokens(value: bigint, nominal = 1000_000_000_000_000_000n): number {
- return Number((value * 1000n) / nominal) / 1000;
-}
-
-export async function createCollectionForBenchmarks(
- mode : TCollectionMode,
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- ethSigner: string,
- proxyContract: string | null,
- permissions: ITokenPropertyPermission[],
-) {
- const donor = await privateKey('//Alice');
-
- const collection = await helper[mode].mintCollection(donor, {
- name: 'test mintToSubstrate',
- description: 'EVMHelpers',
- tokenPrefix: mode,
- ...(mode != 'ft' ? {
- tokenPropertyPermissions: [
- {
- key: 'url',
- permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
- },
- {
- key: 'URI',
- permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
- },
- ],
- } : {}),
- limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},
- permissions: {mintMode: true},
- });
-
- await collection.addToAllowList(donor, {
- Ethereum: helper.address.substrateToEth(donor.address),
- });
- await collection.addToAllowList(donor, {Substrate: donor.address});
- await collection.addAdmin(donor, {Ethereum: ethSigner});
- await collection.addAdmin(donor, {
- Ethereum: helper.address.substrateToEth(donor.address),
- });
-
- if(proxyContract) {
- await collection.addToAllowList(donor, {Ethereum: proxyContract});
- await collection.addAdmin(donor, {Ethereum: proxyContract});
- }
- if(collection instanceof UniqueNFTCollection || collection instanceof UniqueRFTCollection)
- await collection.setTokenPropertyPermissions(donor, permissions);
-
- return collection;
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/README.mddiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# OpenZeppelin Contracts
-
-The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
-
-They are not meant to be edited.
-
-The originals can be found on [GitHub] and [npm].
-
-[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
-[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
-
-Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/access/Ownable.sol
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../utils/Context.sol";
-
-/**
- * @dev Contract module which provides a basic access control mechanism, where
- * there is an account (an owner) that can be granted exclusive access to
- * specific functions.
- *
- * By default, the owner account will be the one that deploys the contract. This
- * can later be changed with {transferOwnership}.
- *
- * This module is used through inheritance. It will make available the modifier
- * `onlyOwner`, which can be applied to your functions to restrict their use to
- * the owner.
- */
-abstract contract Ownable is Context {
- address private _owner;
-
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
- /**
- * @dev Initializes the contract setting the deployer as the initial owner.
- */
- constructor() {
- _transferOwnership(_msgSender());
- }
-
- /**
- * @dev Throws if called by any account other than the owner.
- */
- modifier onlyOwner() {
- _checkOwner();
- _;
- }
-
- /**
- * @dev Returns the address of the current owner.
- */
- function owner() public view virtual returns (address) {
- return _owner;
- }
-
- /**
- * @dev Throws if the sender is not the owner.
- */
- function _checkOwner() internal view virtual {
- require(owner() == _msgSender(), "Ownable: caller is not the owner");
- }
-
- /**
- * @dev Leaves the contract without owner. It will not be possible to call
- * `onlyOwner` functions anymore. Can only be called by the current owner.
- *
- * NOTE: Renouncing ownership will leave the contract without an owner,
- * thereby removing any functionality that is only available to the owner.
- */
- function renounceOwnership() public virtual onlyOwner {
- _transferOwnership(address(0));
- }
-
- /**
- * @dev Transfers ownership of the contract to a new account (`newOwner`).
- * Can only be called by the current owner.
- */
- function transferOwnership(address newOwner) public virtual onlyOwner {
- require(newOwner != address(0), "Ownable: new owner is the zero address");
- _transferOwnership(newOwner);
- }
-
- /**
- * @dev Transfers ownership of the contract to a new account (`newOwner`).
- * Internal function without access restriction.
- */
- function _transferOwnership(address newOwner) internal virtual {
- address oldOwner = _owner;
- _owner = newOwner;
- emit OwnershipTransferred(oldOwner, newOwner);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/governance/utils/IVotes.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/governance/utils/IVotes.sol
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
-pragma solidity ^0.8.0;
-
-/**
- * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
- *
- * _Available since v4.5._
- */
-interface IVotes {
- /**
- * @dev Emitted when an account changes their delegate.
- */
- event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
-
- /**
- * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
- */
- event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
-
- /**
- * @dev Returns the current amount of votes that `account` has.
- */
- function getVotes(address account) external view returns (uint256);
-
- /**
- * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
- */
- function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
-
- /**
- * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
- *
- * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
- * Votes that have not been delegated are still part of total supply, even though they would not participate in a
- * vote.
- */
- function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
-
- /**
- * @dev Returns the delegate that `account` has chosen.
- */
- function delegates(address account) external view returns (address);
-
- /**
- * @dev Delegates votes from the sender to `delegatee`.
- */
- function delegate(address delegatee) external;
-
- /**
- * @dev Delegates votes from signer to `delegatee`.
- */
- function delegateBySig(
- address delegatee,
- uint256 nonce,
- uint256 expiry,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) external;
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Interface of the ERC3156 FlashBorrower, as defined in
- * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
- *
- * _Available since v4.1._
- */
-interface IERC3156FlashBorrower {
- /**
- * @dev Receive a flash loan.
- * @param initiator The initiator of the loan.
- * @param token The loan currency.
- * @param amount The amount of tokens lent.
- * @param fee The additional amount of tokens to repay.
- * @param data Arbitrary data structure, intended to contain user-defined parameters.
- * @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan"
- */
- function onFlashLoan(
- address initiator,
- address token,
- uint256 amount,
- uint256 fee,
- bytes calldata data
- ) external returns (bytes32);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashLender.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC3156FlashBorrower.sol";
-
-/**
- * @dev Interface of the ERC3156 FlashLender, as defined in
- * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
- *
- * _Available since v4.1._
- */
-interface IERC3156FlashLender {
- /**
- * @dev The amount of currency available to be lended.
- * @param token The loan currency.
- * @return The amount of `token` that can be borrowed.
- */
- function maxFlashLoan(address token) external view returns (uint256);
-
- /**
- * @dev The fee to be charged for a given loan.
- * @param token The loan currency.
- * @param amount The amount of tokens lent.
- * @return The amount of `token` to be charged for the loan, on top of the returned principal.
- */
- function flashFee(address token, uint256 amount) external view returns (uint256);
-
- /**
- * @dev Initiate a flash loan.
- * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
- * @param token The loan currency.
- * @param amount The amount of tokens lent.
- * @param data Arbitrary data structure, intended to contain user-defined parameters.
- */
- function flashLoan(
- IERC3156FlashBorrower receiver,
- address token,
- uint256 amount,
- bytes calldata data
- ) external returns (bool);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/security/Pausable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/security/Pausable.sol
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../utils/Context.sol";
-
-/**
- * @dev Contract module which allows children to implement an emergency stop
- * mechanism that can be triggered by an authorized account.
- *
- * This module is used through inheritance. It will make available the
- * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
- * the functions of your contract. Note that they will not be pausable by
- * simply including this module, only once the modifiers are put in place.
- */
-abstract contract Pausable is Context {
- /**
- * @dev Emitted when the pause is triggered by `account`.
- */
- event Paused(address account);
-
- /**
- * @dev Emitted when the pause is lifted by `account`.
- */
- event Unpaused(address account);
-
- bool private _paused;
-
- /**
- * @dev Initializes the contract in unpaused state.
- */
- constructor() {
- _paused = false;
- }
-
- /**
- * @dev Modifier to make a function callable only when the contract is not paused.
- *
- * Requirements:
- *
- * - The contract must not be paused.
- */
- modifier whenNotPaused() {
- _requireNotPaused();
- _;
- }
-
- /**
- * @dev Modifier to make a function callable only when the contract is paused.
- *
- * Requirements:
- *
- * - The contract must be paused.
- */
- modifier whenPaused() {
- _requirePaused();
- _;
- }
-
- /**
- * @dev Returns true if the contract is paused, and false otherwise.
- */
- function paused() public view virtual returns (bool) {
- return _paused;
- }
-
- /**
- * @dev Throws if the contract is paused.
- */
- function _requireNotPaused() internal view virtual {
- require(!paused(), "Pausable: paused");
- }
-
- /**
- * @dev Throws if the contract is not paused.
- */
- function _requirePaused() internal view virtual {
- require(paused(), "Pausable: not paused");
- }
-
- /**
- * @dev Triggers stopped state.
- *
- * Requirements:
- *
- * - The contract must not be paused.
- */
- function _pause() internal virtual whenNotPaused {
- _paused = true;
- emit Paused(_msgSender());
- }
-
- /**
- * @dev Returns to normal state.
- *
- * Requirements:
- *
- * - The contract must be paused.
- */
- function _unpause() internal virtual whenPaused {
- _paused = false;
- emit Unpaused(_msgSender());
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/ERC20.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/ERC20.sol
+++ /dev/null
@@ -1,389 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC20.sol";
-import "./extensions/IERC20Metadata.sol";
-import "../../utils/Context.sol";
-
-/**
- * @dev Implementation of the {IERC20} interface.
- *
- * This implementation is agnostic to the way tokens are created. This means
- * that a supply mechanism has to be added in a derived contract using {_mint}.
- * For a generic mechanism see {ERC20PresetMinterPauser}.
- *
- * TIP: For a detailed writeup see our guide
- * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
- * to implement supply mechanisms].
- *
- * We have followed general OpenZeppelin Contracts guidelines: functions revert
- * instead returning `false` on failure. This behavior is nonetheless
- * conventional and does not conflict with the expectations of ERC20
- * applications.
- *
- * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
- * This allows applications to reconstruct the allowance for all accounts just
- * by listening to said events. Other implementations of the EIP may not emit
- * these events, as it isn't required by the specification.
- *
- * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
- * functions have been added to mitigate the well-known issues around setting
- * allowances. See {IERC20-approve}.
- */
-contract ERC20 is Context, IERC20, IERC20Metadata {
- mapping(address => uint256) private _balances;
-
- mapping(address => mapping(address => uint256)) private _allowances;
-
- uint256 private _totalSupply;
-
- string private _name;
- string private _symbol;
-
- /**
- * @dev Sets the values for {name} and {symbol}.
- *
- * The default value of {decimals} is 18. To select a different value for
- * {decimals} you should overload it.
- *
- * All two of these values are immutable: they can only be set once during
- * construction.
- */
- constructor(string memory name_, string memory symbol_) {
- _name = name_;
- _symbol = symbol_;
- }
-
- /**
- * @dev Returns the name of the token.
- */
- function name() public view virtual override returns (string memory) {
- return _name;
- }
-
- /**
- * @dev Returns the symbol of the token, usually a shorter version of the
- * name.
- */
- function symbol() public view virtual override returns (string memory) {
- return _symbol;
- }
-
- /**
- * @dev Returns the number of decimals used to get its user representation.
- * For example, if `decimals` equals `2`, a balance of `505` tokens should
- * be displayed to a user as `5.05` (`505 / 10 ** 2`).
- *
- * Tokens usually opt for a value of 18, imitating the relationship between
- * Ether and Wei. This is the value {ERC20} uses, unless this function is
- * overridden;
- *
- * NOTE: This information is only used for _display_ purposes: it in
- * no way affects any of the arithmetic of the contract, including
- * {IERC20-balanceOf} and {IERC20-transfer}.
- */
- function decimals() public view virtual override returns (uint8) {
- return 18;
- }
-
- /**
- * @dev See {IERC20-totalSupply}.
- */
- function totalSupply() public view virtual override returns (uint256) {
- return _totalSupply;
- }
-
- /**
- * @dev See {IERC20-balanceOf}.
- */
- function balanceOf(address account) public view virtual override returns (uint256) {
- return _balances[account];
- }
-
- /**
- * @dev See {IERC20-transfer}.
- *
- * Requirements:
- *
- * - `to` cannot be the zero address.
- * - the caller must have a balance of at least `amount`.
- */
- function transfer(address to, uint256 amount) public virtual override returns (bool) {
- address owner = _msgSender();
- _transfer(owner, to, amount);
- return true;
- }
-
- /**
- * @dev See {IERC20-allowance}.
- */
- function allowance(address owner, address spender) public view virtual override returns (uint256) {
- return _allowances[owner][spender];
- }
-
- /**
- * @dev See {IERC20-approve}.
- *
- * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
- * `transferFrom`. This is semantically equivalent to an infinite approval.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- */
- function approve(address spender, uint256 amount) public virtual override returns (bool) {
- address owner = _msgSender();
- _approve(owner, spender, amount);
- return true;
- }
-
- /**
- * @dev See {IERC20-transferFrom}.
- *
- * Emits an {Approval} event indicating the updated allowance. This is not
- * required by the EIP. See the note at the beginning of {ERC20}.
- *
- * NOTE: Does not update the allowance if the current allowance
- * is the maximum `uint256`.
- *
- * Requirements:
- *
- * - `from` and `to` cannot be the zero address.
- * - `from` must have a balance of at least `amount`.
- * - the caller must have allowance for ``from``'s tokens of at least
- * `amount`.
- */
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) public virtual override returns (bool) {
- address spender = _msgSender();
- _spendAllowance(from, spender, amount);
- _transfer(from, to, amount);
- return true;
- }
-
- /**
- * @dev Atomically increases the allowance granted to `spender` by the caller.
- *
- * This is an alternative to {approve} that can be used as a mitigation for
- * problems described in {IERC20-approve}.
- *
- * Emits an {Approval} event indicating the updated allowance.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- */
- function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
- address owner = _msgSender();
- _approve(owner, spender, allowance(owner, spender) + addedValue);
- return true;
- }
-
- /**
- * @dev Atomically decreases the allowance granted to `spender` by the caller.
- *
- * This is an alternative to {approve} that can be used as a mitigation for
- * problems described in {IERC20-approve}.
- *
- * Emits an {Approval} event indicating the updated allowance.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- * - `spender` must have allowance for the caller of at least
- * `subtractedValue`.
- */
- function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
- address owner = _msgSender();
- uint256 currentAllowance = allowance(owner, spender);
- require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
- unchecked {
- _approve(owner, spender, currentAllowance - subtractedValue);
- }
-
- return true;
- }
-
- /**
- * @dev Moves `amount` of tokens from `from` to `to`.
- *
- * This internal function is equivalent to {transfer}, and can be used to
- * e.g. implement automatic token fees, slashing mechanisms, etc.
- *
- * Emits a {Transfer} event.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `from` must have a balance of at least `amount`.
- */
- function _transfer(
- address from,
- address to,
- uint256 amount
- ) internal virtual {
- require(from != address(0), "ERC20: transfer from the zero address");
- require(to != address(0), "ERC20: transfer to the zero address");
-
- _beforeTokenTransfer(from, to, amount);
-
- uint256 fromBalance = _balances[from];
- require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
- unchecked {
- _balances[from] = fromBalance - amount;
- // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
- // decrementing then incrementing.
- _balances[to] += amount;
- }
-
- emit Transfer(from, to, amount);
-
- _afterTokenTransfer(from, to, amount);
- }
-
- /** @dev Creates `amount` tokens and assigns them to `account`, increasing
- * the total supply.
- *
- * Emits a {Transfer} event with `from` set to the zero address.
- *
- * Requirements:
- *
- * - `account` cannot be the zero address.
- */
- function _mint(address account, uint256 amount) internal virtual {
- require(account != address(0), "ERC20: mint to the zero address");
-
- _beforeTokenTransfer(address(0), account, amount);
-
- _totalSupply += amount;
- unchecked {
- // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
- _balances[account] += amount;
- }
- emit Transfer(address(0), account, amount);
-
- _afterTokenTransfer(address(0), account, amount);
- }
-
- /**
- * @dev Destroys `amount` tokens from `account`, reducing the
- * total supply.
- *
- * Emits a {Transfer} event with `to` set to the zero address.
- *
- * Requirements:
- *
- * - `account` cannot be the zero address.
- * - `account` must have at least `amount` tokens.
- */
- function _burn(address account, uint256 amount) internal virtual {
- require(account != address(0), "ERC20: burn from the zero address");
-
- _beforeTokenTransfer(account, address(0), amount);
-
- uint256 accountBalance = _balances[account];
- require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
- unchecked {
- _balances[account] = accountBalance - amount;
- // Overflow not possible: amount <= accountBalance <= totalSupply.
- _totalSupply -= amount;
- }
-
- emit Transfer(account, address(0), amount);
-
- _afterTokenTransfer(account, address(0), amount);
- }
-
- /**
- * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
- *
- * This internal function is equivalent to `approve`, and can be used to
- * e.g. set automatic allowances for certain subsystems, etc.
- *
- * Emits an {Approval} event.
- *
- * Requirements:
- *
- * - `owner` cannot be the zero address.
- * - `spender` cannot be the zero address.
- */
- function _approve(
- address owner,
- address spender,
- uint256 amount
- ) internal virtual {
- require(owner != address(0), "ERC20: approve from the zero address");
- require(spender != address(0), "ERC20: approve to the zero address");
-
- _allowances[owner][spender] = amount;
- emit Approval(owner, spender, amount);
- }
-
- /**
- * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
- *
- * Does not update the allowance amount in case of infinite allowance.
- * Revert if not enough allowance is available.
- *
- * Might emit an {Approval} event.
- */
- function _spendAllowance(
- address owner,
- address spender,
- uint256 amount
- ) internal virtual {
- uint256 currentAllowance = allowance(owner, spender);
- if (currentAllowance != type(uint256).max) {
- require(currentAllowance >= amount, "ERC20: insufficient allowance");
- unchecked {
- _approve(owner, spender, currentAllowance - amount);
- }
- }
- }
-
- /**
- * @dev Hook that is called before any transfer of tokens. This includes
- * minting and burning.
- *
- * Calling conditions:
- *
- * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
- * will be transferred to `to`.
- * - when `from` is zero, `amount` tokens will be minted for `to`.
- * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
- * - `from` and `to` are never both zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _beforeTokenTransfer(
- address from,
- address to,
- uint256 amount
- ) internal virtual {}
-
- /**
- * @dev Hook that is called after any transfer of tokens. This includes
- * minting and burning.
- *
- * Calling conditions:
- *
- * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
- * has been transferred to `to`.
- * - when `from` is zero, `amount` tokens have been minted for `to`.
- * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
- * - `from` and `to` are never both zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _afterTokenTransfer(
- address from,
- address to,
- uint256 amount
- ) internal virtual {}
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/IERC20.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/IERC20.sol
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Interface of the ERC20 standard as defined in the EIP.
- */
-interface IERC20 {
- /**
- * @dev Emitted when `value` tokens are moved from one account (`from`) to
- * another (`to`).
- *
- * Note that `value` may be zero.
- */
- event Transfer(address indexed from, address indexed to, uint256 value);
-
- /**
- * @dev Emitted when the allowance of a `spender` for an `owner` is set by
- * a call to {approve}. `value` is the new allowance.
- */
- event Approval(address indexed owner, address indexed spender, uint256 value);
-
- /**
- * @dev Returns the amount of tokens in existence.
- */
- function totalSupply() external view returns (uint256);
-
- /**
- * @dev Returns the amount of tokens owned by `account`.
- */
- function balanceOf(address account) external view returns (uint256);
-
- /**
- * @dev Moves `amount` tokens from the caller's account to `to`.
- *
- * Returns a boolean value indicating whether the operation succeeded.
- *
- * Emits a {Transfer} event.
- */
- function transfer(address to, uint256 amount) external returns (bool);
-
- /**
- * @dev Returns the remaining number of tokens that `spender` will be
- * allowed to spend on behalf of `owner` through {transferFrom}. This is
- * zero by default.
- *
- * This value changes when {approve} or {transferFrom} are called.
- */
- function allowance(address owner, address spender) external view returns (uint256);
-
- /**
- * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
- *
- * Returns a boolean value indicating whether the operation succeeded.
- *
- * IMPORTANT: Beware that changing an allowance with this method brings the risk
- * that someone may use both the old and the new allowance by unfortunate
- * transaction ordering. One possible solution to mitigate this race
- * condition is to first reduce the spender's allowance to 0 and set the
- * desired value afterwards:
- * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
- *
- * Emits an {Approval} event.
- */
- function approve(address spender, uint256 amount) external returns (bool);
-
- /**
- * @dev Moves `amount` tokens from `from` to `to` using the
- * allowance mechanism. `amount` is then deducted from the caller's
- * allowance.
- *
- * Returns a boolean value indicating whether the operation succeeded.
- *
- * Emits a {Transfer} event.
- */
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) external returns (bool);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC20.sol";
-import "../../../utils/Context.sol";
-
-/**
- * @dev Extension of {ERC20} that allows token holders to destroy both their own
- * tokens and those that they have an allowance for, in a way that can be
- * recognized off-chain (via event analysis).
- */
-abstract contract ERC20Burnable is Context, ERC20 {
- /**
- * @dev Destroys `amount` tokens from the caller.
- *
- * See {ERC20-_burn}.
- */
- function burn(uint256 amount) public virtual {
- _burn(_msgSender(), amount);
- }
-
- /**
- * @dev Destroys `amount` tokens from `account`, deducting from the caller's
- * allowance.
- *
- * See {ERC20-_burn} and {ERC20-allowance}.
- *
- * Requirements:
- *
- * - the caller must have allowance for ``accounts``'s tokens of at least
- * `amount`.
- */
- function burnFrom(address account, uint256 amount) public virtual {
- _spendAllowance(account, _msgSender(), amount);
- _burn(account, amount);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20FlashMint.sol)
-
-pragma solidity ^0.8.0;
-
-import "../../../interfaces/IERC3156FlashBorrower.sol";
-import "../../../interfaces/IERC3156FlashLender.sol";
-import "../ERC20.sol";
-
-/**
- * @dev Implementation of the ERC3156 Flash loans extension, as defined in
- * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
- *
- * Adds the {flashLoan} method, which provides flash loan support at the token
- * level. By default there is no fee, but this can be changed by overriding {flashFee}.
- *
- * _Available since v4.1._
- */
-abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
- bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
-
- /**
- * @dev Returns the maximum amount of tokens available for loan.
- * @param token The address of the token that is requested.
- * @return The amount of token that can be loaned.
- */
- function maxFlashLoan(address token) public view virtual override returns (uint256) {
- return token == address(this) ? type(uint256).max - ERC20.totalSupply() : 0;
- }
-
- /**
- * @dev Returns the fee applied when doing flash loans. This function calls
- * the {_flashFee} function which returns the fee applied when doing flash
- * loans.
- * @param token The token to be flash loaned.
- * @param amount The amount of tokens to be loaned.
- * @return The fees applied to the corresponding flash loan.
- */
- function flashFee(address token, uint256 amount) public view virtual override returns (uint256) {
- require(token == address(this), "ERC20FlashMint: wrong token");
- return _flashFee(token, amount);
- }
-
- /**
- * @dev Returns the fee applied when doing flash loans. By default this
- * implementation has 0 fees. This function can be overloaded to make
- * the flash loan mechanism deflationary.
- * @param token The token to be flash loaned.
- * @param amount The amount of tokens to be loaned.
- * @return The fees applied to the corresponding flash loan.
- */
- function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) {
- // silence warning about unused variable without the addition of bytecode.
- token;
- amount;
- return 0;
- }
-
- /**
- * @dev Returns the receiver address of the flash fee. By default this
- * implementation returns the address(0) which means the fee amount will be burnt.
- * This function can be overloaded to change the fee receiver.
- * @return The address for which the flash fee will be sent to.
- */
- function _flashFeeReceiver() internal view virtual returns (address) {
- return address(0);
- }
-
- /**
- * @dev Performs a flash loan. New tokens are minted and sent to the
- * `receiver`, who is required to implement the {IERC3156FlashBorrower}
- * interface. By the end of the flash loan, the receiver is expected to own
- * amount + fee tokens and have them approved back to the token contract itself so
- * they can be burned.
- * @param receiver The receiver of the flash loan. Should implement the
- * {IERC3156FlashBorrower-onFlashLoan} interface.
- * @param token The token to be flash loaned. Only `address(this)` is
- * supported.
- * @param amount The amount of tokens to be loaned.
- * @param data An arbitrary datafield that is passed to the receiver.
- * @return `true` if the flash loan was successful.
- */
- // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount
- // minted at the beginning is always recovered and burned at the end, or else the entire function will revert.
- // slither-disable-next-line reentrancy-no-eth
- function flashLoan(
- IERC3156FlashBorrower receiver,
- address token,
- uint256 amount,
- bytes calldata data
- ) public virtual override returns (bool) {
- require(amount <= maxFlashLoan(token), "ERC20FlashMint: amount exceeds maxFlashLoan");
- uint256 fee = flashFee(token, amount);
- _mint(address(receiver), amount);
- require(
- receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE,
- "ERC20FlashMint: invalid return value"
- );
- address flashFeeReceiver = _flashFeeReceiver();
- _spendAllowance(address(receiver), address(this), amount + fee);
- if (fee == 0 || flashFeeReceiver == address(0)) {
- _burn(address(receiver), amount + fee);
- } else {
- _burn(address(receiver), amount);
- _transfer(address(receiver), flashFeeReceiver, fee);
- }
- return true;
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol
+++ /dev/null
@@ -1,275 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol)
-
-pragma solidity ^0.8.0;
-
-import "./draft-ERC20Permit.sol";
-import "../../../utils/math/Math.sol";
-import "../../../governance/utils/IVotes.sol";
-import "../../../utils/math/SafeCast.sol";
-import "../../../utils/cryptography/ECDSA.sol";
-
-/**
- * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
- * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
- *
- * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
- *
- * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
- * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
- * power can be queried through the public accessors {getVotes} and {getPastVotes}.
- *
- * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
- * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
- *
- * _Available since v4.2._
- */
-abstract contract ERC20Votes is IVotes, ERC20Permit {
- struct Checkpoint {
- uint32 fromBlock;
- uint224 votes;
- }
-
- bytes32 private constant _DELEGATION_TYPEHASH =
- keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
-
- mapping(address => address) private _delegates;
- mapping(address => Checkpoint[]) private _checkpoints;
- Checkpoint[] private _totalSupplyCheckpoints;
-
- /**
- * @dev Get the `pos`-th checkpoint for `account`.
- */
- function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
- return _checkpoints[account][pos];
- }
-
- /**
- * @dev Get number of checkpoints for `account`.
- */
- function numCheckpoints(address account) public view virtual returns (uint32) {
- return SafeCast.toUint32(_checkpoints[account].length);
- }
-
- /**
- * @dev Get the address `account` is currently delegating to.
- */
- function delegates(address account) public view virtual override returns (address) {
- return _delegates[account];
- }
-
- /**
- * @dev Gets the current votes balance for `account`
- */
- function getVotes(address account) public view virtual override returns (uint256) {
- uint256 pos = _checkpoints[account].length;
- return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
- }
-
- /**
- * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
- *
- * Requirements:
- *
- * - `blockNumber` must have been already mined
- */
- function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
- require(blockNumber < block.number, "ERC20Votes: block not yet mined");
- return _checkpointsLookup(_checkpoints[account], blockNumber);
- }
-
- /**
- * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
- * It is but NOT the sum of all the delegated votes!
- *
- * Requirements:
- *
- * - `blockNumber` must have been already mined
- */
- function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
- require(blockNumber < block.number, "ERC20Votes: block not yet mined");
- return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
- }
-
- /**
- * @dev Lookup a value in a list of (sorted) checkpoints.
- */
- function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
- // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
- //
- // Initially we check if the block is recent to narrow the search range.
- // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
- // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
- // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
- // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
- // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
- // out of bounds (in which case we're looking too far in the past and the result is 0).
- // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
- // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
- // the same.
- uint256 length = ckpts.length;
-
- uint256 low = 0;
- uint256 high = length;
-
- if (length > 5) {
- uint256 mid = length - Math.sqrt(length);
- if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
- high = mid;
- } else {
- low = mid + 1;
- }
- }
-
- while (low < high) {
- uint256 mid = Math.average(low, high);
- if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
- high = mid;
- } else {
- low = mid + 1;
- }
- }
-
- return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
- }
-
- /**
- * @dev Delegate votes from the sender to `delegatee`.
- */
- function delegate(address delegatee) public virtual override {
- _delegate(_msgSender(), delegatee);
- }
-
- /**
- * @dev Delegates votes from signer to `delegatee`
- */
- function delegateBySig(
- address delegatee,
- uint256 nonce,
- uint256 expiry,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) public virtual override {
- require(block.timestamp <= expiry, "ERC20Votes: signature expired");
- address signer = ECDSA.recover(
- _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
- v,
- r,
- s
- );
- require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
- _delegate(signer, delegatee);
- }
-
- /**
- * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
- */
- function _maxSupply() internal view virtual returns (uint224) {
- return type(uint224).max;
- }
-
- /**
- * @dev Snapshots the totalSupply after it has been increased.
- */
- function _mint(address account, uint256 amount) internal virtual override {
- super._mint(account, amount);
- require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
-
- _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
- }
-
- /**
- * @dev Snapshots the totalSupply after it has been decreased.
- */
- function _burn(address account, uint256 amount) internal virtual override {
- super._burn(account, amount);
-
- _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
- }
-
- /**
- * @dev Move voting power when tokens are transferred.
- *
- * Emits a {IVotes-DelegateVotesChanged} event.
- */
- function _afterTokenTransfer(
- address from,
- address to,
- uint256 amount
- ) internal virtual override {
- super._afterTokenTransfer(from, to, amount);
-
- _moveVotingPower(delegates(from), delegates(to), amount);
- }
-
- /**
- * @dev Change delegation for `delegator` to `delegatee`.
- *
- * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
- */
- function _delegate(address delegator, address delegatee) internal virtual {
- address currentDelegate = delegates(delegator);
- uint256 delegatorBalance = balanceOf(delegator);
- _delegates[delegator] = delegatee;
-
- emit DelegateChanged(delegator, currentDelegate, delegatee);
-
- _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
- }
-
- function _moveVotingPower(
- address src,
- address dst,
- uint256 amount
- ) private {
- if (src != dst && amount > 0) {
- if (src != address(0)) {
- (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
- emit DelegateVotesChanged(src, oldWeight, newWeight);
- }
-
- if (dst != address(0)) {
- (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
- emit DelegateVotesChanged(dst, oldWeight, newWeight);
- }
- }
- }
-
- function _writeCheckpoint(
- Checkpoint[] storage ckpts,
- function(uint256, uint256) view returns (uint256) op,
- uint256 delta
- ) private returns (uint256 oldWeight, uint256 newWeight) {
- uint256 pos = ckpts.length;
-
- Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
-
- oldWeight = oldCkpt.votes;
- newWeight = op(oldWeight, delta);
-
- if (pos > 0 && oldCkpt.fromBlock == block.number) {
- _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
- } else {
- ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
- }
- }
-
- function _add(uint256 a, uint256 b) private pure returns (uint256) {
- return a + b;
- }
-
- function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
- return a - b;
- }
-
- /**
- * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
- */
- function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
- assembly {
- mstore(0, ckpts.slot)
- result.slot := add(keccak256(0, 0x20), pos)
- }
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
-
-pragma solidity ^0.8.0;
-
-import "../IERC20.sol";
-
-/**
- * @dev Interface for the optional metadata functions from the ERC20 standard.
- *
- * _Available since v4.1._
- */
-interface IERC20Metadata is IERC20 {
- /**
- * @dev Returns the name of the token.
- */
- function name() external view returns (string memory);
-
- /**
- * @dev Returns the symbol of the token.
- */
- function symbol() external view returns (string memory);
-
- /**
- * @dev Returns the decimals places of the token.
- */
- function decimals() external view returns (uint8);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol
+++ /dev/null
@@ -1,95 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)
-
-pragma solidity ^0.8.0;
-
-import "./draft-IERC20Permit.sol";
-import "../ERC20.sol";
-import "../../../utils/cryptography/ECDSA.sol";
-import "../../../utils/cryptography/EIP712.sol";
-import "../../../utils/Counters.sol";
-
-/**
- * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
- * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
- *
- * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
- * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
- * need to send a transaction, and thus is not required to hold Ether at all.
- *
- * _Available since v3.4._
- */
-abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
- using Counters for Counters.Counter;
-
- mapping(address => Counters.Counter) private _nonces;
-
- // solhint-disable-next-line var-name-mixedcase
- bytes32 private constant _PERMIT_TYPEHASH =
- keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
- /**
- * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
- * However, to ensure consistency with the upgradeable transpiler, we will continue
- * to reserve a slot.
- * @custom:oz-renamed-from _PERMIT_TYPEHASH
- */
- // solhint-disable-next-line var-name-mixedcase
- bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
-
- /**
- * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
- *
- * It's a good idea to use the same `name` that is defined as the ERC20 token name.
- */
- constructor(string memory name) EIP712(name, "1") {}
-
- /**
- * @dev See {IERC20Permit-permit}.
- */
- function permit(
- address owner,
- address spender,
- uint256 value,
- uint256 deadline,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) public virtual override {
- require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
-
- bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
-
- bytes32 hash = _hashTypedDataV4(structHash);
-
- address signer = ECDSA.recover(hash, v, r, s);
- require(signer == owner, "ERC20Permit: invalid signature");
-
- _approve(owner, spender, value);
- }
-
- /**
- * @dev See {IERC20Permit-nonces}.
- */
- function nonces(address owner) public view virtual override returns (uint256) {
- return _nonces[owner].current();
- }
-
- /**
- * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
- */
- // solhint-disable-next-line func-name-mixedcase
- function DOMAIN_SEPARATOR() external view override returns (bytes32) {
- return _domainSeparatorV4();
- }
-
- /**
- * @dev "Consume a nonce": return the current value and increment.
- *
- * _Available since v4.1._
- */
- function _useNonce(address owner) internal virtual returns (uint256 current) {
- Counters.Counter storage nonce = _nonces[owner];
- current = nonce.current();
- nonce.increment();
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
- * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
- *
- * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
- * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
- * need to send a transaction, and thus is not required to hold Ether at all.
- */
-interface IERC20Permit {
- /**
- * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
- * given ``owner``'s signed approval.
- *
- * IMPORTANT: The same issues {IERC20-approve} has related to transaction
- * ordering also apply here.
- *
- * Emits an {Approval} event.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- * - `deadline` must be a timestamp in the future.
- * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
- * over the EIP712-formatted function arguments.
- * - the signature must use ``owner``'s current nonce (see {nonces}).
- *
- * For more information on the signature format, see the
- * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
- * section].
- */
- function permit(
- address owner,
- address spender,
- uint256 value,
- uint256 deadline,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) external;
-
- /**
- * @dev Returns the current nonce for `owner`. This value must be
- * included whenever a signature is generated for {permit}.
- *
- * Every successful call to {permit} increases ``owner``'s nonce by one. This
- * prevents a signature from being used multiple times.
- */
- function nonces(address owner) external view returns (uint256);
-
- /**
- * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
- */
- // solhint-disable-next-line func-name-mixedcase
- function DOMAIN_SEPARATOR() external view returns (bytes32);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Context.sol
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Provides information about the current execution context, including the
- * sender of the transaction and its data. While these are generally available
- * via msg.sender and msg.data, they should not be accessed in such a direct
- * manner, since when dealing with meta-transactions the account sending and
- * paying for execution may not be the actual sender (as far as an application
- * is concerned).
- *
- * This contract is only required for intermediate, library-like contracts.
- */
-abstract contract Context {
- function _msgSender() internal view virtual returns (address) {
- return msg.sender;
- }
-
- function _msgData() internal view virtual returns (bytes calldata) {
- return msg.data;
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Counters.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @title Counters
- * @author Matt Condon (@shrugs)
- * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
- * of elements in a mapping, issuing ERC721 ids, or counting request ids.
- *
- * Include with `using Counters for Counters.Counter;`
- */
-library Counters {
- struct Counter {
- // This variable should never be directly accessed by users of the library: interactions must be restricted to
- // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
- // this feature: see https://github.com/ethereum/solidity/issues/4637
- uint256 _value; // default: 0
- }
-
- function current(Counter storage counter) internal view returns (uint256) {
- return counter._value;
- }
-
- function increment(Counter storage counter) internal {
- unchecked {
- counter._value += 1;
- }
- }
-
- function decrement(Counter storage counter) internal {
- uint256 value = counter._value;
- require(value > 0, "Counter: decrement overflow");
- unchecked {
- counter._value = value - 1;
- }
- }
-
- function reset(Counter storage counter) internal {
- counter._value = 0;
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Strings.sol
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
-
-pragma solidity ^0.8.0;
-
-import "./math/Math.sol";
-
-/**
- * @dev String operations.
- */
-library Strings {
- bytes16 private constant _SYMBOLS = "0123456789abcdef";
- uint8 private constant _ADDRESS_LENGTH = 20;
-
- /**
- * @dev Converts a `uint256` to its ASCII `string` decimal representation.
- */
- function toString(uint256 value) internal pure returns (string memory) {
- unchecked {
- uint256 length = Math.log10(value) + 1;
- string memory buffer = new string(length);
- uint256 ptr;
- /// @solidity memory-safe-assembly
- assembly {
- ptr := add(buffer, add(32, length))
- }
- while (true) {
- ptr--;
- /// @solidity memory-safe-assembly
- assembly {
- mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
- }
- value /= 10;
- if (value == 0) break;
- }
- return buffer;
- }
- }
-
- /**
- * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
- */
- function toHexString(uint256 value) internal pure returns (string memory) {
- unchecked {
- return toHexString(value, Math.log256(value) + 1);
- }
- }
-
- /**
- * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
- */
- function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
- bytes memory buffer = new bytes(2 * length + 2);
- buffer[0] = "0";
- buffer[1] = "x";
- for (uint256 i = 2 * length + 1; i > 1; --i) {
- buffer[i] = _SYMBOLS[value & 0xf];
- value >>= 4;
- }
- require(value == 0, "Strings: hex length insufficient");
- return string(buffer);
- }
-
- /**
- * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
- */
- function toHexString(address addr) internal pure returns (string memory) {
- return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/ECDSA.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/ECDSA.sol
+++ /dev/null
@@ -1,213 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
-
-pragma solidity ^0.8.0;
-
-import "../Strings.sol";
-
-/**
- * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
- *
- * These functions can be used to verify that a message was signed by the holder
- * of the private keys of a given address.
- */
-library ECDSA {
- enum RecoverError {
- NoError,
- InvalidSignature,
- InvalidSignatureLength,
- InvalidSignatureS,
- InvalidSignatureV // Deprecated in v4.8
- }
-
- function _throwError(RecoverError error) private pure {
- if (error == RecoverError.NoError) {
- return; // no error: do nothing
- } else if (error == RecoverError.InvalidSignature) {
- revert("ECDSA: invalid signature");
- } else if (error == RecoverError.InvalidSignatureLength) {
- revert("ECDSA: invalid signature length");
- } else if (error == RecoverError.InvalidSignatureS) {
- revert("ECDSA: invalid signature 's' value");
- }
- }
-
- /**
- * @dev Returns the address that signed a hashed message (`hash`) with
- * `signature` or error string. This address can then be used for verification purposes.
- *
- * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
- * this function rejects them by requiring the `s` value to be in the lower
- * half order, and the `v` value to be either 27 or 28.
- *
- * IMPORTANT: `hash` _must_ be the result of a hash operation for the
- * verification to be secure: it is possible to craft signatures that
- * recover to arbitrary addresses for non-hashed data. A safe way to ensure
- * this is by receiving a hash of the original message (which may otherwise
- * be too long), and then calling {toEthSignedMessageHash} on it.
- *
- * Documentation for signature generation:
- * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
- * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
- *
- * _Available since v4.3._
- */
- function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
- if (signature.length == 65) {
- bytes32 r;
- bytes32 s;
- uint8 v;
- // ecrecover takes the signature parameters, and the only way to get them
- // currently is to use assembly.
- /// @solidity memory-safe-assembly
- assembly {
- r := mload(add(signature, 0x20))
- s := mload(add(signature, 0x40))
- v := byte(0, mload(add(signature, 0x60)))
- }
- return tryRecover(hash, v, r, s);
- } else {
- return (address(0), RecoverError.InvalidSignatureLength);
- }
- }
-
- /**
- * @dev Returns the address that signed a hashed message (`hash`) with
- * `signature`. This address can then be used for verification purposes.
- *
- * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
- * this function rejects them by requiring the `s` value to be in the lower
- * half order, and the `v` value to be either 27 or 28.
- *
- * IMPORTANT: `hash` _must_ be the result of a hash operation for the
- * verification to be secure: it is possible to craft signatures that
- * recover to arbitrary addresses for non-hashed data. A safe way to ensure
- * this is by receiving a hash of the original message (which may otherwise
- * be too long), and then calling {toEthSignedMessageHash} on it.
- */
- function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
- (address recovered, RecoverError error) = tryRecover(hash, signature);
- _throwError(error);
- return recovered;
- }
-
- /**
- * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
- *
- * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
- *
- * _Available since v4.3._
- */
- function tryRecover(
- bytes32 hash,
- bytes32 r,
- bytes32 vs
- ) internal pure returns (address, RecoverError) {
- bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
- uint8 v = uint8((uint256(vs) >> 255) + 27);
- return tryRecover(hash, v, r, s);
- }
-
- /**
- * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
- *
- * _Available since v4.2._
- */
- function recover(
- bytes32 hash,
- bytes32 r,
- bytes32 vs
- ) internal pure returns (address) {
- (address recovered, RecoverError error) = tryRecover(hash, r, vs);
- _throwError(error);
- return recovered;
- }
-
- /**
- * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
- * `r` and `s` signature fields separately.
- *
- * _Available since v4.3._
- */
- function tryRecover(
- bytes32 hash,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) internal pure returns (address, RecoverError) {
- // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
- // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
- // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
- // signatures from current libraries generate a unique signature with an s-value in the lower half order.
- //
- // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
- // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
- // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
- // these malleable signatures as well.
- if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
- return (address(0), RecoverError.InvalidSignatureS);
- }
-
- // If the signature is valid (and not malleable), return the signer address
- address signer = ecrecover(hash, v, r, s);
- if (signer == address(0)) {
- return (address(0), RecoverError.InvalidSignature);
- }
-
- return (signer, RecoverError.NoError);
- }
-
- /**
- * @dev Overload of {ECDSA-recover} that receives the `v`,
- * `r` and `s` signature fields separately.
- */
- function recover(
- bytes32 hash,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) internal pure returns (address) {
- (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
- _throwError(error);
- return recovered;
- }
-
- /**
- * @dev Returns an Ethereum Signed Message, created from a `hash`. This
- * produces hash corresponding to the one signed with the
- * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
- * JSON-RPC method as part of EIP-191.
- *
- * See {recover}.
- */
- function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
- // 32 is the length in bytes of hash,
- // enforced by the type signature above
- return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
- }
-
- /**
- * @dev Returns an Ethereum Signed Message, created from `s`. This
- * produces hash corresponding to the one signed with the
- * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
- * JSON-RPC method as part of EIP-191.
- *
- * See {recover}.
- */
- function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
- return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
- }
-
- /**
- * @dev Returns an Ethereum Signed Typed Data, created from a
- * `domainSeparator` and a `structHash`. This produces hash corresponding
- * to the one signed with the
- * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
- * JSON-RPC method as part of EIP-712.
- *
- * See {recover}.
- */
- function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
- return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/EIP712.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/EIP712.sol
+++ /dev/null
@@ -1,104 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
-
-pragma solidity ^0.8.0;
-
-import "./ECDSA.sol";
-
-/**
- * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
- *
- * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
- * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
- * they need in their contracts using a combination of `abi.encode` and `keccak256`.
- *
- * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
- * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
- * ({_hashTypedDataV4}).
- *
- * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
- * the chain id to protect against replay attacks on an eventual fork of the chain.
- *
- * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
- * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
- *
- * _Available since v3.4._
- */
-abstract contract EIP712 {
- /* solhint-disable var-name-mixedcase */
- // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
- // invalidate the cached domain separator if the chain id changes.
- bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
- uint256 private immutable _CACHED_CHAIN_ID;
- address private immutable _CACHED_THIS;
-
- bytes32 private immutable _HASHED_NAME;
- bytes32 private immutable _HASHED_VERSION;
- bytes32 private immutable _TYPE_HASH;
-
- /* solhint-enable var-name-mixedcase */
-
- /**
- * @dev Initializes the domain separator and parameter caches.
- *
- * The meaning of `name` and `version` is specified in
- * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
- *
- * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
- * - `version`: the current major version of the signing domain.
- *
- * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
- * contract upgrade].
- */
- constructor(string memory name, string memory version) {
- bytes32 hashedName = keccak256(bytes(name));
- bytes32 hashedVersion = keccak256(bytes(version));
- bytes32 typeHash = keccak256(
- "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
- );
- _HASHED_NAME = hashedName;
- _HASHED_VERSION = hashedVersion;
- _CACHED_CHAIN_ID = block.chainid;
- _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
- _CACHED_THIS = address(this);
- _TYPE_HASH = typeHash;
- }
-
- /**
- * @dev Returns the domain separator for the current chain.
- */
- function _domainSeparatorV4() internal view returns (bytes32) {
- if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
- return _CACHED_DOMAIN_SEPARATOR;
- } else {
- return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
- }
- }
-
- function _buildDomainSeparator(
- bytes32 typeHash,
- bytes32 nameHash,
- bytes32 versionHash
- ) private view returns (bytes32) {
- return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
- }
-
- /**
- * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
- * function returns the hash of the fully encoded EIP712 message for this domain.
- *
- * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
- *
- * ```solidity
- * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
- * keccak256("Mail(address to,string contents)"),
- * mailTo,
- * keccak256(bytes(mailContents))
- * )));
- * address signer = ECDSA.recover(digest, signature);
- * ```
- */
- function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
- return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/Math.sol
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Standard math utilities missing in the Solidity language.
- */
-library Math {
- enum Rounding {
- Down, // Toward negative infinity
- Up, // Toward infinity
- Zero // Toward zero
- }
-
- /**
- * @dev Returns the largest of two numbers.
- */
- function max(uint256 a, uint256 b) internal pure returns (uint256) {
- return a > b ? a : b;
- }
-
- /**
- * @dev Returns the smallest of two numbers.
- */
- function min(uint256 a, uint256 b) internal pure returns (uint256) {
- return a < b ? a : b;
- }
-
- /**
- * @dev Returns the average of two numbers. The result is rounded towards
- * zero.
- */
- function average(uint256 a, uint256 b) internal pure returns (uint256) {
- // (a + b) / 2 can overflow.
- return (a & b) + (a ^ b) / 2;
- }
-
- /**
- * @dev Returns the ceiling of the division of two numbers.
- *
- * This differs from standard division with `/` in that it rounds up instead
- * of rounding down.
- */
- function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
- // (a + b - 1) / b can overflow on addition, so we distribute.
- return a == 0 ? 0 : (a - 1) / b + 1;
- }
-
- /**
- * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
- * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
- * with further edits by Uniswap Labs also under MIT license.
- */
- function mulDiv(
- uint256 x,
- uint256 y,
- uint256 denominator
- ) internal pure returns (uint256 result) {
- unchecked {
- // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
- // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
- // variables such that product = prod1 * 2^256 + prod0.
- uint256 prod0; // Least significant 256 bits of the product
- uint256 prod1; // Most significant 256 bits of the product
- assembly {
- let mm := mulmod(x, y, not(0))
- prod0 := mul(x, y)
- prod1 := sub(sub(mm, prod0), lt(mm, prod0))
- }
-
- // Handle non-overflow cases, 256 by 256 division.
- if (prod1 == 0) {
- return prod0 / denominator;
- }
-
- // Make sure the result is less than 2^256. Also prevents denominator == 0.
- require(denominator > prod1);
-
- ///////////////////////////////////////////////
- // 512 by 256 division.
- ///////////////////////////////////////////////
-
- // Make division exact by subtracting the remainder from [prod1 prod0].
- uint256 remainder;
- assembly {
- // Compute remainder using mulmod.
- remainder := mulmod(x, y, denominator)
-
- // Subtract 256 bit number from 512 bit number.
- prod1 := sub(prod1, gt(remainder, prod0))
- prod0 := sub(prod0, remainder)
- }
-
- // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
- // See https://cs.stackexchange.com/q/138556/92363.
-
- // Does not overflow because the denominator cannot be zero at this stage in the function.
- uint256 twos = denominator & (~denominator + 1);
- assembly {
- // Divide denominator by twos.
- denominator := div(denominator, twos)
-
- // Divide [prod1 prod0] by twos.
- prod0 := div(prod0, twos)
-
- // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
- twos := add(div(sub(0, twos), twos), 1)
- }
-
- // Shift in bits from prod1 into prod0.
- prod0 |= prod1 * twos;
-
- // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
- // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
- // four bits. That is, denominator * inv = 1 mod 2^4.
- uint256 inverse = (3 * denominator) ^ 2;
-
- // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
- // in modular arithmetic, doubling the correct bits in each step.
- inverse *= 2 - denominator * inverse; // inverse mod 2^8
- inverse *= 2 - denominator * inverse; // inverse mod 2^16
- inverse *= 2 - denominator * inverse; // inverse mod 2^32
- inverse *= 2 - denominator * inverse; // inverse mod 2^64
- inverse *= 2 - denominator * inverse; // inverse mod 2^128
- inverse *= 2 - denominator * inverse; // inverse mod 2^256
-
- // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
- // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
- // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
- // is no longer required.
- result = prod0 * inverse;
- return result;
- }
- }
-
- /**
- * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
- */
- function mulDiv(
- uint256 x,
- uint256 y,
- uint256 denominator,
- Rounding rounding
- ) internal pure returns (uint256) {
- uint256 result = mulDiv(x, y, denominator);
- if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
- result += 1;
- }
- return result;
- }
-
- /**
- * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
- *
- * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
- */
- function sqrt(uint256 a) internal pure returns (uint256) {
- if (a == 0) {
- return 0;
- }
-
- // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
- //
- // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
- // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
- //
- // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
- // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
- // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
- //
- // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
- uint256 result = 1 << (log2(a) >> 1);
-
- // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
- // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
- // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
- // into the expected uint128 result.
- unchecked {
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- return min(result, a / result);
- }
- }
-
- /**
- * @notice Calculates sqrt(a), following the selected rounding direction.
- */
- function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = sqrt(a);
- return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
- }
- }
-
- /**
- * @dev Return the log in base 2, rounded down, of a positive value.
- * Returns 0 if given 0.
- */
- function log2(uint256 value) internal pure returns (uint256) {
- uint256 result = 0;
- unchecked {
- if (value >> 128 > 0) {
- value >>= 128;
- result += 128;
- }
- if (value >> 64 > 0) {
- value >>= 64;
- result += 64;
- }
- if (value >> 32 > 0) {
- value >>= 32;
- result += 32;
- }
- if (value >> 16 > 0) {
- value >>= 16;
- result += 16;
- }
- if (value >> 8 > 0) {
- value >>= 8;
- result += 8;
- }
- if (value >> 4 > 0) {
- value >>= 4;
- result += 4;
- }
- if (value >> 2 > 0) {
- value >>= 2;
- result += 2;
- }
- if (value >> 1 > 0) {
- result += 1;
- }
- }
- return result;
- }
-
- /**
- * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
- * Returns 0 if given 0.
- */
- function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = log2(value);
- return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
- }
- }
-
- /**
- * @dev Return the log in base 10, rounded down, of a positive value.
- * Returns 0 if given 0.
- */
- function log10(uint256 value) internal pure returns (uint256) {
- uint256 result = 0;
- unchecked {
- if (value >= 10**64) {
- value /= 10**64;
- result += 64;
- }
- if (value >= 10**32) {
- value /= 10**32;
- result += 32;
- }
- if (value >= 10**16) {
- value /= 10**16;
- result += 16;
- }
- if (value >= 10**8) {
- value /= 10**8;
- result += 8;
- }
- if (value >= 10**4) {
- value /= 10**4;
- result += 4;
- }
- if (value >= 10**2) {
- value /= 10**2;
- result += 2;
- }
- if (value >= 10**1) {
- result += 1;
- }
- }
- return result;
- }
-
- /**
- * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
- * Returns 0 if given 0.
- */
- function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = log10(value);
- return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
- }
- }
-
- /**
- * @dev Return the log in base 256, rounded down, of a positive value.
- * Returns 0 if given 0.
- *
- * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
- */
- function log256(uint256 value) internal pure returns (uint256) {
- uint256 result = 0;
- unchecked {
- if (value >> 128 > 0) {
- value >>= 128;
- result += 16;
- }
- if (value >> 64 > 0) {
- value >>= 64;
- result += 8;
- }
- if (value >> 32 > 0) {
- value >>= 32;
- result += 4;
- }
- if (value >> 16 > 0) {
- value >>= 16;
- result += 2;
- }
- if (value >> 8 > 0) {
- result += 1;
- }
- }
- return result;
- }
-
- /**
- * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
- * Returns 0 if given 0.
- */
- function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = log256(value);
- return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
- }
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/SafeCast.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/SafeCast.sol
+++ /dev/null
@@ -1,1136 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
-// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
- * checks.
- *
- * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
- * easily result in undesired exploitation or bugs, since developers usually
- * assume that overflows raise errors. `SafeCast` restores this intuition by
- * reverting the transaction when such an operation overflows.
- *
- * Using this library instead of the unchecked operations eliminates an entire
- * class of bugs, so it's recommended to use it always.
- *
- * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
- * all math on `uint256` and `int256` and then downcasting.
- */
-library SafeCast {
- /**
- * @dev Returns the downcasted uint248 from uint256, reverting on
- * overflow (when the input is greater than largest uint248).
- *
- * Counterpart to Solidity's `uint248` operator.
- *
- * Requirements:
- *
- * - input must fit into 248 bits
- *
- * _Available since v4.7._
- */
- function toUint248(uint256 value) internal pure returns (uint248) {
- require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
- return uint248(value);
- }
-
- /**
- * @dev Returns the downcasted uint240 from uint256, reverting on
- * overflow (when the input is greater than largest uint240).
- *
- * Counterpart to Solidity's `uint240` operator.
- *
- * Requirements:
- *
- * - input must fit into 240 bits
- *
- * _Available since v4.7._
- */
- function toUint240(uint256 value) internal pure returns (uint240) {
- require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
- return uint240(value);
- }
-
- /**
- * @dev Returns the downcasted uint232 from uint256, reverting on
- * overflow (when the input is greater than largest uint232).
- *
- * Counterpart to Solidity's `uint232` operator.
- *
- * Requirements:
- *
- * - input must fit into 232 bits
- *
- * _Available since v4.7._
- */
- function toUint232(uint256 value) internal pure returns (uint232) {
- require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
- return uint232(value);
- }
-
- /**
- * @dev Returns the downcasted uint224 from uint256, reverting on
- * overflow (when the input is greater than largest uint224).
- *
- * Counterpart to Solidity's `uint224` operator.
- *
- * Requirements:
- *
- * - input must fit into 224 bits
- *
- * _Available since v4.2._
- */
- function toUint224(uint256 value) internal pure returns (uint224) {
- require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
- return uint224(value);
- }
-
- /**
- * @dev Returns the downcasted uint216 from uint256, reverting on
- * overflow (when the input is greater than largest uint216).
- *
- * Counterpart to Solidity's `uint216` operator.
- *
- * Requirements:
- *
- * - input must fit into 216 bits
- *
- * _Available since v4.7._
- */
- function toUint216(uint256 value) internal pure returns (uint216) {
- require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
- return uint216(value);
- }
-
- /**
- * @dev Returns the downcasted uint208 from uint256, reverting on
- * overflow (when the input is greater than largest uint208).
- *
- * Counterpart to Solidity's `uint208` operator.
- *
- * Requirements:
- *
- * - input must fit into 208 bits
- *
- * _Available since v4.7._
- */
- function toUint208(uint256 value) internal pure returns (uint208) {
- require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
- return uint208(value);
- }
-
- /**
- * @dev Returns the downcasted uint200 from uint256, reverting on
- * overflow (when the input is greater than largest uint200).
- *
- * Counterpart to Solidity's `uint200` operator.
- *
- * Requirements:
- *
- * - input must fit into 200 bits
- *
- * _Available since v4.7._
- */
- function toUint200(uint256 value) internal pure returns (uint200) {
- require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
- return uint200(value);
- }
-
- /**
- * @dev Returns the downcasted uint192 from uint256, reverting on
- * overflow (when the input is greater than largest uint192).
- *
- * Counterpart to Solidity's `uint192` operator.
- *
- * Requirements:
- *
- * - input must fit into 192 bits
- *
- * _Available since v4.7._
- */
- function toUint192(uint256 value) internal pure returns (uint192) {
- require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
- return uint192(value);
- }
-
- /**
- * @dev Returns the downcasted uint184 from uint256, reverting on
- * overflow (when the input is greater than largest uint184).
- *
- * Counterpart to Solidity's `uint184` operator.
- *
- * Requirements:
- *
- * - input must fit into 184 bits
- *
- * _Available since v4.7._
- */
- function toUint184(uint256 value) internal pure returns (uint184) {
- require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
- return uint184(value);
- }
-
- /**
- * @dev Returns the downcasted uint176 from uint256, reverting on
- * overflow (when the input is greater than largest uint176).
- *
- * Counterpart to Solidity's `uint176` operator.
- *
- * Requirements:
- *
- * - input must fit into 176 bits
- *
- * _Available since v4.7._
- */
- function toUint176(uint256 value) internal pure returns (uint176) {
- require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
- return uint176(value);
- }
-
- /**
- * @dev Returns the downcasted uint168 from uint256, reverting on
- * overflow (when the input is greater than largest uint168).
- *
- * Counterpart to Solidity's `uint168` operator.
- *
- * Requirements:
- *
- * - input must fit into 168 bits
- *
- * _Available since v4.7._
- */
- function toUint168(uint256 value) internal pure returns (uint168) {
- require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
- return uint168(value);
- }
-
- /**
- * @dev Returns the downcasted uint160 from uint256, reverting on
- * overflow (when the input is greater than largest uint160).
- *
- * Counterpart to Solidity's `uint160` operator.
- *
- * Requirements:
- *
- * - input must fit into 160 bits
- *
- * _Available since v4.7._
- */
- function toUint160(uint256 value) internal pure returns (uint160) {
- require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
- return uint160(value);
- }
-
- /**
- * @dev Returns the downcasted uint152 from uint256, reverting on
- * overflow (when the input is greater than largest uint152).
- *
- * Counterpart to Solidity's `uint152` operator.
- *
- * Requirements:
- *
- * - input must fit into 152 bits
- *
- * _Available since v4.7._
- */
- function toUint152(uint256 value) internal pure returns (uint152) {
- require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
- return uint152(value);
- }
-
- /**
- * @dev Returns the downcasted uint144 from uint256, reverting on
- * overflow (when the input is greater than largest uint144).
- *
- * Counterpart to Solidity's `uint144` operator.
- *
- * Requirements:
- *
- * - input must fit into 144 bits
- *
- * _Available since v4.7._
- */
- function toUint144(uint256 value) internal pure returns (uint144) {
- require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
- return uint144(value);
- }
-
- /**
- * @dev Returns the downcasted uint136 from uint256, reverting on
- * overflow (when the input is greater than largest uint136).
- *
- * Counterpart to Solidity's `uint136` operator.
- *
- * Requirements:
- *
- * - input must fit into 136 bits
- *
- * _Available since v4.7._
- */
- function toUint136(uint256 value) internal pure returns (uint136) {
- require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
- return uint136(value);
- }
-
- /**
- * @dev Returns the downcasted uint128 from uint256, reverting on
- * overflow (when the input is greater than largest uint128).
- *
- * Counterpart to Solidity's `uint128` operator.
- *
- * Requirements:
- *
- * - input must fit into 128 bits
- *
- * _Available since v2.5._
- */
- function toUint128(uint256 value) internal pure returns (uint128) {
- require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
- return uint128(value);
- }
-
- /**
- * @dev Returns the downcasted uint120 from uint256, reverting on
- * overflow (when the input is greater than largest uint120).
- *
- * Counterpart to Solidity's `uint120` operator.
- *
- * Requirements:
- *
- * - input must fit into 120 bits
- *
- * _Available since v4.7._
- */
- function toUint120(uint256 value) internal pure returns (uint120) {
- require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
- return uint120(value);
- }
-
- /**
- * @dev Returns the downcasted uint112 from uint256, reverting on
- * overflow (when the input is greater than largest uint112).
- *
- * Counterpart to Solidity's `uint112` operator.
- *
- * Requirements:
- *
- * - input must fit into 112 bits
- *
- * _Available since v4.7._
- */
- function toUint112(uint256 value) internal pure returns (uint112) {
- require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
- return uint112(value);
- }
-
- /**
- * @dev Returns the downcasted uint104 from uint256, reverting on
- * overflow (when the input is greater than largest uint104).
- *
- * Counterpart to Solidity's `uint104` operator.
- *
- * Requirements:
- *
- * - input must fit into 104 bits
- *
- * _Available since v4.7._
- */
- function toUint104(uint256 value) internal pure returns (uint104) {
- require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
- return uint104(value);
- }
-
- /**
- * @dev Returns the downcasted uint96 from uint256, reverting on
- * overflow (when the input is greater than largest uint96).
- *
- * Counterpart to Solidity's `uint96` operator.
- *
- * Requirements:
- *
- * - input must fit into 96 bits
- *
- * _Available since v4.2._
- */
- function toUint96(uint256 value) internal pure returns (uint96) {
- require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
- return uint96(value);
- }
-
- /**
- * @dev Returns the downcasted uint88 from uint256, reverting on
- * overflow (when the input is greater than largest uint88).
- *
- * Counterpart to Solidity's `uint88` operator.
- *
- * Requirements:
- *
- * - input must fit into 88 bits
- *
- * _Available since v4.7._
- */
- function toUint88(uint256 value) internal pure returns (uint88) {
- require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
- return uint88(value);
- }
-
- /**
- * @dev Returns the downcasted uint80 from uint256, reverting on
- * overflow (when the input is greater than largest uint80).
- *
- * Counterpart to Solidity's `uint80` operator.
- *
- * Requirements:
- *
- * - input must fit into 80 bits
- *
- * _Available since v4.7._
- */
- function toUint80(uint256 value) internal pure returns (uint80) {
- require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
- return uint80(value);
- }
-
- /**
- * @dev Returns the downcasted uint72 from uint256, reverting on
- * overflow (when the input is greater than largest uint72).
- *
- * Counterpart to Solidity's `uint72` operator.
- *
- * Requirements:
- *
- * - input must fit into 72 bits
- *
- * _Available since v4.7._
- */
- function toUint72(uint256 value) internal pure returns (uint72) {
- require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
- return uint72(value);
- }
-
- /**
- * @dev Returns the downcasted uint64 from uint256, reverting on
- * overflow (when the input is greater than largest uint64).
- *
- * Counterpart to Solidity's `uint64` operator.
- *
- * Requirements:
- *
- * - input must fit into 64 bits
- *
- * _Available since v2.5._
- */
- function toUint64(uint256 value) internal pure returns (uint64) {
- require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
- return uint64(value);
- }
-
- /**
- * @dev Returns the downcasted uint56 from uint256, reverting on
- * overflow (when the input is greater than largest uint56).
- *
- * Counterpart to Solidity's `uint56` operator.
- *
- * Requirements:
- *
- * - input must fit into 56 bits
- *
- * _Available since v4.7._
- */
- function toUint56(uint256 value) internal pure returns (uint56) {
- require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
- return uint56(value);
- }
-
- /**
- * @dev Returns the downcasted uint48 from uint256, reverting on
- * overflow (when the input is greater than largest uint48).
- *
- * Counterpart to Solidity's `uint48` operator.
- *
- * Requirements:
- *
- * - input must fit into 48 bits
- *
- * _Available since v4.7._
- */
- function toUint48(uint256 value) internal pure returns (uint48) {
- require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
- return uint48(value);
- }
-
- /**
- * @dev Returns the downcasted uint40 from uint256, reverting on
- * overflow (when the input is greater than largest uint40).
- *
- * Counterpart to Solidity's `uint40` operator.
- *
- * Requirements:
- *
- * - input must fit into 40 bits
- *
- * _Available since v4.7._
- */
- function toUint40(uint256 value) internal pure returns (uint40) {
- require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
- return uint40(value);
- }
-
- /**
- * @dev Returns the downcasted uint32 from uint256, reverting on
- * overflow (when the input is greater than largest uint32).
- *
- * Counterpart to Solidity's `uint32` operator.
- *
- * Requirements:
- *
- * - input must fit into 32 bits
- *
- * _Available since v2.5._
- */
- function toUint32(uint256 value) internal pure returns (uint32) {
- require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
- return uint32(value);
- }
-
- /**
- * @dev Returns the downcasted uint24 from uint256, reverting on
- * overflow (when the input is greater than largest uint24).
- *
- * Counterpart to Solidity's `uint24` operator.
- *
- * Requirements:
- *
- * - input must fit into 24 bits
- *
- * _Available since v4.7._
- */
- function toUint24(uint256 value) internal pure returns (uint24) {
- require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
- return uint24(value);
- }
-
- /**
- * @dev Returns the downcasted uint16 from uint256, reverting on
- * overflow (when the input is greater than largest uint16).
- *
- * Counterpart to Solidity's `uint16` operator.
- *
- * Requirements:
- *
- * - input must fit into 16 bits
- *
- * _Available since v2.5._
- */
- function toUint16(uint256 value) internal pure returns (uint16) {
- require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
- return uint16(value);
- }
-
- /**
- * @dev Returns the downcasted uint8 from uint256, reverting on
- * overflow (when the input is greater than largest uint8).
- *
- * Counterpart to Solidity's `uint8` operator.
- *
- * Requirements:
- *
- * - input must fit into 8 bits
- *
- * _Available since v2.5._
- */
- function toUint8(uint256 value) internal pure returns (uint8) {
- require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
- return uint8(value);
- }
-
- /**
- * @dev Converts a signed int256 into an unsigned uint256.
- *
- * Requirements:
- *
- * - input must be greater than or equal to 0.
- *
- * _Available since v3.0._
- */
- function toUint256(int256 value) internal pure returns (uint256) {
- require(value >= 0, "SafeCast: value must be positive");
- return uint256(value);
- }
-
- /**
- * @dev Returns the downcasted int248 from int256, reverting on
- * overflow (when the input is less than smallest int248 or
- * greater than largest int248).
- *
- * Counterpart to Solidity's `int248` operator.
- *
- * Requirements:
- *
- * - input must fit into 248 bits
- *
- * _Available since v4.7._
- */
- function toInt248(int256 value) internal pure returns (int248 downcasted) {
- downcasted = int248(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
- }
-
- /**
- * @dev Returns the downcasted int240 from int256, reverting on
- * overflow (when the input is less than smallest int240 or
- * greater than largest int240).
- *
- * Counterpart to Solidity's `int240` operator.
- *
- * Requirements:
- *
- * - input must fit into 240 bits
- *
- * _Available since v4.7._
- */
- function toInt240(int256 value) internal pure returns (int240 downcasted) {
- downcasted = int240(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
- }
-
- /**
- * @dev Returns the downcasted int232 from int256, reverting on
- * overflow (when the input is less than smallest int232 or
- * greater than largest int232).
- *
- * Counterpart to Solidity's `int232` operator.
- *
- * Requirements:
- *
- * - input must fit into 232 bits
- *
- * _Available since v4.7._
- */
- function toInt232(int256 value) internal pure returns (int232 downcasted) {
- downcasted = int232(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
- }
-
- /**
- * @dev Returns the downcasted int224 from int256, reverting on
- * overflow (when the input is less than smallest int224 or
- * greater than largest int224).
- *
- * Counterpart to Solidity's `int224` operator.
- *
- * Requirements:
- *
- * - input must fit into 224 bits
- *
- * _Available since v4.7._
- */
- function toInt224(int256 value) internal pure returns (int224 downcasted) {
- downcasted = int224(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
- }
-
- /**
- * @dev Returns the downcasted int216 from int256, reverting on
- * overflow (when the input is less than smallest int216 or
- * greater than largest int216).
- *
- * Counterpart to Solidity's `int216` operator.
- *
- * Requirements:
- *
- * - input must fit into 216 bits
- *
- * _Available since v4.7._
- */
- function toInt216(int256 value) internal pure returns (int216 downcasted) {
- downcasted = int216(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
- }
-
- /**
- * @dev Returns the downcasted int208 from int256, reverting on
- * overflow (when the input is less than smallest int208 or
- * greater than largest int208).
- *
- * Counterpart to Solidity's `int208` operator.
- *
- * Requirements:
- *
- * - input must fit into 208 bits
- *
- * _Available since v4.7._
- */
- function toInt208(int256 value) internal pure returns (int208 downcasted) {
- downcasted = int208(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
- }
-
- /**
- * @dev Returns the downcasted int200 from int256, reverting on
- * overflow (when the input is less than smallest int200 or
- * greater than largest int200).
- *
- * Counterpart to Solidity's `int200` operator.
- *
- * Requirements:
- *
- * - input must fit into 200 bits
- *
- * _Available since v4.7._
- */
- function toInt200(int256 value) internal pure returns (int200 downcasted) {
- downcasted = int200(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
- }
-
- /**
- * @dev Returns the downcasted int192 from int256, reverting on
- * overflow (when the input is less than smallest int192 or
- * greater than largest int192).
- *
- * Counterpart to Solidity's `int192` operator.
- *
- * Requirements:
- *
- * - input must fit into 192 bits
- *
- * _Available since v4.7._
- */
- function toInt192(int256 value) internal pure returns (int192 downcasted) {
- downcasted = int192(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
- }
-
- /**
- * @dev Returns the downcasted int184 from int256, reverting on
- * overflow (when the input is less than smallest int184 or
- * greater than largest int184).
- *
- * Counterpart to Solidity's `int184` operator.
- *
- * Requirements:
- *
- * - input must fit into 184 bits
- *
- * _Available since v4.7._
- */
- function toInt184(int256 value) internal pure returns (int184 downcasted) {
- downcasted = int184(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
- }
-
- /**
- * @dev Returns the downcasted int176 from int256, reverting on
- * overflow (when the input is less than smallest int176 or
- * greater than largest int176).
- *
- * Counterpart to Solidity's `int176` operator.
- *
- * Requirements:
- *
- * - input must fit into 176 bits
- *
- * _Available since v4.7._
- */
- function toInt176(int256 value) internal pure returns (int176 downcasted) {
- downcasted = int176(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
- }
-
- /**
- * @dev Returns the downcasted int168 from int256, reverting on
- * overflow (when the input is less than smallest int168 or
- * greater than largest int168).
- *
- * Counterpart to Solidity's `int168` operator.
- *
- * Requirements:
- *
- * - input must fit into 168 bits
- *
- * _Available since v4.7._
- */
- function toInt168(int256 value) internal pure returns (int168 downcasted) {
- downcasted = int168(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
- }
-
- /**
- * @dev Returns the downcasted int160 from int256, reverting on
- * overflow (when the input is less than smallest int160 or
- * greater than largest int160).
- *
- * Counterpart to Solidity's `int160` operator.
- *
- * Requirements:
- *
- * - input must fit into 160 bits
- *
- * _Available since v4.7._
- */
- function toInt160(int256 value) internal pure returns (int160 downcasted) {
- downcasted = int160(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
- }
-
- /**
- * @dev Returns the downcasted int152 from int256, reverting on
- * overflow (when the input is less than smallest int152 or
- * greater than largest int152).
- *
- * Counterpart to Solidity's `int152` operator.
- *
- * Requirements:
- *
- * - input must fit into 152 bits
- *
- * _Available since v4.7._
- */
- function toInt152(int256 value) internal pure returns (int152 downcasted) {
- downcasted = int152(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
- }
-
- /**
- * @dev Returns the downcasted int144 from int256, reverting on
- * overflow (when the input is less than smallest int144 or
- * greater than largest int144).
- *
- * Counterpart to Solidity's `int144` operator.
- *
- * Requirements:
- *
- * - input must fit into 144 bits
- *
- * _Available since v4.7._
- */
- function toInt144(int256 value) internal pure returns (int144 downcasted) {
- downcasted = int144(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
- }
-
- /**
- * @dev Returns the downcasted int136 from int256, reverting on
- * overflow (when the input is less than smallest int136 or
- * greater than largest int136).
- *
- * Counterpart to Solidity's `int136` operator.
- *
- * Requirements:
- *
- * - input must fit into 136 bits
- *
- * _Available since v4.7._
- */
- function toInt136(int256 value) internal pure returns (int136 downcasted) {
- downcasted = int136(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
- }
-
- /**
- * @dev Returns the downcasted int128 from int256, reverting on
- * overflow (when the input is less than smallest int128 or
- * greater than largest int128).
- *
- * Counterpart to Solidity's `int128` operator.
- *
- * Requirements:
- *
- * - input must fit into 128 bits
- *
- * _Available since v3.1._
- */
- function toInt128(int256 value) internal pure returns (int128 downcasted) {
- downcasted = int128(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
- }
-
- /**
- * @dev Returns the downcasted int120 from int256, reverting on
- * overflow (when the input is less than smallest int120 or
- * greater than largest int120).
- *
- * Counterpart to Solidity's `int120` operator.
- *
- * Requirements:
- *
- * - input must fit into 120 bits
- *
- * _Available since v4.7._
- */
- function toInt120(int256 value) internal pure returns (int120 downcasted) {
- downcasted = int120(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
- }
-
- /**
- * @dev Returns the downcasted int112 from int256, reverting on
- * overflow (when the input is less than smallest int112 or
- * greater than largest int112).
- *
- * Counterpart to Solidity's `int112` operator.
- *
- * Requirements:
- *
- * - input must fit into 112 bits
- *
- * _Available since v4.7._
- */
- function toInt112(int256 value) internal pure returns (int112 downcasted) {
- downcasted = int112(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
- }
-
- /**
- * @dev Returns the downcasted int104 from int256, reverting on
- * overflow (when the input is less than smallest int104 or
- * greater than largest int104).
- *
- * Counterpart to Solidity's `int104` operator.
- *
- * Requirements:
- *
- * - input must fit into 104 bits
- *
- * _Available since v4.7._
- */
- function toInt104(int256 value) internal pure returns (int104 downcasted) {
- downcasted = int104(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
- }
-
- /**
- * @dev Returns the downcasted int96 from int256, reverting on
- * overflow (when the input is less than smallest int96 or
- * greater than largest int96).
- *
- * Counterpart to Solidity's `int96` operator.
- *
- * Requirements:
- *
- * - input must fit into 96 bits
- *
- * _Available since v4.7._
- */
- function toInt96(int256 value) internal pure returns (int96 downcasted) {
- downcasted = int96(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
- }
-
- /**
- * @dev Returns the downcasted int88 from int256, reverting on
- * overflow (when the input is less than smallest int88 or
- * greater than largest int88).
- *
- * Counterpart to Solidity's `int88` operator.
- *
- * Requirements:
- *
- * - input must fit into 88 bits
- *
- * _Available since v4.7._
- */
- function toInt88(int256 value) internal pure returns (int88 downcasted) {
- downcasted = int88(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
- }
-
- /**
- * @dev Returns the downcasted int80 from int256, reverting on
- * overflow (when the input is less than smallest int80 or
- * greater than largest int80).
- *
- * Counterpart to Solidity's `int80` operator.
- *
- * Requirements:
- *
- * - input must fit into 80 bits
- *
- * _Available since v4.7._
- */
- function toInt80(int256 value) internal pure returns (int80 downcasted) {
- downcasted = int80(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
- }
-
- /**
- * @dev Returns the downcasted int72 from int256, reverting on
- * overflow (when the input is less than smallest int72 or
- * greater than largest int72).
- *
- * Counterpart to Solidity's `int72` operator.
- *
- * Requirements:
- *
- * - input must fit into 72 bits
- *
- * _Available since v4.7._
- */
- function toInt72(int256 value) internal pure returns (int72 downcasted) {
- downcasted = int72(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
- }
-
- /**
- * @dev Returns the downcasted int64 from int256, reverting on
- * overflow (when the input is less than smallest int64 or
- * greater than largest int64).
- *
- * Counterpart to Solidity's `int64` operator.
- *
- * Requirements:
- *
- * - input must fit into 64 bits
- *
- * _Available since v3.1._
- */
- function toInt64(int256 value) internal pure returns (int64 downcasted) {
- downcasted = int64(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
- }
-
- /**
- * @dev Returns the downcasted int56 from int256, reverting on
- * overflow (when the input is less than smallest int56 or
- * greater than largest int56).
- *
- * Counterpart to Solidity's `int56` operator.
- *
- * Requirements:
- *
- * - input must fit into 56 bits
- *
- * _Available since v4.7._
- */
- function toInt56(int256 value) internal pure returns (int56 downcasted) {
- downcasted = int56(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
- }
-
- /**
- * @dev Returns the downcasted int48 from int256, reverting on
- * overflow (when the input is less than smallest int48 or
- * greater than largest int48).
- *
- * Counterpart to Solidity's `int48` operator.
- *
- * Requirements:
- *
- * - input must fit into 48 bits
- *
- * _Available since v4.7._
- */
- function toInt48(int256 value) internal pure returns (int48 downcasted) {
- downcasted = int48(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
- }
-
- /**
- * @dev Returns the downcasted int40 from int256, reverting on
- * overflow (when the input is less than smallest int40 or
- * greater than largest int40).
- *
- * Counterpart to Solidity's `int40` operator.
- *
- * Requirements:
- *
- * - input must fit into 40 bits
- *
- * _Available since v4.7._
- */
- function toInt40(int256 value) internal pure returns (int40 downcasted) {
- downcasted = int40(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
- }
-
- /**
- * @dev Returns the downcasted int32 from int256, reverting on
- * overflow (when the input is less than smallest int32 or
- * greater than largest int32).
- *
- * Counterpart to Solidity's `int32` operator.
- *
- * Requirements:
- *
- * - input must fit into 32 bits
- *
- * _Available since v3.1._
- */
- function toInt32(int256 value) internal pure returns (int32 downcasted) {
- downcasted = int32(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
- }
-
- /**
- * @dev Returns the downcasted int24 from int256, reverting on
- * overflow (when the input is less than smallest int24 or
- * greater than largest int24).
- *
- * Counterpart to Solidity's `int24` operator.
- *
- * Requirements:
- *
- * - input must fit into 24 bits
- *
- * _Available since v4.7._
- */
- function toInt24(int256 value) internal pure returns (int24 downcasted) {
- downcasted = int24(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
- }
-
- /**
- * @dev Returns the downcasted int16 from int256, reverting on
- * overflow (when the input is less than smallest int16 or
- * greater than largest int16).
- *
- * Counterpart to Solidity's `int16` operator.
- *
- * Requirements:
- *
- * - input must fit into 16 bits
- *
- * _Available since v3.1._
- */
- function toInt16(int256 value) internal pure returns (int16 downcasted) {
- downcasted = int16(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
- }
-
- /**
- * @dev Returns the downcasted int8 from int256, reverting on
- * overflow (when the input is less than smallest int8 or
- * greater than largest int8).
- *
- * Counterpart to Solidity's `int8` operator.
- *
- * Requirements:
- *
- * - input must fit into 8 bits
- *
- * _Available since v3.1._
- */
- function toInt8(int256 value) internal pure returns (int8 downcasted) {
- downcasted = int8(value);
- require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
- }
-
- /**
- * @dev Converts an unsigned uint256 into a signed int256.
- *
- * Requirements:
- *
- * - input must be less than or equal to maxInt256.
- *
- * _Available since v3.0._
- */
- function toInt256(uint256 value) internal pure returns (int256) {
- // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
- require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
- return int256(value);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/ZeppelinContract.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/ZeppelinContract.sol
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.9;
-
-import "./@openzeppelin/contracts/token/ERC20/ERC20.sol";
-import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
-import "./@openzeppelin/contracts/security/Pausable.sol";
-import "./@openzeppelin/contracts/access/Ownable.sol";
-import "./@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
-import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
-import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";
-
-contract ZeppelinContract is ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint {
- constructor()
- ERC20("ZeppelinContract", "UNQ")
- ERC20Permit("ZeppelinContract")
- {}
-
- function pause() public onlyOwner {
- _pause();
- }
-
- function unpause() public onlyOwner {
- _unpause();
- }
-
- function mint(address to, uint256 amount) public onlyOwner {
- _mint(to, amount);
- }
-
- function _beforeTokenTransfer(address from, address to, uint256 amount)
- internal
- whenNotPaused
- override
- {
- super._beforeTokenTransfer(from, to, amount);
- }
-
- // The following functions are overrides required by Solidity.
-
- function _afterTokenTransfer(address from, address to, uint256 amount)
- internal
- override(ERC20, ERC20Votes)
- {
- super._afterTokenTransfer(from, to, amount);
- }
-
- function _mint(address to, uint256 amount)
- internal
- override(ERC20, ERC20Votes)
- {
- super._mint(to, amount);
- }
-
- function _burn(address account, uint256 amount)
- internal
- override(ERC20, ERC20Votes)
- {
- super._burn(account, amount);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.abidiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.abi
+++ /dev/null
@@ -1 +0,0 @@
-[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"pos","type":"uint32"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint224","name":"votes","type":"uint224"}],"internalType":"struct ERC20Votes.Checkpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.bindiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.bin
+++ /dev/null
@@ -1 +0,0 @@
-6101406040523480156200001257600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525080604051806040016040528060018152602001603160f81b8152506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b8152508160039081620000ad919062000269565b506004620000bc828262000269565b50506005805460ff1916905550620000d4336200016a565b815160209283012081519183019190912060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818801819052818301969096526060810194909452608080850193909352308483018190528151808603909301835260c094850190915281519190950120905291909152610120525062000335565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001ef57607f821691505b6020821081036200021057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200026457600081815260208120601f850160051c810160208610156200023f5750805b601f850160051c820191505b8181101562000260578281556001016200024b565b5050505b505050565b81516001600160401b03811115620002855762000285620001c4565b6200029d81620002968454620001da565b8462000216565b602080601f831160018114620002d55760008415620002bc5750858301515b600019600386901b1c1916600185901b17855562000260565b600085815260208120601f198616915b828110156200030657888601518255948401946001909101908401620002e5565b5085821015620003255787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e05161010051610120516125f06200038560003960006112ad015260006112fc015260006112d7015260006112300152600061125a0152600061128401526125f06000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806370a082311161011a5780639ab24eb0116100ad578063d505accf1161007c578063d505accf1461046a578063d9d98ce41461047d578063dd62ed3e14610490578063f1127ed8146104a3578063f2fde38b146104e057600080fd5b80639ab24eb01461041e578063a457c2d714610431578063a9059cbb14610444578063c3cda5201461045757600080fd5b80638456cb59116100e95780638456cb59146103e55780638da5cb5b146103ed5780638e539e8c1461040357806395d89b411461041657600080fd5b806370a082311461038e578063715018a6146103b757806379cc6790146103bf5780637ecebe00146103d257600080fd5b80633f4ba83a1161019d5780635c19a95c1161016c5780635c19a95c146103225780635c975abb146103355780635cffe9de14610340578063613255ab146103535780636fcfff451461036657600080fd5b80633f4ba83a146102ae57806340c10f19146102b857806342966c68146102cb578063587cde1e146102de57600080fd5b8063313ce567116101d9578063313ce567146102715780633644e5151461028057806339509351146102885780633a46b1a81461029b57600080fd5b806306fdde031461020b578063095ea7b31461022957806318160ddd1461024c57806323b872dd1461025e575b600080fd5b6102136104f3565b604051610220919061217e565b60405180910390f35b61023c6102373660046121e1565b610585565b6040519015158152602001610220565b6002545b604051908152602001610220565b61023c61026c36600461220d565b61059f565b60405160128152602001610220565b6102506105c3565b61023c6102963660046121e1565b6105d2565b6102506102a93660046121e1565b6105f4565b6102b6610673565b005b6102b66102c63660046121e1565b610685565b6102b66102d936600461224e565b61069b565b61030a6102ec366004612267565b6001600160a01b039081166000908152600860205260409020541690565b6040516001600160a01b039091168152602001610220565b6102b6610330366004612267565b6106a8565b60055460ff1661023c565b61023c61034e366004612284565b6106b2565b610250610361366004612267565b610896565b610379610374366004612267565b6108be565b60405163ffffffff9091168152602001610220565b61025061039c366004612267565b6001600160a01b031660009081526020819052604090205490565b6102b66108e0565b6102b66103cd3660046121e1565b6108f2565b6102506103e0366004612267565b610907565b6102b6610925565b60055461010090046001600160a01b031661030a565b61025061041136600461224e565b610935565b610213610991565b61025061042c366004612267565b6109a0565b61023c61043f3660046121e1565b610a27565b61023c6104523660046121e1565b610aa2565b6102b6610465366004612339565b610ab0565b6102b6610478366004612393565b610be6565b61025061048b3660046121e1565b610d4a565b61025061049e366004612401565b610dab565b6104b66104b136600461243a565b610dd6565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610220565b6102b66104ee366004612267565b610e5a565b60606003805461050290612471565b80601f016020809104026020016040519081016040528092919081815260200182805461052e90612471565b801561057b5780601f106105505761010080835404028352916020019161057b565b820191906000526020600020905b81548152906001019060200180831161055e57829003601f168201915b5050505050905090565b600033610593818585610ed0565b60019150505b92915050565b6000336105ad858285610ff4565b6105b885858561106e565b506001949350505050565b60006105cd611223565b905090565b6000336105938185856105e58383610dab565b6105ef91906124bb565b610ed0565b600043821061064a5760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064015b60405180910390fd5b6001600160a01b038316600090815260096020526040902061066c908361134a565b9392505050565b61067b611441565b6106836114a1565b565b61068d611441565b61069782826114f3565b5050565b6106a533826114fd565b50565b6106a53382611507565b60006106bd85610896565b8411156107205760405162461bcd60e51b815260206004820152602b60248201527f4552433230466c6173684d696e743a20616d6f756e742065786365656473206d60448201526a30bc233630b9b42637b0b760a91b6064820152608401610641565b600061072c8686610d4a565b905061073887866114f3565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038916906323e30c8b906107909033908b908b9088908c908c906004016124ce565b6020604051808303816000875af11580156107af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d3919061252a565b1461082c5760405162461bcd60e51b8152602060048201526024808201527f4552433230466c6173684d696e743a20696e76616c69642072657475726e2076604482015263616c756560e01b6064820152608401610641565b6000610842883061083d858a6124bb565b610ff4565b81158061085657506001600160a01b038116155b156108735761086e8861086984896124bb565b6114fd565b610888565b61087d88876114fd565b61088888828461106e565b506001979650505050505050565b60006001600160a01b03821630146108af576000610599565b60025461059990600019612543565b6001600160a01b03811660009081526009602052604081205461059990611580565b6108e8611441565b61068360006115e9565b6108fd823383610ff4565b61069782826114fd565b6001600160a01b038116600090815260066020526040812054610599565b61092d611441565b610683611643565b60004382106109865760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610641565b610599600a8361134a565b60606004805461050290612471565b6001600160a01b0381166000908152600960205260408120548015610a14576001600160a01b03831660009081526009602052604090206109e2600183612543565b815481106109f2576109f2612556565b60009182526020909120015464010000000090046001600160e01b0316610a17565b60005b6001600160e01b03169392505050565b60003381610a358286610dab565b905083811015610a955760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610641565b6105b88286868403610ed0565b60003361059381858561106e565b83421115610b005760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610641565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610b7a90610b729060a00160405160208183030381529060405280519060200120611680565b8585856116ce565b9050610b85816116f6565b8614610bd35760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610641565b610bdd8188611507565b50505050505050565b83421115610c365760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610641565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610c658c6116f6565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610cc082611680565b90506000610cd0828787876116ce565b9050896001600160a01b0316816001600160a01b031614610d335760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610641565b610d3e8a8a8a610ed0565b50505050505050505050565b60006001600160a01b0383163014610da45760405162461bcd60e51b815260206004820152601b60248201527f4552433230466c6173684d696e743a2077726f6e6720746f6b656e00000000006044820152606401610641565b600061066c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60408051808201909152600080825260208201526001600160a01b0383166000908152600960205260409020805463ffffffff8416908110610e1a57610e1a612556565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b610e62611441565b6001600160a01b038116610ec75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610641565b6106a5816115e9565b6001600160a01b038316610f325760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610641565b6001600160a01b038216610f935760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610641565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006110008484610dab565b90506000198114611068578181101561105b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610641565b6110688484848403610ed0565b50505050565b6001600160a01b0383166110d25760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610641565b6001600160a01b0382166111345760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610641565b61113f83838361171e565b6001600160a01b038316600090815260208190526040902054818110156111b75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610641565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361106884848461172b565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561127c57507f000000000000000000000000000000000000000000000000000000000000000046145b156112a657507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b8154600090818160058111156113a457600061136584611736565b61136f9085612543565b600088815260209020909150869082015463ffffffff161115611394578091506113a2565b61139f8160016124bb565b92505b505b808210156113f15760006113b8838361181e565b600088815260209020909150869082015463ffffffff1611156113dd578091506113eb565b6113e88160016124bb565b92505b506113a4565b801561142b5761141486611406600184612543565b600091825260209091200190565b5464010000000090046001600160e01b031661142e565b60005b6001600160e01b03169695505050505050565b6005546001600160a01b036101009091041633146106835760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610641565b6114a9611839565b6005805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6106978282611882565b610697828261190c565b6001600160a01b038281166000818152600860208181526040808420805485845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611068828483611924565b600063ffffffff8211156115e55760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610641565b5090565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61164b611a61565b6005805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114d63390565b600061059961168d611223565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006116df87878787611aa7565b915091506116ec81611b6b565b5095945050505050565b6001600160a01b03811660009081526006602052604090208054600181018255905b50919050565b611726611a61565b505050565b611726838383611cb5565b60008160000361174857506000919050565b6000600161175584611ce7565b901c6001901b9050600181848161176e5761176e61256c565b048201901c905060018184816117865761178661256c565b048201901c9050600181848161179e5761179e61256c565b048201901c905060018184816117b6576117b661256c565b048201901c905060018184816117ce576117ce61256c565b048201901c905060018184816117e6576117e661256c565b048201901c905060018184816117fe576117fe61256c565b048201901c905061066c818285816118185761181861256c565b04611d7b565b600061182d6002848418612582565b61066c908484166124bb565b60055460ff166106835760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610641565b61188c8282611d91565b6002546001600160e01b0310156118fe5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610641565b611068600a611e6483611e70565b6119168282611fc4565b611068600a61210983611e70565b816001600160a01b0316836001600160a01b0316141580156119465750600081115b15611726576001600160a01b038316156119d4576001600160a01b038316600090815260096020526040812081906119819061210985611e70565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516119c9929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611726576001600160a01b03821660009081526009602052604081208190611a0a90611e6485611e70565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611a52929190918252602082015260400190565b60405180910390a25050505050565b60055460ff16156106835760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610641565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611ade5750600090506003611b62565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611b32573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611b5b57600060019250925050611b62565b9150600090505b94509492505050565b6000816004811115611b7f57611b7f6125a4565b03611b875750565b6001816004811115611b9b57611b9b6125a4565b03611be85760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610641565b6002816004811115611bfc57611bfc6125a4565b03611c495760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610641565b6003816004811115611c5d57611c5d6125a4565b036106a55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610641565b6001600160a01b0383811660009081526008602052604080822054858416835291205461172692918216911683611924565b600080608083901c15611cfc57608092831c92015b604083901c15611d0e57604092831c92015b602083901c15611d2057602092831c92015b601083901c15611d3257601092831c92015b600883901c15611d4457600892831c92015b600483901c15611d5657600492831c92015b600283901c15611d6857600292831c92015b600183901c156105995760010192915050565b6000818310611d8a578161066c565b5090919050565b6001600160a01b038216611de75760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610641565b611df36000838361171e565b8060026000828254611e0591906124bb565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106976000838361172b565b600061066c82846124bb565b82546000908190818115611ebd57611e8d87611406600185612543565b60408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152611ed2565b60408051808201909152600080825260208201525b905080602001516001600160e01b03169350611ef284868863ffffffff16565b9250600082118015611f0a5750805163ffffffff1643145b15611f4f57611f1883612115565b611f2788611406600186612543565b80546001600160e01b03929092166401000000000263ffffffff909216919091179055611fba565b866040518060400160405280611f6443611580565b63ffffffff168152602001611f7886612115565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b6001600160a01b0382166120245760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610641565b6120308260008361171e565b6001600160a01b038216600090815260208190526040902054818110156120a45760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610641565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36117268360008461172b565b600061066c8284612543565b60006001600160e01b038211156115e55760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610641565b600060208083528351808285015260005b818110156121ab5785810183015185820160400152820161218f565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b03811681146106a557600080fd5b600080604083850312156121f457600080fd5b82356121ff816121cc565b946020939093013593505050565b60008060006060848603121561222257600080fd5b833561222d816121cc565b9250602084013561223d816121cc565b929592945050506040919091013590565b60006020828403121561226057600080fd5b5035919050565b60006020828403121561227957600080fd5b813561066c816121cc565b60008060008060006080868803121561229c57600080fd5b85356122a7816121cc565b945060208601356122b7816121cc565b935060408601359250606086013567ffffffffffffffff808211156122db57600080fd5b818801915088601f8301126122ef57600080fd5b8135818111156122fe57600080fd5b89602082850101111561231057600080fd5b9699959850939650602001949392505050565b803560ff8116811461233457600080fd5b919050565b60008060008060008060c0878903121561235257600080fd5b863561235d816121cc565b9550602087013594506040870135935061237960608801612323565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a0312156123ae57600080fd5b87356123b9816121cc565b965060208801356123c9816121cc565b955060408801359450606088013593506123e560808901612323565b925060a0880135915060c0880135905092959891949750929550565b6000806040838503121561241457600080fd5b823561241f816121cc565b9150602083013561242f816121cc565b809150509250929050565b6000806040838503121561244d57600080fd5b8235612458816121cc565b9150602083013563ffffffff8116811461242f57600080fd5b600181811c9082168061248557607f821691505b60208210810361171857634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610599576105996124a5565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60006020828403121561253c57600080fd5b5051919050565b81810381811115610599576105996124a5565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60008261259f57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fdfea264697066735822122057e08ed799a9773c2de4d8c40122801fc9994042a2e3e3ac01e5aa1c384b1c4b64736f6c63430008110033
\ No newline at end of file
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/README.mddiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# OpenZeppelin Contracts
-
-The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
-
-They are not meant to be edited.
-
-The originals can be found on [GitHub] and [npm].
-
-[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
-[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
-
-Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/access/Ownable.sol
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../utils/Context.sol";
-
-/**
- * @dev Contract module which provides a basic access control mechanism, where
- * there is an account (an owner) that can be granted exclusive access to
- * specific functions.
- *
- * By default, the owner account will be the one that deploys the contract. This
- * can later be changed with {transferOwnership}.
- *
- * This module is used through inheritance. It will make available the modifier
- * `onlyOwner`, which can be applied to your functions to restrict their use to
- * the owner.
- */
-abstract contract Ownable is Context {
- address private _owner;
-
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
- /**
- * @dev Initializes the contract setting the deployer as the initial owner.
- */
- constructor() {
- _transferOwnership(_msgSender());
- }
-
- /**
- * @dev Throws if called by any account other than the owner.
- */
- modifier onlyOwner() {
- _checkOwner();
- _;
- }
-
- /**
- * @dev Returns the address of the current owner.
- */
- function owner() public view virtual returns (address) {
- return _owner;
- }
-
- /**
- * @dev Throws if the sender is not the owner.
- */
- function _checkOwner() internal view virtual {
- require(owner() == _msgSender(), "Ownable: caller is not the owner");
- }
-
- /**
- * @dev Leaves the contract without owner. It will not be possible to call
- * `onlyOwner` functions anymore. Can only be called by the current owner.
- *
- * NOTE: Renouncing ownership will leave the contract without an owner,
- * thereby removing any functionality that is only available to the owner.
- */
- function renounceOwnership() public virtual onlyOwner {
- _transferOwnership(address(0));
- }
-
- /**
- * @dev Transfers ownership of the contract to a new account (`newOwner`).
- * Can only be called by the current owner.
- */
- function transferOwnership(address newOwner) public virtual onlyOwner {
- require(newOwner != address(0), "Ownable: new owner is the zero address");
- _transferOwnership(newOwner);
- }
-
- /**
- * @dev Transfers ownership of the contract to a new account (`newOwner`).
- * Internal function without access restriction.
- */
- function _transferOwnership(address newOwner) internal virtual {
- address oldOwner = _owner;
- _owner = newOwner;
- emit OwnershipTransferred(oldOwner, newOwner);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/ERC721.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/ERC721.sol
+++ /dev/null
@@ -1,503 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC721.sol";
-import "./IERC721Receiver.sol";
-import "./extensions/IERC721Metadata.sol";
-import "../../utils/Address.sol";
-import "../../utils/Context.sol";
-import "../../utils/Strings.sol";
-import "../../utils/introspection/ERC165.sol";
-
-/**
- * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
- * the Metadata extension, but not including the Enumerable extension, which is available separately as
- * {ERC721Enumerable}.
- */
-contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
- using Address for address;
- using Strings for uint256;
-
- // Token name
- string private _name;
-
- // Token symbol
- string private _symbol;
-
- // Mapping from token ID to owner address
- mapping(uint256 => address) private _owners;
-
- // Mapping owner address to token count
- mapping(address => uint256) private _balances;
-
- // Mapping from token ID to approved address
- mapping(uint256 => address) private _tokenApprovals;
-
- // Mapping from owner to operator approvals
- mapping(address => mapping(address => bool)) private _operatorApprovals;
-
- /**
- * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
- */
- constructor(string memory name_, string memory symbol_) {
- _name = name_;
- _symbol = symbol_;
- }
-
- /**
- * @dev See {IERC165-supportsInterface}.
- */
- function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
- return
- interfaceId == type(IERC721).interfaceId ||
- interfaceId == type(IERC721Metadata).interfaceId ||
- super.supportsInterface(interfaceId);
- }
-
- /**
- * @dev See {IERC721-balanceOf}.
- */
- function balanceOf(address owner) public view virtual override returns (uint256) {
- require(owner != address(0), "ERC721: address zero is not a valid owner");
- return _balances[owner];
- }
-
- /**
- * @dev See {IERC721-ownerOf}.
- */
- function ownerOf(uint256 tokenId) public view virtual override returns (address) {
- address owner = _ownerOf(tokenId);
- require(owner != address(0), "ERC721: invalid token ID");
- return owner;
- }
-
- /**
- * @dev See {IERC721Metadata-name}.
- */
- function name() public view virtual override returns (string memory) {
- return _name;
- }
-
- /**
- * @dev See {IERC721Metadata-symbol}.
- */
- function symbol() public view virtual override returns (string memory) {
- return _symbol;
- }
-
- /**
- * @dev See {IERC721Metadata-tokenURI}.
- */
- function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
- _requireMinted(tokenId);
-
- string memory baseURI = _baseURI();
- return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
- }
-
- /**
- * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
- * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
- * by default, can be overridden in child contracts.
- */
- function _baseURI() internal view virtual returns (string memory) {
- return "";
- }
-
- /**
- * @dev See {IERC721-approve}.
- */
- function approve(address to, uint256 tokenId) public virtual override {
- address owner = ERC721.ownerOf(tokenId);
- require(to != owner, "ERC721: approval to current owner");
-
- require(
- _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
- "ERC721: approve caller is not token owner or approved for all"
- );
-
- _approve(to, tokenId);
- }
-
- /**
- * @dev See {IERC721-getApproved}.
- */
- function getApproved(uint256 tokenId) public view virtual override returns (address) {
- _requireMinted(tokenId);
-
- return _tokenApprovals[tokenId];
- }
-
- /**
- * @dev See {IERC721-setApprovalForAll}.
- */
- function setApprovalForAll(address operator, bool approved) public virtual override {
- _setApprovalForAll(_msgSender(), operator, approved);
- }
-
- /**
- * @dev See {IERC721-isApprovedForAll}.
- */
- function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
- return _operatorApprovals[owner][operator];
- }
-
- /**
- * @dev See {IERC721-transferFrom}.
- */
- function transferFrom(
- address from,
- address to,
- uint256 tokenId
- ) public virtual override {
- //solhint-disable-next-line max-line-length
- require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
-
- _transfer(from, to, tokenId);
- }
-
- /**
- * @dev See {IERC721-safeTransferFrom}.
- */
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId
- ) public virtual override {
- safeTransferFrom(from, to, tokenId, "");
- }
-
- /**
- * @dev See {IERC721-safeTransferFrom}.
- */
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId,
- bytes memory data
- ) public virtual override {
- require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
- _safeTransfer(from, to, tokenId, data);
- }
-
- /**
- * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
- * are aware of the ERC721 protocol to prevent tokens from being forever locked.
- *
- * `data` is additional data, it has no specified format and it is sent in call to `to`.
- *
- * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
- * implement alternative mechanisms to perform token transfer, such as signature-based.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `tokenId` token must exist and be owned by `from`.
- * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
- *
- * Emits a {Transfer} event.
- */
- function _safeTransfer(
- address from,
- address to,
- uint256 tokenId,
- bytes memory data
- ) internal virtual {
- _transfer(from, to, tokenId);
- require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
- }
-
- /**
- * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
- */
- function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
- return _owners[tokenId];
- }
-
- /**
- * @dev Returns whether `tokenId` exists.
- *
- * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
- *
- * Tokens start existing when they are minted (`_mint`),
- * and stop existing when they are burned (`_burn`).
- */
- function _exists(uint256 tokenId) internal view virtual returns (bool) {
- return _ownerOf(tokenId) != address(0);
- }
-
- /**
- * @dev Returns whether `spender` is allowed to manage `tokenId`.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- */
- function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
- address owner = ERC721.ownerOf(tokenId);
- return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
- }
-
- /**
- * @dev Safely mints `tokenId` and transfers it to `to`.
- *
- * Requirements:
- *
- * - `tokenId` must not exist.
- * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
- *
- * Emits a {Transfer} event.
- */
- function _safeMint(address to, uint256 tokenId) internal virtual {
- _safeMint(to, tokenId, "");
- }
-
- /**
- * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
- * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
- */
- function _safeMint(
- address to,
- uint256 tokenId,
- bytes memory data
- ) internal virtual {
- _mint(to, tokenId);
- require(
- _checkOnERC721Received(address(0), to, tokenId, data),
- "ERC721: transfer to non ERC721Receiver implementer"
- );
- }
-
- /**
- * @dev Mints `tokenId` and transfers it to `to`.
- *
- * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
- *
- * Requirements:
- *
- * - `tokenId` must not exist.
- * - `to` cannot be the zero address.
- *
- * Emits a {Transfer} event.
- */
- function _mint(address to, uint256 tokenId) internal virtual {
- require(to != address(0), "ERC721: mint to the zero address");
- require(!_exists(tokenId), "ERC721: token already minted");
-
- _beforeTokenTransfer(address(0), to, tokenId, 1);
-
- // Check that tokenId was not minted by `_beforeTokenTransfer` hook
- require(!_exists(tokenId), "ERC721: token already minted");
-
- unchecked {
- // Will not overflow unless all 2**256 token ids are minted to the same owner.
- // Given that tokens are minted one by one, it is impossible in practice that
- // this ever happens. Might change if we allow batch minting.
- // The ERC fails to describe this case.
- _balances[to] += 1;
- }
-
- _owners[tokenId] = to;
-
- emit Transfer(address(0), to, tokenId);
-
- _afterTokenTransfer(address(0), to, tokenId, 1);
- }
-
- /**
- * @dev Destroys `tokenId`.
- * The approval is cleared when the token is burned.
- * This is an internal function that does not check if the sender is authorized to operate on the token.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- *
- * Emits a {Transfer} event.
- */
- function _burn(uint256 tokenId) internal virtual {
- address owner = ERC721.ownerOf(tokenId);
-
- _beforeTokenTransfer(owner, address(0), tokenId, 1);
-
- // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
- owner = ERC721.ownerOf(tokenId);
-
- // Clear approvals
- delete _tokenApprovals[tokenId];
-
- unchecked {
- // Cannot overflow, as that would require more tokens to be burned/transferred
- // out than the owner initially received through minting and transferring in.
- _balances[owner] -= 1;
- }
- delete _owners[tokenId];
-
- emit Transfer(owner, address(0), tokenId);
-
- _afterTokenTransfer(owner, address(0), tokenId, 1);
- }
-
- /**
- * @dev Transfers `tokenId` from `from` to `to`.
- * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
- *
- * Requirements:
- *
- * - `to` cannot be the zero address.
- * - `tokenId` token must be owned by `from`.
- *
- * Emits a {Transfer} event.
- */
- function _transfer(
- address from,
- address to,
- uint256 tokenId
- ) internal virtual {
- require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
- require(to != address(0), "ERC721: transfer to the zero address");
-
- _beforeTokenTransfer(from, to, tokenId, 1);
-
- // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
- require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
-
- // Clear approvals from the previous owner
- delete _tokenApprovals[tokenId];
-
- unchecked {
- // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
- // `from`'s balance is the number of token held, which is at least one before the current
- // transfer.
- // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
- // all 2**256 token ids to be minted, which in practice is impossible.
- _balances[from] -= 1;
- _balances[to] += 1;
- }
- _owners[tokenId] = to;
-
- emit Transfer(from, to, tokenId);
-
- _afterTokenTransfer(from, to, tokenId, 1);
- }
-
- /**
- * @dev Approve `to` to operate on `tokenId`
- *
- * Emits an {Approval} event.
- */
- function _approve(address to, uint256 tokenId) internal virtual {
- _tokenApprovals[tokenId] = to;
- emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
- }
-
- /**
- * @dev Approve `operator` to operate on all of `owner` tokens
- *
- * Emits an {ApprovalForAll} event.
- */
- function _setApprovalForAll(
- address owner,
- address operator,
- bool approved
- ) internal virtual {
- require(owner != operator, "ERC721: approve to caller");
- _operatorApprovals[owner][operator] = approved;
- emit ApprovalForAll(owner, operator, approved);
- }
-
- /**
- * @dev Reverts if the `tokenId` has not been minted yet.
- */
- function _requireMinted(uint256 tokenId) internal view virtual {
- require(_exists(tokenId), "ERC721: invalid token ID");
- }
-
- /**
- * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
- * The call is not executed if the target address is not a contract.
- *
- * @param from address representing the previous owner of the given token ID
- * @param to target address that will receive the tokens
- * @param tokenId uint256 ID of the token to be transferred
- * @param data bytes optional data to send along with the call
- * @return bool whether the call correctly returned the expected magic value
- */
- function _checkOnERC721Received(
- address from,
- address to,
- uint256 tokenId,
- bytes memory data
- ) private returns (bool) {
- if (to.isContract()) {
- try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
- return retval == IERC721Receiver.onERC721Received.selector;
- } catch (bytes memory reason) {
- if (reason.length == 0) {
- revert("ERC721: transfer to non ERC721Receiver implementer");
- } else {
- /// @solidity memory-safe-assembly
- assembly {
- revert(add(32, reason), mload(reason))
- }
- }
- }
- } else {
- return true;
- }
- }
-
- /**
- * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
- * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
- *
- * Calling conditions:
- *
- * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
- * - When `from` is zero, the tokens will be minted for `to`.
- * - When `to` is zero, ``from``'s tokens will be burned.
- * - `from` and `to` are never both zero.
- * - `batchSize` is non-zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _beforeTokenTransfer(
- address from,
- address to,
- uint256, /* firstTokenId */
- uint256 batchSize
- ) internal virtual {
- if (batchSize > 1) {
- if (from != address(0)) {
- _balances[from] -= batchSize;
- }
- if (to != address(0)) {
- _balances[to] += batchSize;
- }
- }
- }
-
- /**
- * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
- * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
- *
- * Calling conditions:
- *
- * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
- * - When `from` is zero, the tokens were minted for `to`.
- * - When `to` is zero, ``from``'s tokens were burned.
- * - `from` and `to` are never both zero.
- * - `batchSize` is non-zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _afterTokenTransfer(
- address from,
- address to,
- uint256 firstTokenId,
- uint256 batchSize
- ) internal virtual {}
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721.sol
+++ /dev/null
@@ -1,145 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
-
-pragma solidity ^0.8.0;
-
-import "../../utils/introspection/IERC165.sol";
-
-/**
- * @dev Required interface of an ERC721 compliant contract.
- */
-interface IERC721 is IERC165 {
- /**
- * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
- */
- event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
-
- /**
- * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
- */
- event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
-
- /**
- * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
- */
- event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-
- /**
- * @dev Returns the number of tokens in ``owner``'s account.
- */
- function balanceOf(address owner) external view returns (uint256 balance);
-
- /**
- * @dev Returns the owner of the `tokenId` token.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- */
- function ownerOf(uint256 tokenId) external view returns (address owner);
-
- /**
- * @dev Safely transfers `tokenId` token from `from` to `to`.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `tokenId` token must exist and be owned by `from`.
- * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
- * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
- *
- * Emits a {Transfer} event.
- */
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId,
- bytes calldata data
- ) external;
-
- /**
- * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
- * are aware of the ERC721 protocol to prevent tokens from being forever locked.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `tokenId` token must exist and be owned by `from`.
- * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
- * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
- *
- * Emits a {Transfer} event.
- */
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external;
-
- /**
- * @dev Transfers `tokenId` token from `from` to `to`.
- *
- * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
- * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
- * understand this adds an external call which potentially creates a reentrancy vulnerability.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `tokenId` token must be owned by `from`.
- * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
- *
- * Emits a {Transfer} event.
- */
- function transferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external;
-
- /**
- * @dev Gives permission to `to` to transfer `tokenId` token to another account.
- * The approval is cleared when the token is transferred.
- *
- * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
- *
- * Requirements:
- *
- * - The caller must own the token or be an approved operator.
- * - `tokenId` must exist.
- *
- * Emits an {Approval} event.
- */
- function approve(address to, uint256 tokenId) external;
-
- /**
- * @dev Approve or remove `operator` as an operator for the caller.
- * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
- *
- * Requirements:
- *
- * - The `operator` cannot be the caller.
- *
- * Emits an {ApprovalForAll} event.
- */
- function setApprovalForAll(address operator, bool _approved) external;
-
- /**
- * @dev Returns the account approved for `tokenId` token.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- */
- function getApproved(uint256 tokenId) external view returns (address operator);
-
- /**
- * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
- *
- * See {setApprovalForAll}
- */
- function isApprovedForAll(address owner, address operator) external view returns (bool);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721Receiver.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @title ERC721 token receiver interface
- * @dev Interface for any contract that wants to support safeTransfers
- * from ERC721 asset contracts.
- */
-interface IERC721Receiver {
- /**
- * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
- * by `operator` from `from`, this function is called.
- *
- * It must return its Solidity selector to confirm the token transfer.
- * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
- *
- * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
- */
- function onERC721Received(
- address operator,
- address from,
- uint256 tokenId,
- bytes calldata data
- ) external returns (bytes4);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC721.sol";
-import "../../../utils/Context.sol";
-
-/**
- * @title ERC721 Burnable Token
- * @dev ERC721 Token that can be burned (destroyed).
- */
-abstract contract ERC721Burnable is Context, ERC721 {
- /**
- * @dev Burns `tokenId`. See {ERC721-_burn}.
- *
- * Requirements:
- *
- * - The caller must own `tokenId` or be an approved operator.
- */
- function burn(uint256 tokenId) public virtual {
- //solhint-disable-next-line max-line-length
- require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
- _burn(tokenId);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
+++ /dev/null
@@ -1,159 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC721.sol";
-import "./IERC721Enumerable.sol";
-
-/**
- * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
- * enumerability of all the token ids in the contract as well as all token ids owned by each
- * account.
- */
-abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
- // Mapping from owner to list of owned token IDs
- mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
-
- // Mapping from token ID to index of the owner tokens list
- mapping(uint256 => uint256) private _ownedTokensIndex;
-
- // Array with all token ids, used for enumeration
- uint256[] private _allTokens;
-
- // Mapping from token id to position in the allTokens array
- mapping(uint256 => uint256) private _allTokensIndex;
-
- /**
- * @dev See {IERC165-supportsInterface}.
- */
- function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
- return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
- }
-
- /**
- * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
- */
- function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
- require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
- return _ownedTokens[owner][index];
- }
-
- /**
- * @dev See {IERC721Enumerable-totalSupply}.
- */
- function totalSupply() public view virtual override returns (uint256) {
- return _allTokens.length;
- }
-
- /**
- * @dev See {IERC721Enumerable-tokenByIndex}.
- */
- function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
- require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
- return _allTokens[index];
- }
-
- /**
- * @dev See {ERC721-_beforeTokenTransfer}.
- */
- function _beforeTokenTransfer(
- address from,
- address to,
- uint256 firstTokenId,
- uint256 batchSize
- ) internal virtual override {
- super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
-
- if (batchSize > 1) {
- // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
- revert("ERC721Enumerable: consecutive transfers not supported");
- }
-
- uint256 tokenId = firstTokenId;
-
- if (from == address(0)) {
- _addTokenToAllTokensEnumeration(tokenId);
- } else if (from != to) {
- _removeTokenFromOwnerEnumeration(from, tokenId);
- }
- if (to == address(0)) {
- _removeTokenFromAllTokensEnumeration(tokenId);
- } else if (to != from) {
- _addTokenToOwnerEnumeration(to, tokenId);
- }
- }
-
- /**
- * @dev Private function to add a token to this extension's ownership-tracking data structures.
- * @param to address representing the new owner of the given token ID
- * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
- */
- function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
- uint256 length = ERC721.balanceOf(to);
- _ownedTokens[to][length] = tokenId;
- _ownedTokensIndex[tokenId] = length;
- }
-
- /**
- * @dev Private function to add a token to this extension's token tracking data structures.
- * @param tokenId uint256 ID of the token to be added to the tokens list
- */
- function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
- _allTokensIndex[tokenId] = _allTokens.length;
- _allTokens.push(tokenId);
- }
-
- /**
- * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
- * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
- * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
- * This has O(1) time complexity, but alters the order of the _ownedTokens array.
- * @param from address representing the previous owner of the given token ID
- * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
- */
- function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
- // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
- // then delete the last slot (swap and pop).
-
- uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
- uint256 tokenIndex = _ownedTokensIndex[tokenId];
-
- // When the token to delete is the last token, the swap operation is unnecessary
- if (tokenIndex != lastTokenIndex) {
- uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
-
- _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
- _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
- }
-
- // This also deletes the contents at the last position of the array
- delete _ownedTokensIndex[tokenId];
- delete _ownedTokens[from][lastTokenIndex];
- }
-
- /**
- * @dev Private function to remove a token from this extension's token tracking data structures.
- * This has O(1) time complexity, but alters the order of the _allTokens array.
- * @param tokenId uint256 ID of the token to be removed from the tokens list
- */
- function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
- // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
- // then delete the last slot (swap and pop).
-
- uint256 lastTokenIndex = _allTokens.length - 1;
- uint256 tokenIndex = _allTokensIndex[tokenId];
-
- // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
- // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
- // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
- uint256 lastTokenId = _allTokens[lastTokenIndex];
-
- _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
- _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
-
- // This also deletes the contents at the last position of the array
- delete _allTokensIndex[tokenId];
- _allTokens.pop();
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC721.sol";
-
-/**
- * @dev ERC721 token with storage based token URI management.
- */
-abstract contract ERC721URIStorage is ERC721 {
- using Strings for uint256;
-
- // Optional mapping for token URIs
- mapping(uint256 => string) private _tokenURIs;
-
- /**
- * @dev See {IERC721Metadata-tokenURI}.
- */
- function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
- _requireMinted(tokenId);
-
- string memory _tokenURI = _tokenURIs[tokenId];
- string memory base = _baseURI();
-
- // If there is no base URI, return the token URI.
- if (bytes(base).length == 0) {
- return _tokenURI;
- }
- // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
- if (bytes(_tokenURI).length > 0) {
- return string(abi.encodePacked(base, _tokenURI));
- }
-
- return super.tokenURI(tokenId);
- }
-
- /**
- * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- */
- function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
- require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
- _tokenURIs[tokenId] = _tokenURI;
- }
-
- /**
- * @dev See {ERC721-_burn}. This override additionally checks to see if a
- * token-specific URI was set for the token, and if so, it deletes the token URI from
- * the storage mapping.
- */
- function _burn(uint256 tokenId) internal virtual override {
- super._burn(tokenId);
-
- if (bytes(_tokenURIs[tokenId]).length != 0) {
- delete _tokenURIs[tokenId];
- }
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../IERC721.sol";
-
-/**
- * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
- * @dev See https://eips.ethereum.org/EIPS/eip-721
- */
-interface IERC721Enumerable is IERC721 {
- /**
- * @dev Returns the total amount of tokens stored by the contract.
- */
- function totalSupply() external view returns (uint256);
-
- /**
- * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
- * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
- */
- function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
-
- /**
- * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
- * Use along with {totalSupply} to enumerate all tokens.
- */
- function tokenByIndex(uint256 index) external view returns (uint256);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
-
-pragma solidity ^0.8.0;
-
-import "../IERC721.sol";
-
-/**
- * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
- * @dev See https://eips.ethereum.org/EIPS/eip-721
- */
-interface IERC721Metadata is IERC721 {
- /**
- * @dev Returns the token collection name.
- */
- function name() external view returns (string memory);
-
- /**
- * @dev Returns the token collection symbol.
- */
- function symbol() external view returns (string memory);
-
- /**
- * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
- */
- function tokenURI(uint256 tokenId) external view returns (string memory);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Address.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Address.sol
+++ /dev/null
@@ -1,244 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
-
-pragma solidity ^0.8.1;
-
-/**
- * @dev Collection of functions related to the address type
- */
-library Address {
- /**
- * @dev Returns true if `account` is a contract.
- *
- * [IMPORTANT]
- * ====
- * It is unsafe to assume that an address for which this function returns
- * false is an externally-owned account (EOA) and not a contract.
- *
- * Among others, `isContract` will return false for the following
- * types of addresses:
- *
- * - an externally-owned account
- * - a contract in construction
- * - an address where a contract will be created
- * - an address where a contract lived, but was destroyed
- * ====
- *
- * [IMPORTANT]
- * ====
- * You shouldn't rely on `isContract` to protect against flash loan attacks!
- *
- * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
- * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
- * constructor.
- * ====
- */
- function isContract(address account) internal view returns (bool) {
- // This method relies on extcodesize/address.code.length, which returns 0
- // for contracts in construction, since the code is only stored at the end
- // of the constructor execution.
-
- return account.code.length > 0;
- }
-
- /**
- * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
- * `recipient`, forwarding all available gas and reverting on errors.
- *
- * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
- * of certain opcodes, possibly making contracts go over the 2300 gas limit
- * imposed by `transfer`, making them unable to receive funds via
- * `transfer`. {sendValue} removes this limitation.
- *
- * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
- *
- * IMPORTANT: because control is transferred to `recipient`, care must be
- * taken to not create reentrancy vulnerabilities. Consider using
- * {ReentrancyGuard} or the
- * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
- */
- function sendValue(address payable recipient, uint256 amount) internal {
- require(address(this).balance >= amount, "Address: insufficient balance");
-
- (bool success, ) = recipient.call{value: amount}("");
- require(success, "Address: unable to send value, recipient may have reverted");
- }
-
- /**
- * @dev Performs a Solidity function call using a low level `call`. A
- * plain `call` is an unsafe replacement for a function call: use this
- * function instead.
- *
- * If `target` reverts with a revert reason, it is bubbled up by this
- * function (like regular Solidity function calls).
- *
- * Returns the raw returned data. To convert to the expected return value,
- * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
- *
- * Requirements:
- *
- * - `target` must be a contract.
- * - calling `target` with `data` must not revert.
- *
- * _Available since v3.1._
- */
- function functionCall(address target, bytes memory data) internal returns (bytes memory) {
- return functionCallWithValue(target, data, 0, "Address: low-level call failed");
- }
-
- /**
- * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
- * `errorMessage` as a fallback revert reason when `target` reverts.
- *
- * _Available since v3.1._
- */
- function functionCall(
- address target,
- bytes memory data,
- string memory errorMessage
- ) internal returns (bytes memory) {
- return functionCallWithValue(target, data, 0, errorMessage);
- }
-
- /**
- * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
- * but also transferring `value` wei to `target`.
- *
- * Requirements:
- *
- * - the calling contract must have an ETH balance of at least `value`.
- * - the called Solidity function must be `payable`.
- *
- * _Available since v3.1._
- */
- function functionCallWithValue(
- address target,
- bytes memory data,
- uint256 value
- ) internal returns (bytes memory) {
- return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
- }
-
- /**
- * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
- * with `errorMessage` as a fallback revert reason when `target` reverts.
- *
- * _Available since v3.1._
- */
- function functionCallWithValue(
- address target,
- bytes memory data,
- uint256 value,
- string memory errorMessage
- ) internal returns (bytes memory) {
- require(address(this).balance >= value, "Address: insufficient balance for call");
- (bool success, bytes memory returndata) = target.call{value: value}(data);
- return verifyCallResultFromTarget(target, success, returndata, errorMessage);
- }
-
- /**
- * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
- * but performing a static call.
- *
- * _Available since v3.3._
- */
- function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
- return functionStaticCall(target, data, "Address: low-level static call failed");
- }
-
- /**
- * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
- * but performing a static call.
- *
- * _Available since v3.3._
- */
- function functionStaticCall(
- address target,
- bytes memory data,
- string memory errorMessage
- ) internal view returns (bytes memory) {
- (bool success, bytes memory returndata) = target.staticcall(data);
- return verifyCallResultFromTarget(target, success, returndata, errorMessage);
- }
-
- /**
- * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
- * but performing a delegate call.
- *
- * _Available since v3.4._
- */
- function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
- return functionDelegateCall(target, data, "Address: low-level delegate call failed");
- }
-
- /**
- * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
- * but performing a delegate call.
- *
- * _Available since v3.4._
- */
- function functionDelegateCall(
- address target,
- bytes memory data,
- string memory errorMessage
- ) internal returns (bytes memory) {
- (bool success, bytes memory returndata) = target.delegatecall(data);
- return verifyCallResultFromTarget(target, success, returndata, errorMessage);
- }
-
- /**
- * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
- * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
- *
- * _Available since v4.8._
- */
- function verifyCallResultFromTarget(
- address target,
- bool success,
- bytes memory returndata,
- string memory errorMessage
- ) internal view returns (bytes memory) {
- if (success) {
- if (returndata.length == 0) {
- // only check isContract if the call was successful and the return data is empty
- // otherwise we already know that it was a contract
- require(isContract(target), "Address: call to non-contract");
- }
- return returndata;
- } else {
- _revert(returndata, errorMessage);
- }
- }
-
- /**
- * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
- * revert reason or using the provided one.
- *
- * _Available since v4.3._
- */
- function verifyCallResult(
- bool success,
- bytes memory returndata,
- string memory errorMessage
- ) internal pure returns (bytes memory) {
- if (success) {
- return returndata;
- } else {
- _revert(returndata, errorMessage);
- }
- }
-
- function _revert(bytes memory returndata, string memory errorMessage) private pure {
- // Look for revert reason and bubble it up if present
- if (returndata.length > 0) {
- // The easiest way to bubble the revert reason is using memory via assembly
- /// @solidity memory-safe-assembly
- assembly {
- let returndata_size := mload(returndata)
- revert(add(32, returndata), returndata_size)
- }
- } else {
- revert(errorMessage);
- }
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Context.sol
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Provides information about the current execution context, including the
- * sender of the transaction and its data. While these are generally available
- * via msg.sender and msg.data, they should not be accessed in such a direct
- * manner, since when dealing with meta-transactions the account sending and
- * paying for execution may not be the actual sender (as far as an application
- * is concerned).
- *
- * This contract is only required for intermediate, library-like contracts.
- */
-abstract contract Context {
- function _msgSender() internal view virtual returns (address) {
- return msg.sender;
- }
-
- function _msgData() internal view virtual returns (bytes calldata) {
- return msg.data;
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Counters.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @title Counters
- * @author Matt Condon (@shrugs)
- * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
- * of elements in a mapping, issuing ERC721 ids, or counting request ids.
- *
- * Include with `using Counters for Counters.Counter;`
- */
-library Counters {
- struct Counter {
- // This variable should never be directly accessed by users of the library: interactions must be restricted to
- // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
- // this feature: see https://github.com/ethereum/solidity/issues/4637
- uint256 _value; // default: 0
- }
-
- function current(Counter storage counter) internal view returns (uint256) {
- return counter._value;
- }
-
- function increment(Counter storage counter) internal {
- unchecked {
- counter._value += 1;
- }
- }
-
- function decrement(Counter storage counter) internal {
- uint256 value = counter._value;
- require(value > 0, "Counter: decrement overflow");
- unchecked {
- counter._value = value - 1;
- }
- }
-
- function reset(Counter storage counter) internal {
- counter._value = 0;
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Strings.sol
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
-
-pragma solidity ^0.8.0;
-
-import "./math/Math.sol";
-
-/**
- * @dev String operations.
- */
-library Strings {
- bytes16 private constant _SYMBOLS = "0123456789abcdef";
- uint8 private constant _ADDRESS_LENGTH = 20;
-
- /**
- * @dev Converts a `uint256` to its ASCII `string` decimal representation.
- */
- function toString(uint256 value) internal pure returns (string memory) {
- unchecked {
- uint256 length = Math.log10(value) + 1;
- string memory buffer = new string(length);
- uint256 ptr;
- /// @solidity memory-safe-assembly
- assembly {
- ptr := add(buffer, add(32, length))
- }
- while (true) {
- ptr--;
- /// @solidity memory-safe-assembly
- assembly {
- mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
- }
- value /= 10;
- if (value == 0) break;
- }
- return buffer;
- }
- }
-
- /**
- * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
- */
- function toHexString(uint256 value) internal pure returns (string memory) {
- unchecked {
- return toHexString(value, Math.log256(value) + 1);
- }
- }
-
- /**
- * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
- */
- function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
- bytes memory buffer = new bytes(2 * length + 2);
- buffer[0] = "0";
- buffer[1] = "x";
- for (uint256 i = 2 * length + 1; i > 1; --i) {
- buffer[i] = _SYMBOLS[value & 0xf];
- value >>= 4;
- }
- require(value == 0, "Strings: hex length insufficient");
- return string(buffer);
- }
-
- /**
- * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
- */
- function toHexString(address addr) internal pure returns (string memory) {
- return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/ERC165.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/ERC165.sol
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC165.sol";
-
-/**
- * @dev Implementation of the {IERC165} interface.
- *
- * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
- * for the additional interface id that will be supported. For example:
- *
- * ```solidity
- * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
- * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
- * }
- * ```
- *
- * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
- */
-abstract contract ERC165 is IERC165 {
- /**
- * @dev See {IERC165-supportsInterface}.
- */
- function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
- return interfaceId == type(IERC165).interfaceId;
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/IERC165.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/IERC165.sol
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Interface of the ERC165 standard, as defined in the
- * https://eips.ethereum.org/EIPS/eip-165[EIP].
- *
- * Implementers can declare support of contract interfaces, which can then be
- * queried by others ({ERC165Checker}).
- *
- * For an implementation, see {ERC165}.
- */
-interface IERC165 {
- /**
- * @dev Returns true if this contract implements the interface defined by
- * `interfaceId`. See the corresponding
- * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
- * to learn more about how these ids are created.
- *
- * This function call must use less than 30 000 gas.
- */
- function supportsInterface(bytes4 interfaceId) external view returns (bool);
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/math/Math.sol
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Standard math utilities missing in the Solidity language.
- */
-library Math {
- enum Rounding {
- Down, // Toward negative infinity
- Up, // Toward infinity
- Zero // Toward zero
- }
-
- /**
- * @dev Returns the largest of two numbers.
- */
- function max(uint256 a, uint256 b) internal pure returns (uint256) {
- return a > b ? a : b;
- }
-
- /**
- * @dev Returns the smallest of two numbers.
- */
- function min(uint256 a, uint256 b) internal pure returns (uint256) {
- return a < b ? a : b;
- }
-
- /**
- * @dev Returns the average of two numbers. The result is rounded towards
- * zero.
- */
- function average(uint256 a, uint256 b) internal pure returns (uint256) {
- // (a + b) / 2 can overflow.
- return (a & b) + (a ^ b) / 2;
- }
-
- /**
- * @dev Returns the ceiling of the division of two numbers.
- *
- * This differs from standard division with `/` in that it rounds up instead
- * of rounding down.
- */
- function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
- // (a + b - 1) / b can overflow on addition, so we distribute.
- return a == 0 ? 0 : (a - 1) / b + 1;
- }
-
- /**
- * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
- * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
- * with further edits by Uniswap Labs also under MIT license.
- */
- function mulDiv(
- uint256 x,
- uint256 y,
- uint256 denominator
- ) internal pure returns (uint256 result) {
- unchecked {
- // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
- // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
- // variables such that product = prod1 * 2^256 + prod0.
- uint256 prod0; // Least significant 256 bits of the product
- uint256 prod1; // Most significant 256 bits of the product
- assembly {
- let mm := mulmod(x, y, not(0))
- prod0 := mul(x, y)
- prod1 := sub(sub(mm, prod0), lt(mm, prod0))
- }
-
- // Handle non-overflow cases, 256 by 256 division.
- if (prod1 == 0) {
- return prod0 / denominator;
- }
-
- // Make sure the result is less than 2^256. Also prevents denominator == 0.
- require(denominator > prod1);
-
- ///////////////////////////////////////////////
- // 512 by 256 division.
- ///////////////////////////////////////////////
-
- // Make division exact by subtracting the remainder from [prod1 prod0].
- uint256 remainder;
- assembly {
- // Compute remainder using mulmod.
- remainder := mulmod(x, y, denominator)
-
- // Subtract 256 bit number from 512 bit number.
- prod1 := sub(prod1, gt(remainder, prod0))
- prod0 := sub(prod0, remainder)
- }
-
- // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
- // See https://cs.stackexchange.com/q/138556/92363.
-
- // Does not overflow because the denominator cannot be zero at this stage in the function.
- uint256 twos = denominator & (~denominator + 1);
- assembly {
- // Divide denominator by twos.
- denominator := div(denominator, twos)
-
- // Divide [prod1 prod0] by twos.
- prod0 := div(prod0, twos)
-
- // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
- twos := add(div(sub(0, twos), twos), 1)
- }
-
- // Shift in bits from prod1 into prod0.
- prod0 |= prod1 * twos;
-
- // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
- // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
- // four bits. That is, denominator * inv = 1 mod 2^4.
- uint256 inverse = (3 * denominator) ^ 2;
-
- // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
- // in modular arithmetic, doubling the correct bits in each step.
- inverse *= 2 - denominator * inverse; // inverse mod 2^8
- inverse *= 2 - denominator * inverse; // inverse mod 2^16
- inverse *= 2 - denominator * inverse; // inverse mod 2^32
- inverse *= 2 - denominator * inverse; // inverse mod 2^64
- inverse *= 2 - denominator * inverse; // inverse mod 2^128
- inverse *= 2 - denominator * inverse; // inverse mod 2^256
-
- // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
- // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
- // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
- // is no longer required.
- result = prod0 * inverse;
- return result;
- }
- }
-
- /**
- * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
- */
- function mulDiv(
- uint256 x,
- uint256 y,
- uint256 denominator,
- Rounding rounding
- ) internal pure returns (uint256) {
- uint256 result = mulDiv(x, y, denominator);
- if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
- result += 1;
- }
- return result;
- }
-
- /**
- * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
- *
- * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
- */
- function sqrt(uint256 a) internal pure returns (uint256) {
- if (a == 0) {
- return 0;
- }
-
- // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
- //
- // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
- // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
- //
- // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
- // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
- // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
- //
- // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
- uint256 result = 1 << (log2(a) >> 1);
-
- // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
- // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
- // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
- // into the expected uint128 result.
- unchecked {
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- result = (result + a / result) >> 1;
- return min(result, a / result);
- }
- }
-
- /**
- * @notice Calculates sqrt(a), following the selected rounding direction.
- */
- function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = sqrt(a);
- return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
- }
- }
-
- /**
- * @dev Return the log in base 2, rounded down, of a positive value.
- * Returns 0 if given 0.
- */
- function log2(uint256 value) internal pure returns (uint256) {
- uint256 result = 0;
- unchecked {
- if (value >> 128 > 0) {
- value >>= 128;
- result += 128;
- }
- if (value >> 64 > 0) {
- value >>= 64;
- result += 64;
- }
- if (value >> 32 > 0) {
- value >>= 32;
- result += 32;
- }
- if (value >> 16 > 0) {
- value >>= 16;
- result += 16;
- }
- if (value >> 8 > 0) {
- value >>= 8;
- result += 8;
- }
- if (value >> 4 > 0) {
- value >>= 4;
- result += 4;
- }
- if (value >> 2 > 0) {
- value >>= 2;
- result += 2;
- }
- if (value >> 1 > 0) {
- result += 1;
- }
- }
- return result;
- }
-
- /**
- * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
- * Returns 0 if given 0.
- */
- function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = log2(value);
- return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
- }
- }
-
- /**
- * @dev Return the log in base 10, rounded down, of a positive value.
- * Returns 0 if given 0.
- */
- function log10(uint256 value) internal pure returns (uint256) {
- uint256 result = 0;
- unchecked {
- if (value >= 10**64) {
- value /= 10**64;
- result += 64;
- }
- if (value >= 10**32) {
- value /= 10**32;
- result += 32;
- }
- if (value >= 10**16) {
- value /= 10**16;
- result += 16;
- }
- if (value >= 10**8) {
- value /= 10**8;
- result += 8;
- }
- if (value >= 10**4) {
- value /= 10**4;
- result += 4;
- }
- if (value >= 10**2) {
- value /= 10**2;
- result += 2;
- }
- if (value >= 10**1) {
- result += 1;
- }
- }
- return result;
- }
-
- /**
- * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
- * Returns 0 if given 0.
- */
- function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = log10(value);
- return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
- }
- }
-
- /**
- * @dev Return the log in base 256, rounded down, of a positive value.
- * Returns 0 if given 0.
- *
- * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
- */
- function log256(uint256 value) internal pure returns (uint256) {
- uint256 result = 0;
- unchecked {
- if (value >> 128 > 0) {
- value >>= 128;
- result += 16;
- }
- if (value >> 64 > 0) {
- value >>= 64;
- result += 8;
- }
- if (value >> 32 > 0) {
- value >>= 32;
- result += 4;
- }
- if (value >> 16 > 0) {
- value >>= 16;
- result += 2;
- }
- if (value >> 8 > 0) {
- result += 1;
- }
- }
- return result;
- }
-
- /**
- * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
- * Returns 0 if given 0.
- */
- function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
- unchecked {
- uint256 result = log256(value);
- return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
- }
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/ZeppelinContract.soldiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/ZeppelinContract.sol
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.9;
-
-import "./@openzeppelin/contracts/token/ERC721/ERC721.sol";
-import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
-import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
-import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
-import "./@openzeppelin/contracts/access/Ownable.sol";
-import "./@openzeppelin/contracts/utils/Counters.sol";
-
-contract ZeppelinContract is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Burnable, Ownable {
- using Counters for Counters.Counter;
-
- Counters.Counter private _tokenIdCounter;
-
- constructor() ERC721("ZeppelinContract", "UNQ") {}
-
- function _baseURI() internal pure override returns (string memory) {
- return "test";
- }
-
- function safeMint(address to, string memory uri) public onlyOwner {
- uint256 tokenId = _tokenIdCounter.current();
- _tokenIdCounter.increment();
- _safeMint(to, tokenId);
- _setTokenURI(tokenId, uri);
- }
-
- // The following functions are overrides required by Solidity.
-
- function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
- internal
- override(ERC721, ERC721Enumerable)
- {
- super._beforeTokenTransfer(from, to, tokenId, batchSize);
- }
-
- function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
- super._burn(tokenId);
- }
-
- function tokenURI(uint256 tokenId)
- public
- view
- override(ERC721, ERC721URIStorage)
- returns (string memory)
- {
- return super.tokenURI(tokenId);
- }
-
- function supportsInterface(bytes4 interfaceId)
- public
- view
- override(ERC721, ERC721Enumerable)
- returns (bool)
- {
- return super.supportsInterface(interfaceId);
- }
-}
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.abidiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.abi
+++ /dev/null
@@ -1 +0,0 @@
-[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"string","name":"uri","type":"string"}],"name":"safeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.bindiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.bin
+++ /dev/null
@@ -1 +0,0 @@
-60806040523480156200001157600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b815250816000908162000068919062000195565b50600162000077828262000195565b505050620000946200008e6200009a60201b60201c565b6200009e565b62000261565b3390565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200011b57607f821691505b6020821081036200013c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019057600081815260208120601f850160051c810160208610156200016b5750805b601f850160051c820191505b818110156200018c5782815560010162000177565b5050505b505050565b81516001600160401b03811115620001b157620001b1620000f0565b620001c981620001c2845462000106565b8462000142565b602080601f831160018114620002015760008415620001e85750858301515b600019600386901b1c1916600185901b1785556200018c565b600085815260208120601f198616915b82811015620002325788860151825594840194600190910190840162000211565b5085821015620002515787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611f0d80620002716000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80636352211e116100b8578063a22cb4651161007c578063a22cb46514610271578063b88d4fde14610284578063c87b56dd14610297578063d204c45e146102aa578063e985e9c5146102bd578063f2fde38b146102f957600080fd5b80636352211e1461022a57806370a082311461023d578063715018a6146102505780638da5cb5b1461025857806395d89b411461026957600080fd5b806323b872dd116100ff57806323b872dd146101cb5780632f745c59146101de57806342842e0e146101f157806342966c68146102045780634f6ccce71461021757600080fd5b806301ffc9a71461013c57806306fdde0314610164578063081812fc14610179578063095ea7b3146101a457806318160ddd146101b9575b600080fd5b61014f61014a3660046118ab565b61030c565b60405190151581526020015b60405180910390f35b61016c61031d565b60405161015b9190611918565b61018c61018736600461192b565b6103af565b6040516001600160a01b03909116815260200161015b565b6101b76101b2366004611960565b6103d6565b005b6008545b60405190815260200161015b565b6101b76101d936600461198a565b6104f0565b6101bd6101ec366004611960565b610522565b6101b76101ff36600461198a565b6105b8565b6101b761021236600461192b565b6105d3565b6101bd61022536600461192b565b610604565b61018c61023836600461192b565b610697565b6101bd61024b3660046119c6565b6106f7565b6101b761077d565b600b546001600160a01b031661018c565b61016c610791565b6101b761027f3660046119e1565b6107a0565b6101b7610292366004611aa9565b6107af565b61016c6102a536600461192b565b6107e7565b6101b76102b8366004611b25565b6107f2565b61014f6102cb366004611b87565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6101b76103073660046119c6565b610829565b60006103178261089f565b92915050565b60606000805461032c90611bba565b80601f016020809104026020016040519081016040528092919081815260200182805461035890611bba565b80156103a55780601f1061037a576101008083540402835291602001916103a5565b820191906000526020600020905b81548152906001019060200180831161038857829003601f168201915b5050505050905090565b60006103ba826108c4565b506000908152600460205260409020546001600160a01b031690565b60006103e182610697565b9050806001600160a01b0316836001600160a01b0316036104535760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061046f575061046f81336102cb565b6104e15760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161044a565b6104eb8383610923565b505050565b6104fb335b82610991565b6105175760405162461bcd60e51b815260040161044a90611bf4565b6104eb838383610a10565b600061052d836106f7565b821061058f5760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b606482015260840161044a565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6104eb838383604051806020016040528060008152506107af565b6105dc336104f5565b6105f85760405162461bcd60e51b815260040161044a90611bf4565b61060181610b81565b50565b600061060f60085490565b82106106725760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b606482015260840161044a565b6008828154811061068557610685611c41565b90600052602060002001549050919050565b6000818152600260205260408120546001600160a01b0316806103175760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b60006001600160a01b0382166107615760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161044a565b506001600160a01b031660009081526003602052604090205490565b610785610b8a565b61078f6000610be4565b565b60606001805461032c90611bba565b6107ab338383610c36565b5050565b6107b93383610991565b6107d55760405162461bcd60e51b815260040161044a90611bf4565b6107e184848484610d04565b50505050565b606061031782610d37565b6107fa610b8a565b6000610805600c5490565b9050610815600c80546001019055565b61081f8382610e4b565b6104eb8183610e65565b610831610b8a565b6001600160a01b0381166108965760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161044a565b61060181610be4565b60006001600160e01b0319821663780e9d6360e01b1480610317575061031782610ef8565b6000818152600260205260409020546001600160a01b03166106015760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061095882610697565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061099d83610697565b9050806001600160a01b0316846001600160a01b031614806109e457506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80610a085750836001600160a01b03166109fd846103af565b6001600160a01b0316145b949350505050565b826001600160a01b0316610a2382610697565b6001600160a01b031614610a495760405162461bcd60e51b815260040161044a90611c57565b6001600160a01b038216610aab5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161044a565b610ab88383836001610f48565b826001600160a01b0316610acb82610697565b6001600160a01b031614610af15760405162461bcd60e51b815260040161044a90611c57565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61060181610f54565b600b546001600160a01b0316331461078f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161044a565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b031603610c975760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161044a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b610d0f848484610a10565b610d1b84848484610f94565b6107e15760405162461bcd60e51b815260040161044a90611c9c565b6060610d42826108c4565b6000828152600a602052604081208054610d5b90611bba565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8790611bba565b8015610dd45780601f10610da957610100808354040283529160200191610dd4565b820191906000526020600020905b815481529060010190602001808311610db757829003601f168201915b505050505090506000610dfe6040805180820190915260048152631d195cdd60e21b602082015290565b90508051600003610e10575092915050565b815115610e42578082604051602001610e2a929190611cee565b60405160208183030381529060405292505050919050565b610a0884611095565b6107ab828260405180602001604052806000815250611115565b6000828152600260205260409020546001600160a01b0316610ee05760405162461bcd60e51b815260206004820152602e60248201527f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b606482015260840161044a565b6000828152600a602052604090206104eb8282611d6b565b60006001600160e01b031982166380ac58cd60e01b1480610f2957506001600160e01b03198216635b5e139f60e01b145b8061031757506301ffc9a760e01b6001600160e01b0319831614610317565b6107e184848484611148565b610f5d81611288565b6000818152600a602052604090208054610f7690611bba565b159050610601576000818152600a6020526040812061060191611847565b60006001600160a01b0384163b1561108a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610fd8903390899088908890600401611e2b565b6020604051808303816000875af1925050508015611013575060408051601f3d908101601f1916820190925261101091810190611e68565b60015b611070573d808015611041576040519150601f19603f3d011682016040523d82523d6000602084013e611046565b606091505b5080516000036110685760405162461bcd60e51b815260040161044a90611c9c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610a08565b506001949350505050565b60606110a0826108c4565b60006110c36040805180820190915260048152631d195cdd60e21b602082015290565b905060008151116110e3576040518060200160405280600081525061110e565b806110ed8461132b565b6040516020016110fe929190611cee565b6040516020818303038152906040525b9392505050565b61111f83836113be565b61112c6000848484610f94565b6104eb5760405162461bcd60e51b815260040161044a90611c9c565b61115484848484611557565b60018111156111c35760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b606482015260840161044a565b816001600160a01b03851661121f5761121a81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611242565b836001600160a01b0316856001600160a01b0316146112425761124285826115df565b6001600160a01b03841661125e576112598161167c565b611281565b846001600160a01b0316846001600160a01b03161461128157611281848261172b565b5050505050565b600061129382610697565b90506112a3816000846001610f48565b6112ac82610697565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b606060006113388361176f565b600101905060008167ffffffffffffffff81111561135857611358611a1d565b6040519080825280601f01601f191660200182016040528015611382576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461138c57509392505050565b6001600160a01b0382166114145760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161044a565b6000818152600260205260409020546001600160a01b0316156114795760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b611487600083836001610f48565b6000818152600260205260409020546001600160a01b0316156114ec5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60018111156107e1576001600160a01b0384161561159d576001600160a01b03841660009081526003602052604081208054839290611597908490611e9b565b90915550505b6001600160a01b038316156107e1576001600160a01b038316600090815260036020526040812080548392906115d4908490611eae565b909155505050505050565b600060016115ec846106f7565b6115f69190611e9b565b600083815260076020526040902054909150808214611649576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b60085460009061168e90600190611e9b565b600083815260096020526040812054600880549394509092849081106116b6576116b6611c41565b9060005260206000200154905080600883815481106116d7576116d7611c41565b600091825260208083209091019290925582815260099091526040808220849055858252812055600880548061170f5761170f611ec1565b6001900381819060005260206000200160009055905550505050565b6000611736836106f7565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106117ae5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106117da576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106117f857662386f26fc10000830492506010015b6305f5e1008310611810576305f5e100830492506008015b612710831061182457612710830492506004015b60648310611836576064830492506002015b600a83106103175760010192915050565b50805461185390611bba565b6000825580601f10611863575050565b601f01602090049060005260206000209081019061060191905b80821115611891576000815560010161187d565b5090565b6001600160e01b03198116811461060157600080fd5b6000602082840312156118bd57600080fd5b813561110e81611895565b60005b838110156118e35781810151838201526020016118cb565b50506000910152565b600081518084526119048160208601602086016118c8565b601f01601f19169290920160200192915050565b60208152600061110e60208301846118ec565b60006020828403121561193d57600080fd5b5035919050565b80356001600160a01b038116811461195b57600080fd5b919050565b6000806040838503121561197357600080fd5b61197c83611944565b946020939093013593505050565b60008060006060848603121561199f57600080fd5b6119a884611944565b92506119b660208501611944565b9150604084013590509250925092565b6000602082840312156119d857600080fd5b61110e82611944565b600080604083850312156119f457600080fd5b6119fd83611944565b915060208301358015158114611a1257600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611a4e57611a4e611a1d565b604051601f8501601f19908116603f01168101908282118183101715611a7657611a76611a1d565b81604052809350858152868686011115611a8f57600080fd5b858560208301376000602087830101525050509392505050565b60008060008060808587031215611abf57600080fd5b611ac885611944565b9350611ad660208601611944565b925060408501359150606085013567ffffffffffffffff811115611af957600080fd5b8501601f81018713611b0a57600080fd5b611b1987823560208401611a33565b91505092959194509250565b60008060408385031215611b3857600080fd5b611b4183611944565b9150602083013567ffffffffffffffff811115611b5d57600080fd5b8301601f81018513611b6e57600080fd5b611b7d85823560208401611a33565b9150509250929050565b60008060408385031215611b9a57600080fd5b611ba383611944565b9150611bb160208401611944565b90509250929050565b600181811c90821680611bce57607f821691505b602082108103611bee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60008351611d008184602088016118c8565b835190830190611d148183602088016118c8565b01949350505050565b601f8211156104eb57600081815260208120601f850160051c81016020861015611d445750805b601f850160051c820191505b81811015611d6357828155600101611d50565b505050505050565b815167ffffffffffffffff811115611d8557611d85611a1d565b611d9981611d938454611bba565b84611d1d565b602080601f831160018114611dce5760008415611db65750858301515b600019600386901b1c1916600185901b178555611d63565b600085815260208120601f198616915b82811015611dfd57888601518255948401946001909101908401611dde565b5085821015611e1b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611e5e908301846118ec565b9695505050505050565b600060208284031215611e7a57600080fd5b815161110e81611895565b634e487b7160e01b600052601160045260246000fd5b8181038181111561031757610317611e85565b8082018082111561031757610317611e85565b634e487b7160e01b600052603160045260246000fdfea26469706673582212207960bc65d7484ab1502ccdc352c91f0fb91535a525cf99e1b6392e242548279a64736f6c63430008110033
\ No newline at end of file
js-packages/scripts/src/benchmarks/utils/types.tsdiffbeforeafterboth--- a/js-packages/scripts/src/benchmarks/utils/types.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-export interface IFeeGas {
- fee?: number | bigint,
- gas?: number | bigint,
- substrate?: number,
- zeppelin?: {
- fee: number | bigint,
- gas: number | bigint,
- }
-
-}
-export interface IFeeGasCsv extends IFeeGasVm {
- function: string,
-}
-export interface IFeeGasVm{
- ethFee?: number | bigint,
- ethGas?: number | bigint,
- substrate?: number,
- zeppelinFee?: number | bigint,
- zeppelinGas?: number | bigint
-}
-export interface IFunctionFee {
- [name: string]: IFeeGas
-}
-
-
-export abstract class FunctionFeeVM {
- [name: string]: IFeeGasVm
-
- static toCsv(model: FunctionFeeVM): IFeeGasCsv[]{
- const res: IFeeGasCsv[] = [];
- Object.keys(model).forEach(key => {
- res.push({
- function: key,
- ethFee: model[key].ethFee,
- ethGas: model[key].ethGas,
- substrate: model[key].substrate,
- zeppelinFee: model[key].zeppelinFee,
- zeppelinGas: model[key].zeppelinGas,
- });
- });
- return res;
- }
- static fromModel(model: IFunctionFee): FunctionFeeVM {
- const res: FunctionFeeVM = {};
-
- Object.keys(model).forEach(key => {
- res[key] = {};
- if(model[key].fee && model[key].gas) {
- res[key].ethFee = model[key].fee;
- res[key].ethGas = model[key].gas;
- }
- if(model[key].substrate)
- res[key].substrate = model[key].substrate;
- if(model[key].zeppelin) {
- res[key].zeppelinFee = model[key].zeppelin?.fee;
- res[key].zeppelinGas = model[key].zeppelin?.gas;
- }
- });
-
- return res;
- }
-}
\ No newline at end of file
js-packages/scripts/src/calibrate.tsdiffbeforeafterboth--- a/js-packages/scripts/src/calibrate.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingEthPlaygrounds} from '@unique/tests/src/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/src//eth/util/playgrounds/unique.dev.js';
-
-class Fract {
- static ZERO = new Fract(0n);
- constructor(public readonly a: bigint, public readonly b: bigint = 1n) {
- if(b === 0n) throw new Error('division by zero');
- if(b < 0n) throw new Error('missing normalization');
- }
-
- mul(other: Fract) {
- return new Fract(this.a * other.a, this.b * other.b).optimize();
- }
-
- div(other: Fract) {
- return this.mul(other.inv());
- }
-
- plus(other: Fract) {
- if(this.b === other.b) {
- return new Fract(this.a + other.a, this.b);
- }
- return new Fract(this.a * other.b + other.a * this.b, this.b * other.b).optimize();
- }
-
- minus(other: Fract) {
- return this.plus(other.neg());
- }
-
- neg() {
- return new Fract(-this.a, this.b);
- }
- inv() {
- if(this.a < 0) {
- return new Fract(-this.b, -this.a);
- } else {
- return new Fract(this.b, this.a);
- }
- }
-
- optimize() {
- function gcd(x: bigint, y: bigint) {
- if(x < 0n)
- x = -x;
- if(y < 0n)
- y = -y;
- while(y) {
- const t = y;
- y = x % y;
- x = t;
- }
- return x;
- }
- const v = gcd(this.a, this.b);
- return new Fract(this.a / v, this.b / v);
- }
-
- toBigInt() {
- return this.a / this.b;
- }
- toNumber() {
- const v = this.optimize();
- return Number(v.a) / Number(v.b);
- }
- toString() {
- const v = this.optimize();
- return `${v.a} / ${v.b}`;
- }
-
- lt(other: Fract) {
- return this.a * other.b < other.a * this.b;
- }
- eq(other: Fract) {
- return this.a * other.b === other.a * this.b;
- }
-
- sqrt() {
- if(this.a < 0n) {
- throw new Error('square root of negative numbers is not supported');
- }
-
- if(this.lt(new Fract(2n))) {
- return this;
- }
-
- function newtonIteration(n: Fract, x0: Fract): Fract {
- const x1 = rpn(n, x0, '/', x0, '+', new Fract(2n), '/');
- if(x0.eq(x1) || x0.eq(x1.minus(new Fract(1n)))) {
- return x0;
- }
- return newtonIteration(n, x1);
- }
-
- return newtonIteration(this, new Fract(1n));
- }
-}
-
-type Op = Fract | '+' | '-' | '*' | '/' | 'dup' | Op[];
-function rpn(...ops: (Op)[]) {
- const stack: Fract[] = [];
- for(const op of ops) {
- if(op instanceof Fract) {
- stack.push(op);
- } else if(op === '+') {
- if(stack.length < 2)
- throw new Error('stack underflow');
- const b = stack.pop()!;
- const a = stack.pop()!;
- stack.push(a.plus(b));
- } else if(op === '*') {
- if(stack.length < 2)
- throw new Error('stack underflow');
- const b = stack.pop()!;
- const a = stack.pop()!;
- stack.push(a.mul(b));
- } else if(op === '-') {
- if(stack.length < 2)
- throw new Error('stack underflow');
- const b = stack.pop()!;
- const a = stack.pop()!;
- stack.push(a.minus(b));
- } else if(op === '/') {
- if(stack.length < 2)
- throw new Error('stack underflow');
- const b = stack.pop()!;
- const a = stack.pop()!;
- stack.push(a.div(b));
- } else if(op === 'dup') {
- if(stack.length < 1)
- throw new Error('stack underflow');
- const a = stack.pop()!;
- stack.push(a);
- stack.push(a);
- } else if(Array.isArray(op)) {
- stack.push(rpn(...op));
- } else {
- throw new Error(`unknown operand: ${op}`);
- }
- }
- if(stack.length != 1)
- throw new Error('one element should be left on stack');
- return stack[0]!;
-}
-
-function linearRegression(points: { x: Fract, y: Fract }[]) {
- let sumxy = Fract.ZERO;
- let sumx = Fract.ZERO;
- let sumy = Fract.ZERO;
- let sumx2 = Fract.ZERO;
- const n = points.length;
- for(let i = 0; i < n; i++) {
- const p = points[i];
- sumxy = rpn(p.x, p.y, '*', sumxy, '+');
- sumx = sumx.plus(p.x);
- sumy = sumy.plus(p.y);
- sumx2 = rpn(p.x, p.x, '*', sumx2, '+');
- }
-
- const nb = new Fract(BigInt(n));
-
- const a = rpn(
- [nb, sumxy, '*', sumx, sumy, '*', '-'],
- [nb, sumx2, '*', sumx, sumx, '*', '-'],
- '/',
- );
- const b = rpn(
- [sumy, a, sumx, '*', '-'],
- nb,
- '/',
- );
-
- return {a, b};
-}
-
-const hypothesisLinear = (a: Fract, b: Fract) => (x: Fract) => rpn(x, a, '*', b, '+');
-
-// function error(points: { x: Fract, y: Fract }[], hypothesis: (a: Fract) => Fract) {
-// return points.map(p => {
-// const v = hypothesis(p.x);
-// const vv = p.y;
-
-// return rpn(v, vv, '-', 'dup', '*');
-// }).reduce((a, b) => a.plus(b), Fract.ZERO).sqrt().div(new Fract(BigInt(points.length)));
-// }
-
-async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>) {
- const alice = await privateKey('//Alice');
- const bob = await privateKey('//Bob');
- const dataPoints = [];
-
- {
- const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
- await token.transfer(alice, {Substrate: bob.address});
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
-
- console.log(`\t[NFT transfer] Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
- }
-
- const api = helper.getApi();
- const base = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt();
- for(let i = -5; i < 5; i++) {
- await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(base + base / 1000n * BigInt(i))));
-
- const coefficient = new Fract((await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt());
- const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
- const token = await collection.mintToken(alice, {Substrate: alice.address});
-
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
- await token.transfer(alice, {Substrate: bob.address});
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
-
- const transferPrice = new Fract(aliceBalanceBefore - aliceBalanceAfter);
-
- dataPoints.push({x: transferPrice, y: coefficient});
- }
- const {a, b} = linearRegression(dataPoints);
-
- const hyp = hypothesisLinear(a, b);
- // console.log(`\t[NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`);
-
- // 0.1 UNQ
- const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(1n, 10n), '*'));
- await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toBigInt())));
-
- {
- const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
- await token.transfer(alice, {Substrate: bob.address});
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
-
- console.log(`\t[NFT transfer] Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
- }
-}
-
-async function calibrateMinGasPrice(helper: EthUniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>) {
- const alice = await privateKey('//Alice');
- const caller = await helper.eth.createAccountWithBalance(alice);
- const receiver = helper.eth.createAccount();
- const dataPoints = [];
-
- {
- const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
- const token = await collection.mintToken(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
-
- console.log(`\t[ETH NFT transfer] Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
- }
-
- const api = helper.getApi();
- // const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt();
- const base = (await api.query.configuration.minGasPriceOverride() as any).toBigInt();
- for(let i = -8; i < 8; i++) {
- const gasPrice = base + base / 100000n * BigInt(i);
- const gasPriceStr = '0x' + gasPrice.toString(16);
- await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(gasPrice)));
-
- const coefficient = new Fract((await api.query.configuration.minGasPriceOverride() as any).toBigInt());
- const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
- const token = await collection.mintToken(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- const transferPrice = new Fract(await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS})));
-
- dataPoints.push({x: transferPrice, y: coefficient});
- }
-
- const {a, b} = linearRegression(dataPoints);
-
- const hyp = hypothesisLinear(a, b);
- // console.log(`\t[ETH NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`);
-
- // 0.15 UNQ
- const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(15n, 100n), '*'));
- await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toBigInt())));
-
- {
- const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
- const token = await collection.mintToken(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
-
- console.log(`\t[ETH NFT transfer] Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
- }
-}
-
-// eslint-disable-next-line @typescript-eslint/no-floating-promises
-(async () => {
- await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
- // Subsequent runs reduce error, as price line is not actually straight, this is a curve
-
- const iterations = 3;
-
- console.log('[Calibrate WeightToFee]');
- for(let i = 0; i < iterations; i++) {
- await calibrateWeightToFee(helper, privateKey);
- }
-
- console.log();
-
- console.log('[Calibrate MinGasPrice]');
- for(let i = 0; i < iterations; i++) {
- await calibrateMinGasPrice(helper, privateKey);
- }
- });
-})();
js-packages/scripts/src/calibrateApply.tsdiffbeforeafterboth--- a/js-packages/scripts/src/calibrateApply.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import {readFile, writeFile} from 'fs/promises';
-import path from 'path';
-import {makeNames, usingPlaygrounds} from '@unique/tests/src/util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-const formatNumber = (num: string): string => num.split('').reverse().join('').replace(/([0-9]{3})/g, '$1_').split('').reverse().join('').replace(/^_/, '');
-
-(async () => {
- let weightToFeeCoefficientOverride: string;
- let minGasPriceOverride: string;
- await usingPlaygrounds(async (helpers, _privateKey) => {
- weightToFeeCoefficientOverride = (await helpers.getApi().query.configuration.weightToFeeCoefficientOverride() as any).toBigInt().toString();
- minGasPriceOverride = (await helpers.getApi().query.configuration.minGasPriceOverride() as any).toBigInt().toString();
- });
- const constantsFile = path.resolve(dirname, '../../primitives/common/src/constants.rs');
- let constants = (await readFile(constantsFile)).toString();
-
- let weight2feeFound = false;
- constants = constants.replace(/(\/\*<weight2fee>\*\/)[0-9_]+(\/\*<\/weight2fee>\*\/)/, (_f, p, s) => {
- weight2feeFound = true;
- return p+formatNumber(weightToFeeCoefficientOverride)+s;
- });
- if(!weight2feeFound) {
- throw new Error('failed to find weight2fee marker in source code');
- }
-
- let minGasPriceFound = false;
- constants = constants.replace(/(\/\*<mingasprice>\*\/)[0-9_]+(\/\*<\/mingasprice>\*\/)/, (_f, p, s) => {
- minGasPriceFound = true;
- return p+formatNumber(minGasPriceOverride)+s;
- });
- if(!minGasPriceFound) {
- throw new Error('failed to find mingasprice marker in source code');
- }
-
- await writeFile(constantsFile, constants);
-})().catch(e => {
- console.log(e.stack);
-});
js-packages/scripts/src/fetchMetadata.tsdiffbeforeafterboth--- a/js-packages/scripts/src/fetchMetadata.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import {writeFile} from 'fs/promises';
-import {join} from 'path';
-import {exit} from 'process';
-import {fileURLToPath} from 'url';
-
-const url = process.env.RPC_URL;
-if(!url) throw new Error('RPC_URL is not set');
-
-const srcDir = fileURLToPath(new URL('.', import.meta.url));
-
-for(let i = 0; i < 10; i++) {
- try {
- console.log(`Trying to fetch metadata, retry ${i + 1}/${10}`);
- const response = await fetch(url, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- redirect: 'follow',
- body: JSON.stringify({
- jsonrpc: '2.0',
- id: '1',
- method: 'state_getMetadata',
- params: [],
- }),
- });
- const json = await response.json();
- const output = join(srcDir, 'metadata.json');
- console.log(`Received response, saving to ${output}`);
- await writeFile(output, JSON.stringify(json));
- exit(0);
- } catch (e) {
- console.error('Failed to request metadata:');
- console.error(e);
- console.error('Waiting 1 minute');
- await new Promise(res => setTimeout(res, 60 * 1000));
- }
-}
-console.error('Out of retries');
-exit(1);
js-packages/scripts/src/generateEnv.tsdiffbeforeafterboth--- a/js-packages/scripts/src/generateEnv.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import {ApiPromise, WsProvider} from '@polkadot/api';
-import {readFile} from 'fs/promises';
-import {join} from 'path';
-import {makeNames} from '@unique/tests/src/util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-async function fetchVersion(chain: string): Promise<string> {
- const api = await ApiPromise.create({provider: new WsProvider(chain)});
- const last = (await api.query.system.lastRuntimeUpgrade()).toJSON();
- await api.disconnect();
- return (last as any).specVersion.toString();
-}
-
-function setVar(env: string, key: string, value: string): string {
- let found = false;
- const newEnv = env.replace(new RegExp(`${key}=.+?\n`), () => {
- found = true;
- return `${key}=${value}\n`;
- });
- if(!found) throw new Error(`env key "${key}" is not found`);
- return newEnv;
-}
-
-// Fetch and format version string
-async function ff(url: string, regex: RegExp, rep: string | ((substring: string, ...params:any[]) => string)): Promise<string> {
- const ver = await fetchVersion(url);
- if(ver.match(regex) === null)
- throw new Error(`bad regex for ${url}`);
- return ver.replace(regex, rep as any);
-}
-function fixupUnique(version: string): string {
- if(version === 'release-v930033')
- return 'release-v930033-fix-gas-price';
- if(version === 'release-v930034')
- return 'release-v930034-fix-gas-price';
- return version;
-}
-
-(async () => {
- let env = (await readFile(join(dirname, '../../.env'))).toString();
- await Promise.all([
- ff('wss://rpc.polkadot.io/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'POLKADOT_MAINNET_BRANCH', v)),
- ff('wss://statemint-rpc.polkadot.io/', /^(....)$/, 'release-parachains-v$1').then(v => env = setVar(env, 'STATEMINT_BUILD_BRANCH', v)),
- ff('wss://acala-rpc-0.aca-api.network/', /^(.)(..)(.)$/, '$1.$2.$3').then(v => env = setVar(env, 'ACALA_BUILD_BRANCH', v)),
- ff('wss://wss.api.moonbeam.network/', /^(....)$/, 'runtime-$1').then(v => env = setVar(env, 'MOONBEAM_BUILD_BRANCH', v)),
- ff('wss://ws.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'UNIQUE_MAINNET_BRANCH', fixupUnique(v))),
-
- ff('wss://kusama-rpc.polkadot.io/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'KUSAMA_MAINNET_BRANCH', v)),
- ff('wss://statemine-rpc.polkadot.io/', /^(....)$/, 'release-parachains-v$1').then(v => env = setVar(env, 'STATEMINE_BUILD_BRANCH', v)),
- ff('wss://karura-rpc-0.aca-api.network/', /^(.)(..)(.)$/, 'release-karura-$1.$2.$3').then(v => env = setVar(env, 'KARURA_BUILD_BRANCH', v)),
- ff('wss://wss.api.moonriver.moonbeam.network/', /^(....)$/, 'runtime-$1').then(v => env = setVar(env, 'MOONRIVER_BUILD_BRANCH', v)),
- ff('wss://ws-quartz.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'QUARTZ_MAINNET_BRANCH', fixupUnique(v))),
-
- ff('wss://ws-westend.unique.network/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'UNIQUEWEST_MAINNET_BRANCH', v)),
- ff('wss://westmint-rpc.polkadot.io/', /^(....)$/, 'parachains-v$1').then(v => env = setVar(env, 'WESTMINT_BUILD_BRANCH', v)),
- ff('wss://ws-opal.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'OPAL_MAINNET_BRANCH', fixupUnique(v))),
-
- ff('wss://ws-eastend.unique.network/', /^(.)(..)(.)$/, 'release-v0.$1.$2').then(v => env = setVar(env, 'UNIQUEEAST_MAINNET_BRANCH', v)),
- ff('wss://ws-sapphire.unique.network/', /^(......)$/, 'release-v$1').then(v => env = setVar(env, 'SAPPHIRE_MAINNET_BRANCH', fixupUnique(v))),
-
- ff('wss://rpc.astar.network/', /^(.+)$/, (_, r) => {
- switch (r) {
- case '55': return 'v5.3.0';
- case '57': return 'v5.4.0';
- case '61': return 'v5.11.0';
- case '66': return 'v5.18.0';
- default: throw new Error('unknown astar branch for runtime ' + r);
- }
- }).then(v => env = setVar(env, 'ASTAR_BUILD_BRANCH', v)),
- ff('wss://shiden.api.onfinality.io/public-ws', /^(.+)$/, (_, r) => {
- switch (r) {
- case '90': return 'v4.49.0';
- case '96': return 'v5.4.0';
- case '100': return 'v5.10.0';
- case '104': return 'v5.15.0';
- case '106': return 'v5.18.0';
- default: throw new Error('unknown shiden branch for runtime ' + r);
- }
- }).then(v => env = setVar(env, 'SHIDEN_BUILD_BRANCH', v)),
- ]);
- console.log(env);
-})().catch(e => {
- console.error('Fatal');
- console.error(e.stack);
- process.exit(1);
-});
js-packages/scripts/src/generate_types/functions.shdiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/functions.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-
-function do_rpc {
- curl -s --header "Content-Type: application/json" -XPOST --data "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"$1\",\"params\":[$2]}" $RPC_URL
-}
js-packages/scripts/src/generate_types/generate_types_package.shdiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/generate_types_package.sh
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env bash
-
-set -eu
-
-DIR=$(realpath $(dirname "$0"))
-TEMPLATE=$DIR/types_template
-GIT_REPO=git@github.com:UniqueNetwork/unique-types-js.git
-
-. $DIR/functions.sh
-
-usage() {
- echo "Usage: [RPC_URL=http://localhost:9944] $0 <--rc|--release> [--force] [--push] [--rpc-url=http://localhost:9944]" 1>&2
- exit 1
-}
-
-rc=
-release=
-force=
-push=
-
-for i in "$@"; do
-case $i in
- --rc)
- rc=1
- if test "$release"; then usage; fi
- ;;
- --release)
- release=1
- if test "$rc"; then usage; fi
- ;;
- --force)
- force=1
- ;;
- --push)
- push=1
- ;;
- --rpc-url=*)
- RPC_URL=${i#*=}
- ;;
- *)
- usage
- ;;
-esac
-done
-
-if test \( ! \( "$rc" -o "$release" \) \) -o \( "${RPC_URL=}" = "" \); then
- usage
-elif test "$rc"; then
- echo "Rc build"
-else
- echo "Release build"
-fi
-
-cd $DIR/..
-yarn polkadot-types
-
-version=$(do_rpc state_getRuntimeVersion "")
-spec_version=$(echo $version | jq -r .result.specVersion)
-spec_name=$(echo $version | jq -r .result.specName)
-echo "Spec version: $spec_version, name: $spec_name"
-
-case $spec_name in
- opal)
- package_name=@unique-nft/opal-testnet-types
- repo_branch=opal-testnet
- repo_tag=$repo_branch
- ;;
- sapphire)
- package_name=@unique-nft/sapphire-mainnet-types
- repo_branch=sapphire-mainnet
- repo_tag=$repo_branch
- ;;
- quartz)
- package_name=@unique-nft/quartz-mainnet-types
- repo_branch=quartz-mainnet
- repo_tag=$repo_branch
- ;;
- unique)
- package_name=@unique-nft/unique-mainnet-types
- repo_branch=master
- repo_tag=unique-mainnet
- ;;
- *)
- echo "unknown spec name: $spec_name"
- exit 1
- ;;
-esac
-
-if test "$rc" = 1; then
- if "$spec_name" != opal; then
- echo "rc types can only be based on opal spec"
- exit 1
- fi
- package_name=@unique-nft/rc-types
- repo_branch=rc
- repo_tag=$repo_branch
-fi
-
-package_version=${spec_version:0:4}.$(echo ${spec_version:4:4} | sed 's/^0*//').
-last_patch=NEVER
-for tag in $(git ls-remote -t --refs $GIT_REPO | cut -f 2 | sort -r); do
- tag_prefix=refs/tags/$repo_tag-v$package_version
- if [[ $tag == $tag_prefix* ]]; then
- last_patch=${tag#$tag_prefix}
- break;
- fi
-done
-echo "Package version: ${package_version}X, name: $package_name"
-echo "Last published: $package_version$last_patch"
-
-if test "$last_patch" = "NEVER"; then
- new_package_version=${package_version}0
-else
- new_package_version=${package_version}$((last_patch+1))
-fi
-package_version=${package_version}$last_patch
-echo "New package version: $new_package_version"
-
-pjsapi_ver=^$(cat $DIR/../package.json | jq -r '.dependencies."@polkadot/api"' | sed -e "s/^\^//")
-tsnode_ver=^$(cat $DIR/../package.json | jq -r '.devDependencies."ts-node"' | sed -e "s/^\^//")
-ts_ver=^$(cat $DIR/../package.json | jq -r '.devDependencies."typescript"' | sed -e "s/^\^//")
-
-gen=$(mktemp -d)
-pushd $gen
-git clone $GIT_REPO -b $repo_branch --depth 1 .
-if test "$last_patch" != "NEVER"; then
- git reset --hard $repo_tag-v$package_version
-fi
-git rm -r "*"
-popd
-
-# Using old package_version here, becaue we first check if
-# there is any difference between generated and already uplaoded types
-cat $TEMPLATE/package.json \
-| jq '.private = false' - \
-| jq '.name = "'$package_name'"' - \
-| jq '.version = "'$package_version'"' - \
-| jq '.peerDependencies."@polkadot/api" = "'$pjsapi_ver'"' - \
-| jq '.peerDependencies."@polkadot/types" = "'$pjsapi_ver'"' - \
-| jq '.devDependencies."@polkadot/api" = "'$pjsapi_ver'"' - \
-| jq '.devDependencies."@polkadot/types" = "'$pjsapi_ver'"' - \
-| jq '.devDependencies."ts-node" = "'$tsnode_ver'"' - \
-| jq '.devDependencies."typescript" = "'$ts_ver'"' - \
-> $gen/package.json
-for file in .gitignore .npmignore README.md tsconfig.json; do
- cp $TEMPLATE/$file $gen/
-done
-package_name_replacement=$(printf '%s\n' "$package_name" | sed -e 's/[\/&]/\\&/g')
-sed -i 's/PKGNAME/'$package_name_replacement'/' $gen/README.md
-
-rsync -ar --exclude .gitignore src/interfaces/ $gen
-for file in $gen/augment-* $gen/**/types.ts $gen/registry.ts; do
- sed -i '1s;^;//@ts-nocheck\n;' $file
-done
-
-pushd $gen
-git add .
-popd
-
-pushd $gen
-if git diff --quiet HEAD && test ! "$force"; then
- echo "no changes detected"
- exit 0
-fi
-popd
-
-mv $gen/package.json $gen/package.old.json
-cat $gen/package.old.json \
-| jq '.version = "'$new_package_version'"' - \
-> $gen/package.json
-rm $gen/package.old.json
-pushd $gen
-git add package.json
-popd
-
-echo "package.json contents:"
-cat $gen/package.json
-echo "overall diff:"
-pushd $gen
-git status
-git diff HEAD || true
-popd
-
-# This check is only active if running in interactive terminal
-if [ -t 0 ]; then
- read -p "Is everything ok at $gen [y/n]? " -n 1 -r
- echo
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
- echo "Aborting!"
- exit 1
- fi
-fi
-
-pushd $gen
-yarn
-yarn prepublish
-git commit -m "chore: upgrade types to v$new_package_version"
-git tag --force $repo_tag-v$new_package_version
-if test "$push" = 1; then
- git push --tags --force -u origin HEAD
-else
- echo "--push not given, origin repo left intact"
- echo "To publish manually, go to $gen, and run \"git push --tags --force -u origin HEAD\""
-fi
-popd
js-packages/scripts/src/generate_types/readyness.jsdiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/readyness.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import {ApiPromise, WsProvider} from '@polkadot/api';
-
-const connect = async () => {
- const wsEndpoint = 'ws://127.0.0.1:9944';
- const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});
- await api.isReadyOrError;
-
- const head = (await api.rpc.chain.getHeader()).number.toNumber();
- await api.disconnect();
- if(head < 1) throw Error('No block #1');
-
-};
-
-const sleep = time => new Promise(resolve => {
- setTimeout(() => resolve(), time);
-});
-
-const main = async () => {
- // eslint-disable-next-line no-constant-condition
- while(true) {
- try {
- await connect();
- break;
- }
- catch (e) {
- await sleep(10000);
- console.log(e);
- }
- }
-};
-
-main().then(() => process.exit(0)).catch(e => {
- console.error(e);
- process.exit(1);
-});
js-packages/scripts/src/generate_types/types_template/.gitignorediffbeforeafterboth--- a/js-packages/scripts/src/generate_types/types_template/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*.js
-*.map
-*.d.ts
-/node_modules
-metadata.json
js-packages/scripts/src/generate_types/types_template/.npmignorediffbeforeafterboth--- a/js-packages/scripts/src/generate_types/types_template/.npmignore
+++ /dev/null
@@ -1 +0,0 @@
-/src
js-packages/scripts/src/generate_types/types_template/README.mddiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/types_template/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# PKGNAME
-
-Unique network api types
-
-Do not edit by hand, those types are generated automatically, and definitions are located in chain repo
-
-## Using types
-
-Install library:
-
-```bash
-yarn add --dev PKGNAME
-```
-
-Replace polkadot.js types with our chain types adding corresponding path override to the tsconfig `compilerOptions.paths` section:
-
-```json
-// in tsconfig.json
-{
- "compilerOptions": {
- "paths": {
- "@polkadot/types/lookup": ["node_modules/PKGNAME/types-lookup"]
- }
- }
-}
-```
-
-Since polkadot v7 api augmentations not loaded by default, in every file, where you need to access `api.tx`, `api.query`, `api.rpc`, etc; you should explicitly import corresponding augmentation before any other `polkadot.js` related import:
-```
-import 'PKGNAME/augment-api';
-```
js-packages/scripts/src/generate_types/types_template/package.jsondiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/types_template/package.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "TODO",
- "private": true,
- "version": "TODO",
- "main": "index.js",
- "repository": "git@github.com:UniqueNetwork/unique-types-js.git",
- "homepage": "https://unique.network/",
- "license": "MIT",
- "scripts": {
- "prepublish": "tsc -d"
- },
- "peerDependencies": {
- "@polkadot/api": "TODO",
- "@polkadot/types": "TODO"
- },
- "devDependencies": {
- "@polkadot/api": "TODO",
- "@polkadot/types": "TODO",
- "ts-node": "TODO",
- "typescript": "TODO"
- }
-}
js-packages/scripts/src/generate_types/types_template/tsconfig.jsondiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/types_template/tsconfig.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "exclude": [
- "node_modules",
- "node_modules/**/*",
- "../node_modules/**/*",
- "**/node_modules/**/*"
- ],
- "compilerOptions": {
- "target": "ES2020",
- "moduleResolution": "node",
- "esModuleInterop": true,
- "resolveJsonModule": true,
- "module": "commonjs",
- "sourceMap": true,
- "outDir": ".",
- "rootDir": ".",
- "strict": true,
- "paths": {
- },
- "skipLibCheck": true,
- },
- "include": [
- "**/*",
- ],
- "lib": [
- "es2017"
- ],
-}
js-packages/scripts/src/generate_types/wait_for_first_block.shdiffbeforeafterboth--- a/js-packages/scripts/src/generate_types/wait_for_first_block.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env bash
-
-DIR=$(dirname "$0")
-
-. $DIR/functions.sh
-
-last_block_id=0
-block_id=0
-function get_block {
- block_id_hex=$(do_rpc chain_getHeader | jq -r .result.number)
- block_id=$((${block_id_hex}))
- echo Id = $block_id
-}
-
-function had_new_block {
- last_block_id=$block_id
- get_block
- if (( last_block_id != 0 && block_id > last_block_id )); then
- return 0
- fi
- return 1
-}
-
-function reset_check {
- last_block_id=0
- block_id=0
-}
-
-while ! had_new_block; do
- echo "Waiting for next block..."
- sleep 12
-done
-reset_check
-
-echo "Chain is running, but lets wait for another block after a minute, to avoid startup flakiness."
-sleep 60
-
-while ! had_new_block; do
- echo "Waiting for another block..."
- sleep 12
-done
-
-echo "Chain is running!"
js-packages/scripts/src/metadata.jsondiffbeforeafterboth--- a/js-packages/scripts/src/metadata.json
+++ /dev/null
@@ -1 +0,0 @@
-{"jsonrpc":"2.0","result":"0x6d6574610eed0a000c1c73705f636f72651863727970746f2c4163636f756e7449643332000004000401205b75383b2033325d0000040000032000000008000800000503000c08306672616d655f73797374656d2c4163636f756e74496e666f08144e6f6e636501102c4163636f756e74446174610114001401146e6f6e63651001144e6f6e6365000124636f6e73756d657273100120526566436f756e7400012470726f766964657273100120526566436f756e7400012c73756666696369656e7473100120526566436f756e740001106461746114012c4163636f756e74446174610000100000050500140c3c70616c6c65745f62616c616e6365731474797065732c4163636f756e7444617461041c42616c616e63650118001001106672656518011c42616c616e6365000120726573657276656418011c42616c616e636500011866726f7a656e18011c42616c616e6365000114666c6167731c01284578747261466c61677300001800000507001c0c3c70616c6c65745f62616c616e636573147479706573284578747261466c61677300000400180110753132380000200c346672616d655f737570706f7274206469737061746368405065724469737061746368436c6173730404540124000c01186e6f726d616c2401045400012c6f7065726174696f6e616c240104540001246d616e6461746f7279240104540000240c2873705f77656967687473247765696768745f76321857656967687400000801207265665f74696d6528010c75363400012870726f6f665f73697a6528010c7536340000280000062c002c000005060030083c7072696d69746976655f74797065731048323536000004000401205b75383b2033325d000034000002080038102873705f72756e74696d651c67656e65726963186469676573741844696765737400000401106c6f67733c013c5665633c4469676573744974656d3e00003c000002400040102873705f72756e74696d651c67656e6572696318646967657374284469676573744974656d0001142850726552756e74696d650800440144436f6e73656e737573456e67696e654964000034011c5665633c75383e00060024436f6e73656e7375730800440144436f6e73656e737573456e67696e654964000034011c5665633c75383e000400105365616c0800440144436f6e73656e737573456e67696e654964000034011c5665633c75383e000500144f74686572040034011c5665633c75383e0000006452756e74696d65456e7669726f6e6d656e74557064617465640008000044000003040000000800480000024c004c08306672616d655f73797374656d2c4576656e745265636f7264080445015004540130000c011470686173652106011450686173650001146576656e7450010445000118746f706963735d0501185665633c543e00005008306f70616c5f72756e74696d653052756e74696d654576656e740001981853797374656d04005401706672616d655f73797374656d3a3a4576656e743c52756e74696d653e000000485374617465547269654d6967726174696f6e04007801ac70616c6c65745f73746174655f747269655f6d6967726174696f6e3a3a4576656e743c52756e74696d653e0001003c50617261636861696e53797374656d04008401bc63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d3a3a4576656e743c52756e74696d653e00140044436f6c6c61746f7253656c656374696f6e04008c01a470616c6c65745f636f6c6c61746f725f73656c656374696f6e3a3a4576656e743c52756e74696d653e0017001c53657373696f6e040090015470616c6c65745f73657373696f6e3a3a4576656e740018002042616c616e636573040094017c70616c6c65745f62616c616e6365733a3a4576656e743c52756e74696d653e001e00485472616e73616374696f6e5061796d656e7404009c01a870616c6c65745f7472616e73616374696f6e5f7061796d656e743a3a4576656e743c52756e74696d653e0021002054726561737572790400a0017c70616c6c65745f74726561737572793a3a4576656e743c52756e74696d653e002200105375646f0400a4016c70616c6c65745f7375646f3a3a4576656e743c52756e74696d653e0023001c56657374696e670400b401706f726d6c5f76657374696e673a3a4576656e743c52756e74696d653e0025001c58546f6b656e730400c001706f726d6c5f78746f6b656e733a3a4576656e743c52756e74696d653e00260018546f6b656e7304000901016c6f726d6c5f746f6b656e733a3a4576656e743c52756e74696d653e002700204964656e7469747904001501017c70616c6c65745f6964656e746974793a3a4576656e743c52756e74696d653e00280020507265696d61676504001901017c70616c6c65745f707265696d6167653a3a4576656e743c52756e74696d653e0029002444656d6f637261637904001d01018070616c6c65745f64656d6f63726163793a3a4576656e743c52756e74696d653e002a001c436f756e63696c0400310101fc70616c6c65745f636f6c6c6563746976653a3a4576656e743c52756e74696d652c2070616c6c65745f636f6c6c6563746976653a3a496e7374616e6365313e002b0048546563686e6963616c436f6d6d69747465650400390101fc70616c6c65745f636f6c6c6563746976653a3a4576656e743c52756e74696d652c2070616c6c65745f636f6c6c6563746976653a3a496e7374616e6365323e002c0044436f756e63696c4d656d6265727368697004003d0101fc70616c6c65745f6d656d626572736869703a3a4576656e743c52756e74696d652c2070616c6c65745f6d656d626572736869703a3a496e7374616e6365313e002d0070546563686e6963616c436f6d6d69747465654d656d626572736869700400410101fc70616c6c65745f6d656d626572736869703a3a4576656e743c52756e74696d652c2070616c6c65745f6d656d626572736869703a3a496e7374616e6365323e002e005046656c6c6f7773686970436f6c6c6563746976650400450101a070616c6c65745f72616e6b65645f636f6c6c6563746976653a3a4576656e743c52756e74696d653e002f004c46656c6c6f77736869705265666572656e646104005501018070616c6c65745f7265666572656e64613a3a4576656e743c52756e74696d653e003000245363686564756c65720400b905018070616c6c65745f7363686564756c65723a3a4576656e743c52756e74696d653e0031002458636d7051756575650400bd0501a463756d756c75735f70616c6c65745f78636d705f71756575653a3a4576656e743c52756e74696d653e0032002c506f6c6b61646f7458636d0400c105016870616c6c65745f78636d3a3a4576656e743c52756e74696d653e0033002843756d756c757358636d0400c905018863756d756c75735f70616c6c65745f78636d3a3a4576656e743c52756e74696d653e00340020446d7051756575650400cd0501a063756d756c75735f70616c6c65745f646d705f71756575653a3a4576656e743c52756e74696d653e00350034436f6e66696775726174696f6e0400d105019070616c6c65745f636f6e66696775726174696f6e3a3a4576656e743c52756e74696d653e003f0018436f6d6d6f6e0400d505017470616c6c65745f636f6d6d6f6e3a3a4576656e743c52756e74696d653e004200245374727563747572650400d905018070616c6c65745f7374727563747572653a3a4576656e743c52756e74696d653e0046003041707050726f6d6f74696f6e0400dd05019070616c6c65745f6170705f70726f6d6f74696f6e3a3a4576656e743c52756e74696d653e00490034466f726569676e4173736574730400e105019470616c6c65745f666f726569676e5f6173736574733a3a4576656e743c52756e74696d653e0050000c45564d0400e505016870616c6c65745f65766d3a3a4576656e743c52756e74696d653e00640020457468657265756d0400e905015870616c6c65745f657468657265756d3a3a4576656e740065004845766d436f6e747261637448656c7065727304000d0601ac70616c6c65745f65766d5f636f6e74726163745f68656c706572733a3a4576656e743c52756e74696d653e0097003045766d4d6967726174696f6e04001106019070616c6c65745f65766d5f6d6967726174696f6e3a3a4576656e743c52756e74696d653e0099002c4d61696e74656e616e636504001506018870616c6c65745f6d61696e74656e616e63653a3a4576656e743c52756e74696d653e009a001c5574696c69747904001906015470616c6c65745f7574696c6974793a3a4576656e74009c0024546573745574696c7304001d06018470616c6c65745f746573745f7574696c733a3a4576656e743c52756e74696d653e00ff0000540c306672616d655f73797374656d1870616c6c6574144576656e740404540001184045787472696e7369635375636365737304013464697370617463685f696e666f5801304469737061746368496e666f00000490416e2065787472696e73696320636f6d706c65746564207375636365737366756c6c792e3c45787472696e7369634661696c656408013864697370617463685f6572726f7264013444697370617463684572726f7200013464697370617463685f696e666f5801304469737061746368496e666f00010450416e2065787472696e736963206661696c65642e2c436f64655570646174656400020450603a636f6465602077617320757064617465642e284e65774163636f756e7404011c6163636f756e74000130543a3a4163636f756e7449640003046841206e6577206163636f756e742077617320637265617465642e344b696c6c65644163636f756e7404011c6163636f756e74000130543a3a4163636f756e74496400040458416e206163636f756e7420776173207265617065642e2052656d61726b656408011873656e646572000130543a3a4163636f756e7449640001106861736830011c543a3a48617368000504704f6e206f6e2d636861696e2072656d61726b2068617070656e65642e04704576656e7420666f72207468652053797374656d2070616c6c65742e580c346672616d655f737570706f7274206469737061746368304469737061746368496e666f00000c0118776569676874240118576569676874000114636c6173735c01344469737061746368436c617373000120706179735f6665656001105061797300005c0c346672616d655f737570706f7274206469737061746368344469737061746368436c61737300010c184e6f726d616c0000002c4f7065726174696f6e616c000100244d616e6461746f727900020000600c346672616d655f737570706f727420646973706174636810506179730001080c596573000000084e6f0001000064082873705f72756e74696d653444697370617463684572726f72000138144f746865720000003043616e6e6f744c6f6f6b7570000100244261644f726967696e000200184d6f64756c65040068012c4d6f64756c654572726f7200030044436f6e73756d657252656d61696e696e670004002c4e6f50726f76696465727300050040546f6f4d616e79436f6e73756d65727300060014546f6b656e04006c0128546f6b656e4572726f720007002841726974686d65746963040070013c41726974686d657469634572726f72000800345472616e73616374696f6e616c04007401485472616e73616374696f6e616c4572726f7200090024457868617573746564000a0028436f7272757074696f6e000b002c556e617661696c61626c65000c0038526f6f744e6f74416c6c6f776564000d000068082873705f72756e74696d652c4d6f64756c654572726f720000080114696e64657808010875380001146572726f7244018c5b75383b204d41585f4d4f44554c455f4552524f525f454e434f4445445f53495a455d00006c082873705f72756e74696d6528546f6b656e4572726f720001284046756e6473556e617661696c61626c65000000304f6e6c7950726f76696465720001003042656c6f774d696e696d756d0002003043616e6e6f7443726561746500030030556e6b6e6f776e41737365740004001846726f7a656e0005002c556e737570706f727465640006004043616e6e6f74437265617465486f6c64000700344e6f74457870656e6461626c650008001c426c6f636b65640009000070083473705f61726974686d657469633c41726974686d657469634572726f7200010c24556e646572666c6f77000000204f766572666c6f77000100384469766973696f6e42795a65726f0002000074082873705f72756e74696d65485472616e73616374696f6e616c4572726f72000108304c696d6974526561636865640000001c4e6f4c6179657200010000780c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c6574144576656e74040454000110204d696772617465640c010c746f7010010c7533320001146368696c6410010c75333200011c636f6d707574657c01404d6967726174696f6e436f6d707574650000083901476976656e206e756d626572206f66206028746f702c206368696c642960206b6579732077657265206d6967726174656420726573706563746976656c792c20776974682074686520676976656e2860636f6d70757465602e1c536c617368656408010c77686f000130543a3a4163636f756e744964000118616d6f756e7418013042616c616e63654f663c543e000104b4536f6d65206163636f756e7420676f7420736c61736865642062792074686520676976656e20616d6f756e742e544175746f4d6967726174696f6e46696e697368656400020484546865206175746f206d6967726174696f6e207461736b2066696e69736865642e1848616c7465640401146572726f728001204572726f723c543e000304ec4d6967726174696f6e20676f742068616c7465642064756520746f20616e206572726f72206f72206d6973732d636f6e66696775726174696f6e2e0470496e6e6572206576656e7473206f6620746869732070616c6c65742e7c0c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c6574404d6967726174696f6e436f6d70757465000108185369676e6564000000104175746f00010000800c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c6574144572726f720404540001183c4d61785369676e65644c696d697473000004804d6178207369676e6564206c696d697473206e6f74207265737065637465642e284b6579546f6f4c6f6e6700011cb441206b657920776173206c6f6e676572207468616e2074686520636f6e66696775726564206d6178696d756d2e00110154686973206d65616e73207468617420746865206d6967726174696f6e2068616c746564206174207468652063757272656e74205b6050726f6772657373605d20616e64010163616e20626520726573756d656420776974682061206c6172676572205b6063726174653a3a436f6e6669673a3a4d61784b65794c656e605d2076616c75652e21015265747279696e672077697468207468652073616d65205b6063726174653a3a436f6e6669673a3a4d61784b65794c656e605d2076616c75652077696c6c206e6f7420776f726b2e45015468652076616c75652073686f756c64206f6e6c7920626520696e6372656173656420746f2061766f696420612073746f72616765206d6967726174696f6e20666f72207468652063757272656e746c799073746f726564205b6063726174653a3a50726f67726573733a3a4c6173744b6579605d2e384e6f74456e6f75676846756e6473000204947375626d697474657220646f6573206e6f74206861766520656e6f7567682066756e64732e284261645769746e65737300030468426164207769746e65737320646174612070726f76696465642e645369676e65644d6967726174696f6e4e6f74416c6c6f77656400040425015369676e6564206d6967726174696f6e206973206e6f7420616c6c6f776564206265636175736520746865206d6178696d756d206c696d6974206973206e6f7420736574207965742e304261644368696c64526f6f7400050460426164206368696c6420726f6f742070726f76696465642e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e840c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d1870616c6c6574144576656e7404045400011c6056616c69646174696f6e46756e6374696f6e53746f726564000004d05468652076616c69646174696f6e2066756e6374696f6e20686173206265656e207363686564756c656420746f206170706c792e6456616c69646174696f6e46756e6374696f6e4170706c69656404015472656c61795f636861696e5f626c6f636b5f6e756d10015452656c6179436861696e426c6f636b4e756d62657200010445015468652076616c69646174696f6e2066756e6374696f6e20776173206170706c696564206173206f662074686520636f6e7461696e65642072656c617920636861696e20626c6f636b206e756d6265722e6c56616c69646174696f6e46756e6374696f6e446973636172646564000204b05468652072656c61792d636861696e2061626f727465642074686520757067726164652070726f636573732e4455706772616465417574686f72697a6564040124636f64655f6861736830011c543a3a486173680003047c416e207570677261646520686173206265656e20617574686f72697a65642e60446f776e776172644d657373616765735265636569766564040114636f756e7410010c7533320004040101536f6d6520646f776e77617264206d657373616765732068617665206265656e20726563656976656420616e642077696c6c2062652070726f6365737365642e64446f776e776172644d6573736167657350726f63657373656408012c7765696768745f75736564240118576569676874000120646d715f6865616430014472656c61795f636861696e3a3a48617368000504e0446f776e77617264206d6573736167657320776572652070726f636573736564207573696e672074686520676976656e207765696768742e445570776172644d65737361676553656e740401306d6573736167655f6861736888013c4f7074696f6e3c58636d486173683e000604b8416e20757077617264206d657373616765207761732073656e7420746f207468652072656c617920636861696e2e047c54686520604576656e746020656e756d206f6620746869732070616c6c65748804184f7074696f6e04045401040108104e6f6e6500000010536f6d6504000400000100008c0c6470616c6c65745f636f6c6c61746f725f73656c656374696f6e1870616c6c6574144576656e7404045400011844496e76756c6e657261626c654164646564040130696e76756c6e657261626c65000130543a3a4163636f756e7449640000004c496e76756c6e657261626c6552656d6f766564040130696e76756c6e657261626c65000130543a3a4163636f756e7449640001003c4c6963656e73654f627461696e65640801286163636f756e745f6964000130543a3a4163636f756e74496400011c6465706f73697418013042616c616e63654f663c543e0002003c4c6963656e736552656c65617365640801286163636f756e745f6964000130543a3a4163636f756e7449640001406465706f7369745f72657475726e656418013042616c616e63654f663c543e0003003843616e64696461746541646465640401286163636f756e745f6964000130543a3a4163636f756e7449640004004043616e64696461746552656d6f7665640401286163636f756e745f6964000130543a3a4163636f756e744964000500047c54686520604576656e746020656e756d206f6620746869732070616c6c6574900c3870616c6c65745f73657373696f6e1870616c6c6574144576656e74000104284e657753657373696f6e04013473657373696f6e5f696e64657810013053657373696f6e496e64657800000839014e65772073657373696f6e206861732068617070656e65642e204e6f746520746861742074686520617267756d656e74206973207468652073657373696f6e20696e6465782c206e6f74207468659c626c6f636b206e756d626572206173207468652074797065206d6967687420737567676573742e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574940c3c70616c6c65745f62616c616e6365731870616c6c6574144576656e740804540004490001541c456e646f77656408011c6163636f756e74000130543a3a4163636f756e744964000130667265655f62616c616e6365180128543a3a42616c616e6365000004b8416e206163636f756e74207761732063726561746564207769746820736f6d6520667265652062616c616e63652e20447573744c6f737408011c6163636f756e74000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e63650001083d01416e206163636f756e74207761732072656d6f7665642077686f73652062616c616e636520776173206e6f6e2d7a65726f206275742062656c6f77204578697374656e7469616c4465706f7369742c78726573756c74696e6720696e20616e206f75747269676874206c6f73732e205472616e736665720c011066726f6d000130543a3a4163636f756e744964000108746f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e63650002044c5472616e73666572207375636365656465642e2842616c616e636553657408010c77686f000130543a3a4163636f756e74496400011066726565180128543a3a42616c616e636500030468412062616c616e6365207761732073657420627920726f6f742e20526573657276656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000404e0536f6d652062616c616e63652077617320726573657276656420286d6f7665642066726f6d206672656520746f207265736572766564292e28556e726573657276656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000504e8536f6d652062616c616e63652077617320756e726573657276656420286d6f7665642066726f6d20726573657276656420746f2066726565292e4852657365727665526570617472696174656410011066726f6d000130543a3a4163636f756e744964000108746f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e636500014864657374696e6174696f6e5f7374617475739801185374617475730006084d01536f6d652062616c616e636520776173206d6f7665642066726f6d207468652072657365727665206f6620746865206669727374206163636f756e7420746f20746865207365636f6e64206163636f756e742ed846696e616c20617267756d656e7420696e64696361746573207468652064657374696e6174696f6e2062616c616e636520747970652e1c4465706f73697408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000704d8536f6d6520616d6f756e7420776173206465706f73697465642028652e672e20666f72207472616e73616374696f6e2066656573292e20576974686472617708010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e63650008041d01536f6d6520616d6f756e74207761732077697468647261776e2066726f6d20746865206163636f756e742028652e672e20666f72207472616e73616374696f6e2066656573292e1c536c617368656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e63650009040101536f6d6520616d6f756e74207761732072656d6f7665642066726f6d20746865206163636f756e742028652e672e20666f72206d69736265686176696f72292e184d696e74656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000a049c536f6d6520616d6f756e7420776173206d696e74656420696e746f20616e206163636f756e742e184275726e656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000b049c536f6d6520616d6f756e7420776173206275726e65642066726f6d20616e206163636f756e742e2453757370656e64656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000c041501536f6d6520616d6f756e74207761732073757370656e6465642066726f6d20616e206163636f756e74202869742063616e20626520726573746f726564206c61746572292e20526573746f72656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000d04a4536f6d6520616d6f756e742077617320726573746f72656420696e746f20616e206163636f756e742e20557067726164656404010c77686f000130543a3a4163636f756e744964000e0460416e206163636f756e74207761732075706772616465642e18497373756564040118616d6f756e74180128543a3a42616c616e6365000f042d01546f74616c2069737375616e63652077617320696e637265617365642062792060616d6f756e74602c206372656174696e6720612063726564697420746f2062652062616c616e6365642e2452657363696e646564040118616d6f756e74180128543a3a42616c616e63650010042501546f74616c2069737375616e636520776173206465637265617365642062792060616d6f756e74602c206372656174696e672061206465627420746f2062652062616c616e6365642e184c6f636b656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e636500110460536f6d652062616c616e636520776173206c6f636b65642e20556e6c6f636b656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e636500120468536f6d652062616c616e63652077617320756e6c6f636b65642e1846726f7a656e08010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e636500130460536f6d652062616c616e6365207761732066726f7a656e2e1854686177656408010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e636500140460536f6d652062616c616e636520776173207468617765642e047c54686520604576656e746020656e756d206f6620746869732070616c6c65749814346672616d655f737570706f72741874726169747318746f6b656e73106d6973633442616c616e63655374617475730001081046726565000000205265736572766564000100009c0c6870616c6c65745f7472616e73616374696f6e5f7061796d656e741870616c6c6574144576656e74040454000104485472616e73616374696f6e466565506169640c010c77686f000130543a3a4163636f756e74496400012861637475616c5f66656518013042616c616e63654f663c543e00010c74697018013042616c616e63654f663c543e000008590141207472616e73616374696f6e20666565206061637475616c5f666565602c206f662077686963682060746970602077617320616464656420746f20746865206d696e696d756d20696e636c7573696f6e206665652c5c686173206265656e2070616964206279206077686f602e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574a00c3c70616c6c65745f74726561737572791870616c6c6574144576656e740804540004490001242050726f706f73656404013870726f706f73616c5f696e64657810013450726f706f73616c496e646578000004344e65772070726f706f73616c2e205370656e64696e670401406275646765745f72656d61696e696e6718013c42616c616e63654f663c542c20493e000104e45765206861766520656e6465642061207370656e6420706572696f6420616e642077696c6c206e6f7720616c6c6f636174652066756e64732e1c417761726465640c013870726f706f73616c5f696e64657810013450726f706f73616c496e646578000114617761726418013c42616c616e63654f663c542c20493e00011c6163636f756e74000130543a3a4163636f756e7449640002047c536f6d652066756e64732068617665206265656e20616c6c6f63617465642e2052656a656374656408013870726f706f73616c5f696e64657810013450726f706f73616c496e64657800011c736c617368656418013c42616c616e63654f663c542c20493e000304b0412070726f706f73616c207761732072656a65637465643b2066756e6473207765726520736c61736865642e144275726e7404012c6275726e745f66756e647318013c42616c616e63654f663c542c20493e00040488536f6d65206f66206f75722066756e64732068617665206265656e206275726e742e20526f6c6c6f766572040140726f6c6c6f7665725f62616c616e636518013c42616c616e63654f663c542c20493e0005042d015370656e64696e67206861732066696e69736865643b20746869732069732074686520616d6f756e74207468617420726f6c6c73206f76657220756e74696c206e657874207370656e642e1c4465706f73697404011476616c756518013c42616c616e63654f663c542c20493e0006047c536f6d652066756e64732068617665206265656e206465706f73697465642e345370656e64417070726f7665640c013870726f706f73616c5f696e64657810013450726f706f73616c496e646578000118616d6f756e7418013c42616c616e63654f663c542c20493e00012c62656e6566696369617279000130543a3a4163636f756e7449640007049c41206e6577207370656e642070726f706f73616c20686173206265656e20617070726f7665642e3c55706461746564496e61637469766508012c726561637469766174656418013c42616c616e63654f663c542c20493e00012c646561637469766174656418013c42616c616e63654f663c542c20493e000804cc54686520696e6163746976652066756e6473206f66207468652070616c6c65742068617665206265656e20757064617465642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574a40c2c70616c6c65745f7375646f1870616c6c6574144576656e7404045400010c14537564696404012c7375646f5f726573756c74a801384469737061746368526573756c740000048841207375646f206a75737420746f6f6b20706c6163652e205c5b726573756c745c5d284b65794368616e6765640401286f6c645f7375646f6572b001504f7074696f6e3c543a3a4163636f756e7449643e0001043901546865205c5b7375646f65725c5d206a757374207377697463686564206964656e746974793b20746865206f6c64206b657920697320737570706c696564206966206f6e6520657869737465642e285375646f4173446f6e6504012c7375646f5f726573756c74a801384469737061746368526573756c740002048841207375646f206a75737420746f6f6b20706c6163652e205c5b726573756c745c5d047c54686520604576656e746020656e756d206f6620746869732070616c6c6574a80418526573756c7408045401ac044501640108084f6b0400ac000000000c4572720400640000010000ac0000040000b004184f7074696f6e04045401000108104e6f6e6500000010536f6d650400000000010000b40c306f726d6c5f76657374696e67186d6f64756c65144576656e7404045400010c5056657374696e675363686564756c6541646465640c011066726f6d000130543a3a4163636f756e744964000108746f000130543a3a4163636f756e74496400014076657374696e675f7363686564756c65b8015056657374696e675363686564756c654f663c543e0000046c4164646564206e65772076657374696e67207363686564756c652e1c436c61696d656408010c77686f000130543a3a4163636f756e744964000118616d6f756e7418013042616c616e63654f663c543e00010440436c61696d65642076657374696e672e5c56657374696e675363686564756c65735570646174656404010c77686f000130543a3a4163636f756e74496400020468557064617465642076657374696e67207363686564756c65732e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574b808306f726d6c5f76657374696e673c56657374696e675363686564756c65082c426c6f636b4e756d62657201101c42616c616e6365011800100114737461727410012c426c6f636b4e756d626572000118706572696f6410012c426c6f636b4e756d626572000130706572696f645f636f756e7410010c7533320001287065725f706572696f64bc011c42616c616e63650000bc0000061800c00c306f726d6c5f78746f6b656e73186d6f64756c65144576656e74040454000104585472616e736665727265644d756c746941737365747310011873656e646572000130543a3a4163636f756e744964000118617373657473c4012c4d756c746941737365747300010c666565cc01284d756c7469417373657400011064657374d401344d756c74694c6f636174696f6e000004885472616e7366657272656420604d756c74694173736574602077697468206665652e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574c4102c73746167696e675f78636d087633286d756c746961737365742c4d756c746941737365747300000400c8013c5665633c4d756c746941737365743e0000c8000002cc00cc102c73746167696e675f78636d087633286d756c74696173736574284d756c7469417373657400000801086964d0011c4173736574496400010c66756ef8012c46756e676962696c6974790000d0102c73746167696e675f78636d087633286d756c746961737365741c4173736574496400010820436f6e63726574650400d401344d756c74694c6f636174696f6e00000020416273747261637404000401205b75383b2033325d00010000d4102c73746167696e675f78636d087633346d756c74696c6f636174696f6e344d756c74694c6f636174696f6e000008011c706172656e74730801087538000120696e746572696f72d801244a756e6374696f6e730000d8102c73746167696e675f78636d087633246a756e6374696f6e73244a756e6374696f6e7300012410486572650000000858310400dc01204a756e6374696f6e0001000858320800dc01204a756e6374696f6e0000dc01204a756e6374696f6e0002000858330c00dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0003000858341000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0004000858351400dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0005000858361800dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0006000858371c00dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0007000858382000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e0000dc01204a756e6374696f6e00080000dc102c73746167696e675f78636d087633206a756e6374696f6e204a756e6374696f6e0001282450617261636861696e0400e0010c7533320000002c4163636f756e744964333208011c6e6574776f726be401444f7074696f6e3c4e6574776f726b49643e00010869640401205b75383b2033325d000100384163636f756e74496e646578363408011c6e6574776f726be401444f7074696f6e3c4e6574776f726b49643e000114696e64657828010c753634000200304163636f756e744b6579323008011c6e6574776f726be401444f7074696f6e3c4e6574776f726b49643e00010c6b6579ec01205b75383b2032305d0003003850616c6c6574496e7374616e6365040008010875380004003047656e6572616c496e6465780400bc0110753132380005002847656e6572616c4b65790801186c656e6774680801087538000110646174610401205b75383b2033325d000600244f6e6c794368696c6400070024506c7572616c6974790801086964f00118426f6479496400011070617274f40120426f6479506172740008003c476c6f62616c436f6e73656e7375730400e801244e6574776f726b496400090000e00000061000e404184f7074696f6e04045401e80108104e6f6e6500000010536f6d650400e80000010000e8102c73746167696e675f78636d087633206a756e6374696f6e244e6574776f726b496400012824427947656e6573697304000401205b75383b2033325d000000184279466f726b080130626c6f636b5f6e756d6265722c010c753634000128626c6f636b5f686173680401205b75383b2033325d00010020506f6c6b61646f74000200184b7573616d610003001c57657374656e6400040018526f636f636f00050018576f636f636f00060020457468657265756d040120636861696e5f696428010c7536340007002c426974636f696e436f72650008002c426974636f696e4361736800090000ec000003140000000800f0102c73746167696e675f78636d087633206a756e6374696f6e18426f6479496400012810556e69740000001c4d6f6e696b6572040044011c5b75383b20345d00010014496e6465780400e0010c7533320002002445786563757469766500030024546563686e6963616c0004002c4c656769736c6174697665000500204a7564696369616c0006001c446566656e73650007003841646d696e697374726174696f6e00080020547265617375727900090000f4102c73746167696e675f78636d087633206a756e6374696f6e20426f64795061727400011414566f6963650000001c4d656d62657273040114636f756e74e0010c753332000100204672616374696f6e08010c6e6f6de0010c75333200011464656e6f6de0010c7533320002004441744c6561737450726f706f7274696f6e08010c6e6f6de0010c75333200011464656e6f6de0010c753332000300484d6f72655468616e50726f706f7274696f6e08010c6e6f6de0010c75333200011464656e6f6de0010c75333200040000f8102c73746167696e675f78636d087633286d756c746961737365742c46756e676962696c6974790001082046756e6769626c650400bc0110753132380000002c4e6f6e46756e6769626c650400fc01344173736574496e7374616e636500010000fc102c73746167696e675f78636d087633286d756c74696173736574344173736574496e7374616e636500011824556e646566696e656400000014496e6465780400bc01107531323800010018417272617934040044011c5b75383b20345d0002001841727261793804000101011c5b75383b20385d0003001c417272617931360400050101205b75383b2031365d0004001c4172726179333204000401205b75383b2033325d000500000101000003080000000800050100000310000000080009010c2c6f726d6c5f746f6b656e73186d6f64756c65144576656e740404540001441c456e646f7765640c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000004b8416e206163636f756e74207761732063726561746564207769746820736f6d6520667265652062616c616e63652e20447573744c6f73740c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000108ec416e206163636f756e74207761732072656d6f7665642077686f73652062616c616e636520776173206e6f6e2d7a65726f206275742062656c6f77c84578697374656e7469616c4465706f7369742c20726573756c74696e6720696e20616e206f75747269676874206c6f73732e205472616e7366657210012c63757272656e63795f69640d010134543a3a43757272656e6379496400011066726f6d000130543a3a4163636f756e744964000108746f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e63650002044c5472616e73666572207375636365656465642e2052657365727665640c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000304e0536f6d652062616c616e63652077617320726573657276656420286d6f7665642066726f6d206672656520746f207265736572766564292e28556e72657365727665640c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000404e8536f6d652062616c616e63652077617320756e726573657276656420286d6f7665642066726f6d20726573657276656420746f2066726565292e4852657365727665526570617472696174656414012c63757272656e63795f69640d010134543a3a43757272656e6379496400011066726f6d000130543a3a4163636f756e744964000108746f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e636500011873746174757398013442616c616e6365537461747573000508f4536f6d652072657365727665642062616c616e63652077617320726570617472696174656420286d6f7665642066726f6d20726573657276656420746f44616e6f74686572206163636f756e74292e2842616c616e636553657410012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e74496400011066726565180128543a3a42616c616e63650001207265736572766564180128543a3a42616c616e636500060468412062616c616e6365207761732073657420627920726f6f742e40546f74616c49737375616e636553657408012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74180128543a3a42616c616e6365000704b854686520746f74616c2069737375616e6365206f6620616e2063757272656e637920686173206265656e207365742457697468647261776e0c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000804ec536f6d652062616c616e63657320776572652077697468647261776e2028652e672e2070617920666f72207472616e73616374696f6e20666565291c536c617368656410012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e74496400012c667265655f616d6f756e74180128543a3a42616c616e636500013c72657365727665645f616d6f756e74180128543a3a42616c616e6365000904d4536f6d652062616c616e636573207765726520736c61736865642028652e672e2064756520746f206d69732d6265686176696f7229244465706f73697465640c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000a04984465706f736974656420736f6d652062616c616e636520696e746f20616e206163636f756e741c4c6f636b53657410011c6c6f636b5f6964010101384c6f636b4964656e74696669657200012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000b0454536f6d652066756e647320617265206c6f636b65642c4c6f636b52656d6f7665640c011c6c6f636b5f6964010101384c6f636b4964656e74696669657200012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000c047c536f6d65206c6f636b65642066756e6473207765726520756e6c6f636b6564184c6f636b65640c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000d0474536f6d6520667265652062616c616e636520776173206c6f636b65642e20556e6c6f636b65640c012c63757272656e63795f69640d010134543a3a43757272656e6379496400010c77686f000130543a3a4163636f756e744964000118616d6f756e74180128543a3a42616c616e6365000e0478536f6d65206c6f636b65642062616c616e6365207761732066726565642e1849737375656408012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74180128543a3a42616c616e6365000f002452657363696e64656408012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74180128543a3a42616c616e6365001000047c54686520604576656e746020656e756d206f6620746869732070616c6c65740d01085470616c6c65745f666f726569676e5f6173736574731c4173736574496400010838466f726569676e417373657449640400100138466f726569676e41737365744964000000344e6174697665417373657449640400110101384e617469766543757272656e6379000100001101085470616c6c65745f666f726569676e5f617373657473384e617469766543757272656e6379000108104865726500000018506172656e740001000015010c3c70616c6c65745f6964656e746974791870616c6c6574144576656e740404540001342c4964656e7469747953657404010c77686f000130543a3a4163636f756e744964000004ec41206e616d652077617320736574206f72207265736574202877686963682077696c6c2072656d6f766520616c6c206a756467656d656e7473292e3c4964656e74697479436c656172656408010c77686f000130543a3a4163636f756e74496400011c6465706f73697418013042616c616e63654f663c543e000104cc41206e616d652077617320636c65617265642c20616e642074686520676976656e2062616c616e63652072657475726e65642e384964656e746974794b696c6c656408010c77686f000130543a3a4163636f756e74496400011c6465706f73697418013042616c616e63654f663c543e000204c441206e616d65207761732072656d6f76656420616e642074686520676976656e2062616c616e636520736c61736865642e484964656e746974696573496e736572746564040118616d6f756e7410010c753332000304090141206e756d626572206f66206964656e74697469657320616e64206173736f63696174656420696e666f207765726520666f726369626c7920696e7365727465642e444964656e74697469657352656d6f766564040118616d6f756e7410010c753332000404150141206e756d626572206f66206964656e74697469657320616e6420616c6c206173736f63696174656420696e666f207765726520666f726369626c792072656d6f7665642e484a756467656d656e7452657175657374656408010c77686f000130543a3a4163636f756e74496400013c7265676973747261725f696e646578100138526567697374726172496e6465780005049c41206a756467656d656e74207761732061736b65642066726f6d2061207265676973747261722e504a756467656d656e74556e72657175657374656408010c77686f000130543a3a4163636f756e74496400013c7265676973747261725f696e646578100138526567697374726172496e6465780006048841206a756467656d656e74207265717565737420776173207265747261637465642e384a756467656d656e74476976656e080118746172676574000130543a3a4163636f756e74496400013c7265676973747261725f696e646578100138526567697374726172496e6465780007049441206a756467656d656e742077617320676976656e2062792061207265676973747261722e38526567697374726172416464656404013c7265676973747261725f696e646578100138526567697374726172496e646578000804584120726567697374726172207761732061646465642e405375624964656e7469747941646465640c010c737562000130543a3a4163636f756e7449640001106d61696e000130543a3a4163636f756e74496400011c6465706f73697418013042616c616e63654f663c543e000904f441207375622d6964656e746974792077617320616464656420746f20616e206964656e7469747920616e6420746865206465706f73697420706169642e485375624964656e7469747952656d6f7665640c010c737562000130543a3a4163636f756e7449640001106d61696e000130543a3a4163636f756e74496400011c6465706f73697418013042616c616e63654f663c543e000a04090141207375622d6964656e74697479207761732072656d6f7665642066726f6d20616e206964656e7469747920616e6420746865206465706f7369742066726565642e485375624964656e746974795265766f6b65640c010c737562000130543a3a4163636f756e7449640001106d61696e000130543a3a4163636f756e74496400011c6465706f73697418013042616c616e63654f663c543e000b08190141207375622d6964656e746974792077617320636c65617265642c20616e642074686520676976656e206465706f7369742072657061747269617465642066726f6d20746865c86d61696e206964656e74697479206163636f756e7420746f20746865207375622d6964656e74697479206163636f756e742e545375624964656e746974696573496e736572746564040118616d6f756e7410010c753332000c04150141206e756d626572206f66206964656e746974696573207765726520666f726369626c7920757064617465642077697468206e6577207375622d6964656e7469746965732e047c54686520604576656e746020656e756d206f6620746869732070616c6c657419010c3c70616c6c65745f707265696d6167651870616c6c6574144576656e7404045400010c144e6f7465640401106861736830011c543a3a48617368000004684120707265696d61676520686173206265656e206e6f7465642e245265717565737465640401106861736830011c543a3a48617368000104784120707265696d61676520686173206265656e207265717565737465642e1c436c65617265640401106861736830011c543a3a486173680002046c4120707265696d616765206861732062656e20636c65617265642e047c54686520604576656e746020656e756d206f6620746869732070616c6c65741d010c4070616c6c65745f64656d6f63726163791870616c6c6574144576656e740404540001442050726f706f73656408013870726f706f73616c5f696e64657810012450726f70496e64657800011c6465706f73697418013042616c616e63654f663c543e000004bc41206d6f74696f6e20686173206265656e2070726f706f7365642062792061207075626c6963206163636f756e742e185461626c656408013870726f706f73616c5f696e64657810012450726f70496e64657800011c6465706f73697418013042616c616e63654f663c543e000104d841207075626c69632070726f706f73616c20686173206265656e207461626c656420666f72207265666572656e64756d20766f74652e3845787465726e616c5461626c656400020494416e2065787465726e616c2070726f706f73616c20686173206265656e207461626c65642e1c537461727465640801247265665f696e64657810013c5265666572656e64756d496e6465780001247468726573686f6c6421010134566f74655468726573686f6c640003045c41207265666572656e64756d2068617320626567756e2e185061737365640401247265665f696e64657810013c5265666572656e64756d496e646578000404ac412070726f706f73616c20686173206265656e20617070726f766564206279207265666572656e64756d2e244e6f745061737365640401247265665f696e64657810013c5265666572656e64756d496e646578000504ac412070726f706f73616c20686173206265656e2072656a6563746564206279207265666572656e64756d2e2443616e63656c6c65640401247265665f696e64657810013c5265666572656e64756d496e6465780006048041207265666572656e64756d20686173206265656e2063616e63656c6c65642e2444656c65676174656408010c77686f000130543a3a4163636f756e744964000118746172676574000130543a3a4163636f756e744964000704dc416e206163636f756e74206861732064656c65676174656420746865697220766f746520746f20616e6f74686572206163636f756e742e2c556e64656c65676174656404011c6163636f756e74000130543a3a4163636f756e744964000804e4416e206163636f756e74206861732063616e63656c6c656420612070726576696f75732064656c65676174696f6e206f7065726174696f6e2e185665746f65640c010c77686f000130543a3a4163636f756e74496400013470726f706f73616c5f6861736830011048323536000114756e74696c100144426c6f636b4e756d626572466f723c543e00090494416e2065787465726e616c2070726f706f73616c20686173206265656e207665746f65642e2c426c61636b6c697374656404013470726f706f73616c5f6861736830011048323536000a04c4412070726f706f73616c5f6861736820686173206265656e20626c61636b6c6973746564207065726d616e656e746c792e14566f7465640c0114766f746572000130543a3a4163636f756e7449640001247265665f696e64657810013c5265666572656e64756d496e646578000110766f7465250101644163636f756e74566f74653c42616c616e63654f663c543e3e000b0490416e206163636f756e742068617320766f74656420696e2061207265666572656e64756d205365636f6e6465640801207365636f6e646572000130543a3a4163636f756e74496400012870726f705f696e64657810012450726f70496e646578000c048c416e206163636f756e742068617320736563636f6e64656420612070726f706f73616c4050726f706f73616c43616e63656c656404012870726f705f696e64657810012450726f70496e646578000d0460412070726f706f73616c20676f742063616e63656c65642e2c4d657461646174615365740801146f776e65722d0101344d657461646174614f776e6572043c4d65746164617461206f776e65722e011068617368300130507265696d616765486173680438507265696d61676520686173682e0e04d44d6574616461746120666f7220612070726f706f73616c206f722061207265666572656e64756d20686173206265656e207365742e3c4d65746164617461436c65617265640801146f776e65722d0101344d657461646174614f776e6572043c4d65746164617461206f776e65722e011068617368300130507265696d616765486173680438507265696d61676520686173682e0f04e44d6574616461746120666f7220612070726f706f73616c206f722061207265666572656e64756d20686173206265656e20636c65617265642e4c4d657461646174615472616e736665727265640c0128707265765f6f776e65722d0101344d657461646174614f776e6572046050726576696f7573206d65746164617461206f776e65722e01146f776e65722d0101344d657461646174614f776e6572044c4e6577206d65746164617461206f776e65722e011068617368300130507265696d616765486173680438507265696d61676520686173682e1004ac4d6574616461746120686173206265656e207472616e7366657272656420746f206e6577206f776e65722e047c54686520604576656e746020656e756d206f6620746869732070616c6c657421010c4070616c6c65745f64656d6f637261637938766f74655f7468726573686f6c6434566f74655468726573686f6c6400010c5053757065724d616a6f72697479417070726f76650000005053757065724d616a6f72697479416761696e73740001003853696d706c654d616a6f726974790002000025010c4070616c6c65745f64656d6f637261637910766f74652c4163636f756e74566f7465041c42616c616e636501180108205374616e64617264080110766f746529010110566f746500011c62616c616e636518011c42616c616e63650000001453706c697408010c61796518011c42616c616e636500010c6e617918011c42616c616e63650001000029010c4070616c6c65745f64656d6f637261637910766f746510566f746500000400080000002d010c4070616c6c65745f64656d6f6372616379147479706573344d657461646174614f776e657200010c2045787465726e616c0000002050726f706f73616c040010012450726f70496e646578000100285265666572656e64756d040010013c5265666572656e64756d496e6465780002000031010c4470616c6c65745f636f6c6c6563746976651870616c6c6574144576656e7408045400044900011c2050726f706f73656410011c6163636f756e74000130543a3a4163636f756e74496400013870726f706f73616c5f696e64657810013450726f706f73616c496e64657800013470726f706f73616c5f6861736830011c543a3a486173680001247468726573686f6c6410012c4d656d626572436f756e74000008490141206d6f74696f6e2028676976656e20686173682920686173206265656e2070726f706f7365642028627920676976656e206163636f756e742920776974682061207468726573686f6c642028676976656e3c604d656d626572436f756e7460292e14566f74656414011c6163636f756e74000130543a3a4163636f756e74496400013470726f706f73616c5f6861736830011c543a3a48617368000114766f74656435010110626f6f6c00010c79657310012c4d656d626572436f756e740001086e6f10012c4d656d626572436f756e74000108050141206d6f74696f6e2028676976656e20686173682920686173206265656e20766f746564206f6e20627920676976656e206163636f756e742c206c656176696e671501612074616c6c79202879657320766f74657320616e64206e6f20766f74657320676976656e20726573706563746976656c7920617320604d656d626572436f756e7460292e20417070726f76656404013470726f706f73616c5f6861736830011c543a3a48617368000204c041206d6f74696f6e2077617320617070726f76656420627920746865207265717569726564207468726573686f6c642e2c446973617070726f76656404013470726f706f73616c5f6861736830011c543a3a48617368000304d041206d6f74696f6e20776173206e6f7420617070726f76656420627920746865207265717569726564207468726573686f6c642e20457865637574656408013470726f706f73616c5f6861736830011c543a3a48617368000118726573756c74a801384469737061746368526573756c74000404210141206d6f74696f6e207761732065786563757465643b20726573756c742077696c6c20626520604f6b602069662069742072657475726e656420776974686f7574206572726f722e384d656d626572457865637574656408013470726f706f73616c5f6861736830011c543a3a48617368000118726573756c74a801384469737061746368526573756c740005044901412073696e676c65206d656d6265722064696420736f6d6520616374696f6e3b20726573756c742077696c6c20626520604f6b602069662069742072657475726e656420776974686f7574206572726f722e18436c6f7365640c013470726f706f73616c5f6861736830011c543a3a4861736800010c79657310012c4d656d626572436f756e740001086e6f10012c4d656d626572436f756e740006045501412070726f706f73616c2077617320636c6f736564206265636175736520697473207468726573686f6c64207761732072656163686564206f7220616674657220697473206475726174696f6e207761732075702e047c54686520604576656e746020656e756d206f6620746869732070616c6c65743501000005000039010c4470616c6c65745f636f6c6c6563746976651870616c6c6574144576656e7408045400044900011c2050726f706f73656410011c6163636f756e74000130543a3a4163636f756e74496400013870726f706f73616c5f696e64657810013450726f706f73616c496e64657800013470726f706f73616c5f6861736830011c543a3a486173680001247468726573686f6c6410012c4d656d626572436f756e74000008490141206d6f74696f6e2028676976656e20686173682920686173206265656e2070726f706f7365642028627920676976656e206163636f756e742920776974682061207468726573686f6c642028676976656e3c604d656d626572436f756e7460292e14566f74656414011c6163636f756e74000130543a3a4163636f756e74496400013470726f706f73616c5f6861736830011c543a3a48617368000114766f74656435010110626f6f6c00010c79657310012c4d656d626572436f756e740001086e6f10012c4d656d626572436f756e74000108050141206d6f74696f6e2028676976656e20686173682920686173206265656e20766f746564206f6e20627920676976656e206163636f756e742c206c656176696e671501612074616c6c79202879657320766f74657320616e64206e6f20766f74657320676976656e20726573706563746976656c7920617320604d656d626572436f756e7460292e20417070726f76656404013470726f706f73616c5f6861736830011c543a3a48617368000204c041206d6f74696f6e2077617320617070726f76656420627920746865207265717569726564207468726573686f6c642e2c446973617070726f76656404013470726f706f73616c5f6861736830011c543a3a48617368000304d041206d6f74696f6e20776173206e6f7420617070726f76656420627920746865207265717569726564207468726573686f6c642e20457865637574656408013470726f706f73616c5f6861736830011c543a3a48617368000118726573756c74a801384469737061746368526573756c74000404210141206d6f74696f6e207761732065786563757465643b20726573756c742077696c6c20626520604f6b602069662069742072657475726e656420776974686f7574206572726f722e384d656d626572457865637574656408013470726f706f73616c5f6861736830011c543a3a48617368000118726573756c74a801384469737061746368526573756c740005044901412073696e676c65206d656d6265722064696420736f6d6520616374696f6e3b20726573756c742077696c6c20626520604f6b602069662069742072657475726e656420776974686f7574206572726f722e18436c6f7365640c013470726f706f73616c5f6861736830011c543a3a4861736800010c79657310012c4d656d626572436f756e740001086e6f10012c4d656d626572436f756e740006045501412070726f706f73616c2077617320636c6f736564206265636175736520697473207468726573686f6c64207761732072656163686564206f7220616674657220697473206475726174696f6e207761732075702e047c54686520604576656e746020656e756d206f6620746869732070616c6c65743d010c4470616c6c65745f6d656d626572736869701870616c6c6574144576656e740804540004490001182c4d656d6265724164646564000004e054686520676976656e206d656d626572207761732061646465643b2073656520746865207472616e73616374696f6e20666f722077686f2e344d656d62657252656d6f766564000104e854686520676976656e206d656d626572207761732072656d6f7665643b2073656520746865207472616e73616374696f6e20666f722077686f2e384d656d6265727353776170706564000204d854776f206d656d62657273207765726520737761707065643b2073656520746865207472616e73616374696f6e20666f722077686f2e304d656d6265727352657365740003041501546865206d656d62657273686970207761732072657365743b2073656520746865207472616e73616374696f6e20666f722077686f20746865206e6577207365742069732e284b65794368616e676564000404844f6e65206f6620746865206d656d6265727327206b657973206368616e6765642e1444756d6d790005046c5068616e746f6d206d656d6265722c206e6576657220757365642e047c54686520604576656e746020656e756d206f6620746869732070616c6c657441010c4470616c6c65745f6d656d626572736869701870616c6c6574144576656e740804540004490001182c4d656d6265724164646564000004e054686520676976656e206d656d626572207761732061646465643b2073656520746865207472616e73616374696f6e20666f722077686f2e344d656d62657252656d6f766564000104e854686520676976656e206d656d626572207761732072656d6f7665643b2073656520746865207472616e73616374696f6e20666f722077686f2e384d656d6265727353776170706564000204d854776f206d656d62657273207765726520737761707065643b2073656520746865207472616e73616374696f6e20666f722077686f2e304d656d6265727352657365740003041501546865206d656d62657273686970207761732072657365743b2073656520746865207472616e73616374696f6e20666f722077686f20746865206e6577207365742069732e284b65794368616e676564000404844f6e65206f6620746865206d656d6265727327206b657973206368616e6765642e1444756d6d790005046c5068616e746f6d206d656d6265722c206e6576657220757365642e047c54686520604576656e746020656e756d206f6620746869732070616c6c657445010c6070616c6c65745f72616e6b65645f636f6c6c6563746976651870616c6c6574144576656e740804540004490001102c4d656d626572416464656404010c77686f000130543a3a4163636f756e7449640000047841206d656d626572206077686f6020686173206265656e2061646465642e2c52616e6b4368616e67656408010c77686f000130543a3a4163636f756e74496400011072616e6b4901011052616e6b000104f4546865206d656d626572206077686f6073652072616e6b20686173206265656e206368616e67656420746f2074686520676976656e206072616e6b602e344d656d62657252656d6f76656408010c77686f000130543a3a4163636f756e74496400011072616e6b4901011052616e6b0002041901546865206d656d626572206077686f60206f6620676976656e206072616e6b6020686173206265656e2072656d6f7665642066726f6d2074686520636f6c6c6563746976652e14566f74656410010c77686f000130543a3a4163636f756e744964000110706f6c6c100144506f6c6c496e6465784f663c542c20493e000110766f74654d010128566f74655265636f726400011474616c6c795101013454616c6c794f663c542c20493e0003085501546865206d656d626572206077686f602068617320766f74656420666f72207468652060706f6c6c6020776974682074686520676976656e2060766f746560206c656164696e6720746f20616e2075706461746564206074616c6c79602e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574490100000504004d01086070616c6c65745f72616e6b65645f636f6c6c65637469766528566f74655265636f72640001080c4179650400100114566f7465730000000c4e61790400100114566f746573000100005101086070616c6c65745f72616e6b65645f636f6c6c6563746976651454616c6c790c045400044900044d00000c0124626172655f6179657310012c4d656d626572496e64657800011061796573100114566f7465730001106e617973100114566f746573000055010c4070616c6c65745f7265666572656e64611870616c6c6574144576656e74080454000449000140245375626d69747465640c0114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e0114747261636b4901013c547261636b49644f663c542c20493e04250154686520747261636b2028616e6420627920657874656e73696f6e2070726f706f73616c206469737061746368206f726967696e29206f662074686973207265666572656e64756d2e012070726f706f73616c5901014c426f756e64656443616c6c4f663c542c20493e04805468652070726f706f73616c20666f7220746865207265666572656e64756d2e00048041207265666572656e64756d20686173206265656e207375626d69747465642e544465636973696f6e4465706f736974506c616365640c0114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e010c77686f000130543a3a4163636f756e744964048c546865206163636f756e742077686f20706c6163656420746865206465706f7369742e0118616d6f756e7418013c42616c616e63654f663c542c20493e048454686520616d6f756e7420706c6163656420627920746865206163636f756e742e010494546865206465636973696f6e206465706f73697420686173206265656e20706c616365642e5c4465636973696f6e4465706f736974526566756e6465640c0114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e010c77686f000130543a3a4163636f756e744964048c546865206163636f756e742077686f20706c6163656420746865206465706f7369742e0118616d6f756e7418013c42616c616e63654f663c542c20493e048454686520616d6f756e7420706c6163656420627920746865206163636f756e742e02049c546865206465636973696f6e206465706f73697420686173206265656e20726566756e6465642e384465706f736974536c617368656408010c77686f000130543a3a4163636f756e744964048c546865206163636f756e742077686f20706c6163656420746865206465706f7369742e0118616d6f756e7418013c42616c616e63654f663c542c20493e048454686520616d6f756e7420706c6163656420627920746865206163636f756e742e03047041206465706f73697420686173206265656e20736c6173686165642e3c4465636973696f6e53746172746564100114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e0114747261636b4901013c547261636b49644f663c542c20493e04250154686520747261636b2028616e6420627920657874656e73696f6e2070726f706f73616c206469737061746368206f726967696e29206f662074686973207265666572656e64756d2e012070726f706f73616c5901014c426f756e64656443616c6c4f663c542c20493e04805468652070726f706f73616c20666f7220746865207265666572656e64756d2e011474616c6c7951010120543a3a54616c6c7904b85468652063757272656e742074616c6c79206f6620766f74657320696e2074686973207265666572656e64756d2e0404bc41207265666572656e64756d20686173206d6f76656420696e746f20746865206465636964696e672070686173652e38436f6e6669726d53746172746564040114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e050038436f6e6669726d41626f72746564040114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e060024436f6e6669726d6564080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011474616c6c7951010120543a3a54616c6c7904b05468652066696e616c2074616c6c79206f6620766f74657320696e2074686973207265666572656e64756d2e0704210141207265666572656e64756d2068617320656e6465642069747320636f6e6669726d6174696f6e20706861736520616e6420697320726561647920666f7220617070726f76616c2e20417070726f766564040114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e08040d0141207265666572656e64756d20686173206265656e20617070726f76656420616e64206974732070726f706f73616c20686173206265656e207363686564756c65642e2052656a6563746564080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011474616c6c7951010120543a3a54616c6c7904b05468652066696e616c2074616c6c79206f6620766f74657320696e2074686973207265666572656e64756d2e0904ac412070726f706f73616c20686173206265656e2072656a6563746564206279207265666572656e64756d2e2054696d65644f7574080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011474616c6c7951010120543a3a54616c6c7904b05468652066696e616c2074616c6c79206f6620766f74657320696e2074686973207265666572656e64756d2e0a04d841207265666572656e64756d20686173206265656e2074696d6564206f757420776974686f7574206265696e6720646563696465642e2443616e63656c6c6564080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011474616c6c7951010120543a3a54616c6c7904b05468652066696e616c2074616c6c79206f6620766f74657320696e2074686973207265666572656e64756d2e0b048041207265666572656e64756d20686173206265656e2063616e63656c6c65642e184b696c6c6564080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011474616c6c7951010120543a3a54616c6c7904b05468652066696e616c2074616c6c79206f6620766f74657320696e2074686973207265666572656e64756d2e0c047441207265666572656e64756d20686173206265656e206b696c6c65642e645375626d697373696f6e4465706f736974526566756e6465640c0114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e010c77686f000130543a3a4163636f756e744964048c546865206163636f756e742077686f20706c6163656420746865206465706f7369742e0118616d6f756e7418013c42616c616e63654f663c542c20493e048454686520616d6f756e7420706c6163656420627920746865206163636f756e742e0d04a4546865207375626d697373696f6e206465706f73697420686173206265656e20726566756e6465642e2c4d65746164617461536574080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011068617368300130507265696d616765486173680438507265696d61676520686173682e0e049c4d6574616461746120666f722061207265666572656e64756d20686173206265656e207365742e3c4d65746164617461436c6561726564080114696e64657810013c5265666572656e64756d496e6465780460496e646578206f6620746865207265666572656e64756d2e011068617368300130507265696d616765486173680438507265696d61676520686173682e0f04ac4d6574616461746120666f722061207265666572656e64756d20686173206265656e20636c65617265642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574590110346672616d655f737570706f72741874726169747324707265696d616765731c426f756e646564040454015d01010c184c6567616379040110686173683001104861736800000018496e6c696e650400b5050134426f756e646564496e6c696e65000100184c6f6f6b7570080110686173683001104861736800010c6c656e10010c753332000200005d0108306f70616c5f72756e74696d652c52756e74696d6543616c6c0001a01853797374656d0400610101ad0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c53797374656d2c2052756e74696d653e000000485374617465547269654d6967726174696f6e0400710101dd0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c5374617465547269654d6967726174696f6e2c2052756e74696d653e0001003c50617261636861696e53797374656d0400890101d10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c50617261636861696e53797374656d2c2052756e74696d653e0014003450617261636861696e496e666f0400c10101c90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c50617261636861696e496e666f2c2052756e74696d653e00150044436f6c6c61746f7253656c656374696f6e0400c50101d90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c436f6c6c61746f7253656c656374696f6e2c2052756e74696d653e0017001c53657373696f6e0400c90101b10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c53657373696f6e2c2052756e74696d653e0018002042616c616e6365730400d90101b50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c42616c616e6365732c2052756e74696d653e001e002454696d657374616d700400e90101b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c54696d657374616d702c2052756e74696d653e0020002054726561737572790400ed0101b50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c54726561737572792c2052756e74696d653e002200105375646f0400f10101a50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c5375646f2c2052756e74696d653e0023001c56657374696e670400f50101b10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c56657374696e672c2052756e74696d653e0025001c58546f6b656e730400fd0101b10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c58546f6b656e732c2052756e74696d653e00260018546f6b656e7304004d0201ad0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c546f6b656e732c2052756e74696d653e002700204964656e746974790400510201b50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c4964656e746974792c2052756e74696d653e00280020507265696d6167650400190301b50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c507265696d6167652c2052756e74696d653e0029002444656d6f637261637904001d0301b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c44656d6f63726163792c2052756e74696d653e002a001c436f756e63696c04002d0301b10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c436f756e63696c2c2052756e74696d653e002b0048546563686e6963616c436f6d6d69747465650400310301dd0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c546563686e6963616c436f6d6d69747465652c2052756e74696d653e002c0044436f756e63696c4d656d626572736869700400350301d90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c436f756e63696c4d656d626572736869702c2052756e74696d653e002d0070546563686e6963616c436f6d6d69747465654d656d626572736869700400390301050273656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c546563686e6963616c436f6d6d69747465654d656d626572736869702c2052756e74696d653e002e005046656c6c6f7773686970436f6c6c65637469766504003d0301e50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c46656c6c6f7773686970436f6c6c6563746976652c2052756e74696d653e002f004c46656c6c6f77736869705265666572656e64610400410301e10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c46656c6c6f77736869705265666572656e64612c2052756e74696d653e003000245363686564756c65720400710301b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c5363686564756c65722c2052756e74696d653e0031002458636d70517565756504007d0301b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c58636d7051756575652c2052756e74696d653e0032002c506f6c6b61646f7458636d0400810301c10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c506f6c6b61646f7458636d2c2052756e74696d653e0033002843756d756c757358636d0400250401bd0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c43756d756c757358636d2c2052756e74696d653e00340020446d7051756575650400290401b50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c446d7051756575652c2052756e74696d653e00350024496e666c6174696f6e04002d0401b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c496e666c6174696f6e2c2052756e74696d653e003c0018556e697175650400310401ad0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c556e697175652c2052756e74696d653e003d0034436f6e66696775726174696f6e04000d0501c90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c436f6e66696775726174696f6e2c2052756e74696d653e003f00245374727563747572650400290501b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c5374727563747572652c2052756e74696d653e0046003041707050726f6d6f74696f6e04002d0501c50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c41707050726f6d6f74696f6e2c2052756e74696d653e00490034466f726569676e4173736574730400350501c90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c466f726569676e4173736574732c2052756e74696d653e0050000c45564d0400450501a10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c45564d2c2052756e74696d653e00640020457468657265756d0400610501b50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c457468657265756d2c2052756e74696d653e0065004845766d436f6e747261637448656c706572730400890501dd0173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c45766d436f6e747261637448656c706572732c2052756e74696d653e0097003045766d4d6967726174696f6e0400910501c50173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c45766d4d6967726174696f6e2c2052756e74696d653e0099002c4d61696e74656e616e63650400a50501c10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c4d61696e74656e616e63652c2052756e74696d653e009a001c5574696c6974790400a90501b10173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c5574696c6974792c2052756e74696d653e009c0024546573745574696c730400b10501b90173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c546573745574696c732c2052756e74696d653e00ff000061010c306672616d655f73797374656d1870616c6c65741043616c6c0404540001201872656d61726b04011872656d61726b34011c5665633c75383e0000045c536565205b6050616c6c65743a3a72656d61726b605d2e387365745f686561705f706167657304011470616765732c010c7536340001047c536565205b6050616c6c65743a3a7365745f686561705f7061676573605d2e207365745f636f6465040110636f646534011c5665633c75383e00020464536565205b6050616c6c65743a3a7365745f636f6465605d2e5c7365745f636f64655f776974686f75745f636865636b73040110636f646534011c5665633c75383e000304a0536565205b6050616c6c65743a3a7365745f636f64655f776974686f75745f636865636b73605d2e2c7365745f73746f726167650401146974656d73650101345665633c4b657956616c75653e00040470536565205b6050616c6c65743a3a7365745f73746f72616765605d2e306b696c6c5f73746f726167650401106b6579736d0101205665633c4b65793e00050474536565205b6050616c6c65743a3a6b696c6c5f73746f72616765605d2e2c6b696c6c5f70726566697808011870726566697834010c4b657900011c7375626b65797310010c75333200060470536565205b6050616c6c65743a3a6b696c6c5f707265666978605d2e4472656d61726b5f776974685f6576656e7404011872656d61726b34011c5665633c75383e00070488536565205b6050616c6c65743a3a72656d61726b5f776974685f6576656e74605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e65010000026901006901000004083434006d01000002340071010c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c65741043616c6c04045400011858636f6e74726f6c5f6175746f5f6d6967726174696f6e0401306d617962655f636f6e6669677501015c4f7074696f6e3c4d6967726174696f6e4c696d6974733e0000049c536565205b6050616c6c65743a3a636f6e74726f6c5f6175746f5f6d6967726174696f6e605d2e40636f6e74696e75655f6d6967726174650c01186c696d6974737901013c4d6967726174696f6e4c696d69747300013c7265616c5f73697a655f757070657210010c7533320001307769746e6573735f7461736b7d0101404d6967726174696f6e5461736b3c543e00010484536565205b6050616c6c65743a3a636f6e74696e75655f6d696772617465605d2e486d6967726174655f637573746f6d5f746f700801106b6579736d0101305665633c5665633c75383e3e0001307769746e6573735f73697a6510010c7533320002048c536565205b6050616c6c65743a3a6d6967726174655f637573746f6d5f746f70605d2e506d6967726174655f637573746f6d5f6368696c640c0110726f6f7434011c5665633c75383e0001286368696c645f6b6579736d0101305665633c5665633c75383e3e000128746f74616c5f73697a6510010c75333200030494536565205b6050616c6c65743a3a6d6967726174655f637573746f6d5f6368696c64605d2e547365745f7369676e65645f6d61785f6c696d6974730401186c696d6974737901013c4d6967726174696f6e4c696d69747300040498536565205b6050616c6c65743a3a7365745f7369676e65645f6d61785f6c696d697473605d2e48666f7263655f7365745f70726f677265737308013070726f67726573735f746f708101013450726f67726573734f663c543e00013870726f67726573735f6368696c648101013450726f67726573734f663c543e0005048c536565205b6050616c6c65743a3a666f7263655f7365745f70726f6772657373605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e750104184f7074696f6e0404540179010108104e6f6e6500000010536f6d6504007901000001000079010c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c65743c4d6967726174696f6e4c696d697473000008011073697a6510010c7533320001106974656d10010c75333200007d010c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c6574344d6967726174696f6e5461736b040454000014013070726f67726573735f746f708101013450726f67726573734f663c543e00013870726f67726573735f6368696c648101013450726f67726573734f663c543e00011073697a6510010c753332000124746f705f6974656d7310010c75333200012c6368696c645f6974656d7310010c753332000081010c6c70616c6c65745f73746174655f747269655f6d6967726174696f6e1870616c6c65742050726f677265737304244d61784b65794c656e00010c1c546f53746172740000001c4c6173744b6579040085010164426f756e6465645665633c75382c204d61784b65794c656e3e00010020436f6d706c6574650002000085010c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e000089010c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d1870616c6c65741043616c6c0404540001104c7365745f76616c69646174696f6e5f64617461040110646174618d01015450617261636861696e496e686572656e744461746100000490536565205b6050616c6c65743a3a7365745f76616c69646174696f6e5f64617461605d2e607375646f5f73656e645f7570776172645f6d65737361676504011c6d6573736167653401345570776172644d657373616765000104a4536565205b6050616c6c65743a3a7375646f5f73656e645f7570776172645f6d657373616765605d2e44617574686f72697a655f75706772616465080124636f64655f6861736830011c543a3a48617368000134636865636b5f76657273696f6e35010110626f6f6c00020488536565205b6050616c6c65743a3a617574686f72697a655f75706772616465605d2e60656e6163745f617574686f72697a65645f75706772616465040110636f646534011c5665633c75383e000304a4536565205b6050616c6c65743a3a656e6163745f617574686f72697a65645f75706772616465605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e8d01089463756d756c75735f7072696d6974697665735f70617261636861696e5f696e686572656e745450617261636861696e496e686572656e7444617461000010013c76616c69646174696f6e5f646174619101015c50657273697374656456616c69646174696f6e4461746100014472656c61795f636861696e5f73746174659901015473705f747269653a3a53746f7261676550726f6f66000144646f776e776172645f6d65737361676573a101016c5665633c496e626f756e64446f776e776172644d6573736167653e00014c686f72697a6f6e74616c5f6d65737361676573a90101a442547265654d61703c5061726149642c205665633c496e626f756e6448726d704d6573736167653e3e000091010c4c706f6c6b61646f745f7072696d6974697665730876355c50657273697374656456616c69646174696f6e446174610804480130044e01100010012c706172656e745f6865616495010120486561644461746100014c72656c61795f706172656e745f6e756d6265721001044e00016472656c61795f706172656e745f73746f726167655f726f6f74300104480001306d61785f706f765f73697a6510010c753332000095010c74706f6c6b61646f745f70617261636861696e5f7072696d697469766573287072696d6974697665732048656164446174610000040034011c5665633c75383e000099010c1c73705f747269653473746f726167655f70726f6f663053746f7261676550726f6f660000040128747269655f6e6f6465739d01014442547265655365743c5665633c75383e3e00009d010420425472656553657404045401340004006d01000000a101000002a50100a5010860706f6c6b61646f745f636f72655f7072696d69746976657358496e626f756e64446f776e776172644d657373616765042c426c6f636b4e756d62657201100008011c73656e745f617410012c426c6f636b4e756d62657200010c6d736734013c446f776e776172644d6573736167650000a901042042547265654d617008044b01ad01045601b101000400b901000000ad010c74706f6c6b61646f745f70617261636861696e5f7072696d697469766573287072696d6974697665730849640000040010010c7533320000b101000002b50100b5010860706f6c6b61646f745f636f72655f7072696d69746976657348496e626f756e6448726d704d657373616765042c426c6f636b4e756d62657201100008011c73656e745f617410012c426c6f636b4e756d6265720001106461746134015073705f7374643a3a7665633a3a5665633c75383e0000b901000002bd0100bd0100000408ad01b10100c1010c3870617261636861696e5f696e666f1870616c6c65741043616c6c040454000100040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ec5010c6470616c6c65745f636f6c6c61746f725f73656c656374696f6e1870616c6c65741043616c6c04045400011c406164645f696e76756c6e657261626c6504010c6e6577000130543a3a4163636f756e74496400000484536565205b6050616c6c65743a3a6164645f696e76756c6e657261626c65605d2e4c72656d6f76655f696e76756c6e657261626c6504010c77686f000130543a3a4163636f756e74496400010490536565205b6050616c6c65743a3a72656d6f76655f696e76756c6e657261626c65605d2e2c6765745f6c6963656e736500020470536565205b6050616c6c65743a3a6765745f6c6963656e7365605d2e1c6f6e626f61726400030460536565205b6050616c6c65743a3a6f6e626f617264605d2e206f6666626f61726400040464536565205b6050616c6c65743a3a6f6666626f617264605d2e3c72656c656173655f6c6963656e736500050480536565205b6050616c6c65743a3a72656c656173655f6c6963656e7365605d2e54666f7263655f72656c656173655f6c6963656e736504010c77686f000130543a3a4163636f756e74496400060498536565205b6050616c6c65743a3a666f7263655f72656c656173655f6c6963656e7365605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ec9010c3870616c6c65745f73657373696f6e1870616c6c65741043616c6c040454000108207365745f6b6579730801106b657973cd01011c543a3a4b65797300011470726f6f6634011c5665633c75383e00000464536565205b6050616c6c65743a3a7365745f6b657973605d2e2870757267655f6b6579730001046c536565205b6050616c6c65743a3a70757267655f6b657973605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ecd010c306f70616c5f72756e74696d653872756e74696d655f636f6d6d6f6e2c53657373696f6e4b657973000004011061757261d10101c43c41757261206173202463726174653a3a426f756e64546f52756e74696d654170705075626c69633e3a3a5075626c69630000d101104473705f636f6e73656e7375735f617572611c737232353531392c6170705f73723235353139185075626c696300000400d501013c737232353531393a3a5075626c69630000d5010c1c73705f636f72651c73723235353139185075626c6963000004000401205b75383b2033325d0000d9010c3c70616c6c65745f62616c616e6365731870616c6c65741043616c6c080454000449000124507472616e736665725f616c6c6f775f646561746808011064657374dd0101504163636f756e7449644c6f6f6b75704f663c543e00011476616c7565bc0128543a3a42616c616e636500000494536565205b6050616c6c65743a3a7472616e736665725f616c6c6f775f6465617468605d2e587365745f62616c616e63655f646570726563617465640c010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0001206e65775f66726565bc0128543a3a42616c616e63650001306f6c645f7265736572766564bc0128543a3a42616c616e63650001049c536565205b6050616c6c65743a3a7365745f62616c616e63655f64657072656361746564605d2e38666f7263655f7472616e736665720c0118736f75726365dd0101504163636f756e7449644c6f6f6b75704f663c543e00011064657374dd0101504163636f756e7449644c6f6f6b75704f663c543e00011476616c7565bc0128543a3a42616c616e63650002047c536565205b6050616c6c65743a3a666f7263655f7472616e73666572605d2e4c7472616e736665725f6b6565705f616c69766508011064657374dd0101504163636f756e7449644c6f6f6b75704f663c543e00011476616c7565bc0128543a3a42616c616e636500030490536565205b6050616c6c65743a3a7472616e736665725f6b6565705f616c697665605d2e307472616e736665725f616c6c08011064657374dd0101504163636f756e7449644c6f6f6b75704f663c543e0001286b6565705f616c69766535010110626f6f6c00040474536565205b6050616c6c65743a3a7472616e736665725f616c6c605d2e3c666f7263655f756e7265736572766508010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e000118616d6f756e74180128543a3a42616c616e636500050480536565205b6050616c6c65743a3a666f7263655f756e72657365727665605d2e40757067726164655f6163636f756e747304010c77686fe50101445665633c543a3a4163636f756e7449643e00060484536565205b6050616c6c65743a3a757067726164655f6163636f756e7473605d2e207472616e7366657208011064657374dd0101504163636f756e7449644c6f6f6b75704f663c543e00011476616c7565bc0128543a3a42616c616e636500070464536565205b6050616c6c65743a3a7472616e73666572605d2e44666f7263655f7365745f62616c616e636508010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0001206e65775f66726565bc0128543a3a42616c616e636500080488536565205b6050616c6c65743a3a666f7263655f7365745f62616c616e6365605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732edd010c2873705f72756e74696d65306d756c746961646472657373304d756c74694164647265737308244163636f756e7449640100304163636f756e74496e64657801ac011408496404000001244163636f756e74496400000014496e6465780400e10101304163636f756e74496e6465780001000c526177040034011c5665633c75383e0002002441646472657373333204000401205b75383b2033325d000300244164647265737332300400ec01205b75383b2032305d00040000e101000006ac00e5010000020000e9010c4070616c6c65745f74696d657374616d701870616c6c65741043616c6c0404540001040c73657404010c6e6f77280124543a3a4d6f6d656e7400000450536565205b6050616c6c65743a3a736574605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732eed010c3c70616c6c65745f74726561737572791870616c6c65741043616c6c0804540004490001143470726f706f73655f7370656e6408011476616c7565bc013c42616c616e63654f663c542c20493e00012c62656e6566696369617279dd0101504163636f756e7449644c6f6f6b75704f663c543e00000478536565205b6050616c6c65743a3a70726f706f73655f7370656e64605d2e3c72656a6563745f70726f706f73616c04012c70726f706f73616c5f6964e0013450726f706f73616c496e64657800010480536565205b6050616c6c65743a3a72656a6563745f70726f706f73616c605d2e40617070726f76655f70726f706f73616c04012c70726f706f73616c5f6964e0013450726f706f73616c496e64657800020484536565205b6050616c6c65743a3a617070726f76655f70726f706f73616c605d2e147370656e64080118616d6f756e74bc013c42616c616e63654f663c542c20493e00012c62656e6566696369617279dd0101504163636f756e7449644c6f6f6b75704f663c543e00030458536565205b6050616c6c65743a3a7370656e64605d2e3c72656d6f76655f617070726f76616c04012c70726f706f73616c5f6964e0013450726f706f73616c496e64657800040480536565205b6050616c6c65743a3a72656d6f76655f617070726f76616c605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ef1010c2c70616c6c65745f7375646f1870616c6c65741043616c6c040454000110107375646f04011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00000454536565205b6050616c6c65743a3a7375646f605d2e547375646f5f756e636865636b65645f77656967687408011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00011877656967687424011857656967687400010498536565205b6050616c6c65743a3a7375646f5f756e636865636b65645f776569676874605d2e1c7365745f6b657904010c6e6577dd0101504163636f756e7449644c6f6f6b75704f663c543e00020460536565205b6050616c6c65743a3a7365745f6b6579605d2e1c7375646f5f617308010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e00011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00030460536565205b6050616c6c65743a3a7375646f5f6173605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ef5010c306f726d6c5f76657374696e67186d6f64756c651043616c6c04045400011014636c61696d00000458536565205b6050616c6c65743a3a636c61696d605d2e3c7665737465645f7472616e7366657208011064657374dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f757263650001207363686564756c65b8015056657374696e675363686564756c654f663c543e00010480536565205b6050616c6c65743a3a7665737465645f7472616e73666572605d2e607570646174655f76657374696e675f7363686564756c657308010c77686fdd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500014476657374696e675f7363686564756c6573f90101645665633c56657374696e675363686564756c654f663c543e3e000204a4536565205b6050616c6c65743a3a7570646174655f76657374696e675f7363686564756c6573605d2e24636c61696d5f666f7204011064657374dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500030468536565205b6050616c6c65743a3a636c61696d5f666f72605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ef901000002b800fd010c306f726d6c5f78746f6b656e73186d6f64756c651043616c6c040454000118207472616e7366657210012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74180128543a3a42616c616e6365000110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000144646573745f7765696768745f6c696d69742102012c5765696768744c696d697400000464536565205b6050616c6c65743a3a7472616e73666572605d2e4c7472616e736665725f6d756c746961737365740c0114617373657425020160426f783c56657273696f6e65644d756c746941737365743e000110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000144646573745f7765696768745f6c696d69742102012c5765696768744c696d697400010490536565205b6050616c6c65743a3a7472616e736665725f6d756c74696173736574605d2e447472616e736665725f776974685f66656514012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74180128543a3a42616c616e636500010c666565180128543a3a42616c616e6365000110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000144646573745f7765696768745f6c696d69742102012c5765696768744c696d697400020488536565205b6050616c6c65743a3a7472616e736665725f776974685f666565605d2e707472616e736665725f6d756c746961737365745f776974685f666565100114617373657425020160426f783c56657273696f6e65644d756c746941737365743e00010c66656525020160426f783c56657273696f6e65644d756c746941737365743e000110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000144646573745f7765696768745f6c696d69742102012c5765696768744c696d6974000304b4536565205b6050616c6c65743a3a7472616e736665725f6d756c746961737365745f776974685f666565605d2e607472616e736665725f6d756c746963757272656e6369657310012863757272656e63696573390201805665633c28543a3a43757272656e637949642c20543a3a42616c616e6365293e0001206665655f6974656d10010c753332000110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000144646573745f7765696768745f6c696d69742102012c5765696768744c696d6974000404a4536565205b6050616c6c65743a3a7472616e736665725f6d756c746963757272656e63696573605d2e507472616e736665725f6d756c746961737365747310011861737365747341020164426f783c56657273696f6e65644d756c74694173736574733e0001206665655f6974656d10010c753332000110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000144646573745f7765696768745f6c696d69742102012c5765696768744c696d697400050494536565205b6050616c6c65743a3a7472616e736665725f6d756c7469617373657473605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e0102082c73746167696e675f78636d5856657273696f6e65644d756c74694c6f636174696f6e00010808563204000502014476323a3a4d756c74694c6f636174696f6e0001000856330400d4014476333a3a4d756c74694c6f636174696f6e000300000502102c73746167696e675f78636d087632346d756c74696c6f636174696f6e344d756c74694c6f636174696f6e000008011c706172656e74730801087538000120696e746572696f72090201244a756e6374696f6e7300000902102c73746167696e675f78636d087632346d756c74696c6f636174696f6e244a756e6374696f6e73000124104865726500000008583104000d0201204a756e6374696f6e00010008583208000d0201204a756e6374696f6e00000d0201204a756e6374696f6e0002000858330c000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00030008583410000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00040008583514000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00050008583618000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e0006000858371c000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00070008583820000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e00000d0201204a756e6374696f6e000800000d02102c73746167696e675f78636d087632206a756e6374696f6e204a756e6374696f6e0001242450617261636861696e0400e0010c7533320000002c4163636f756e744964333208011c6e6574776f726b110201244e6574776f726b496400010869640401205b75383b2033325d000100384163636f756e74496e646578363408011c6e6574776f726b110201244e6574776f726b4964000114696e64657828010c753634000200304163636f756e744b6579323008011c6e6574776f726b110201244e6574776f726b496400010c6b6579ec01205b75383b2032305d0003003850616c6c6574496e7374616e6365040008010875380004003047656e6572616c496e6465780400bc0110753132380005002847656e6572616c4b65790400150201805765616b426f756e6465645665633c75382c20436f6e73745533323c33323e3e000600244f6e6c794368696c6400070024506c7572616c697479080108696419020118426f64794964000110706172741d020120426f6479506172740008000011020c2c73746167696e675f78636d087632244e6574776f726b49640001100c416e79000000144e616d65640400150201805765616b426f756e6465645665633c75382c20436f6e73745533323c33323e3e00010020506f6c6b61646f74000200184b7573616d610003000015020c4c626f756e6465645f636f6c6c656374696f6e73407765616b5f626f756e6465645f766563385765616b426f756e64656456656308045401080453000004003401185665633c543e000019020c2c73746167696e675f78636d08763218426f6479496400012810556e6974000000144e616d65640400150201805765616b426f756e6465645665633c75382c20436f6e73745533323c33323e3e00010014496e6465780400e0010c7533320002002445786563757469766500030024546563686e6963616c0004002c4c656769736c6174697665000500204a7564696369616c0006001c446566656e73650007003841646d696e697374726174696f6e000800205472656173757279000900001d020c2c73746167696e675f78636d08763220426f64795061727400011414566f6963650000001c4d656d62657273040114636f756e74e0010c753332000100204672616374696f6e08010c6e6f6de0010c75333200011464656e6f6de0010c7533320002004441744c6561737450726f706f7274696f6e08010c6e6f6de0010c75333200011464656e6f6de0010c753332000300484d6f72655468616e50726f706f7274696f6e08010c6e6f6de0010c75333200011464656e6f6de0010c7533320004000021020c2c73746167696e675f78636d0876332c5765696768744c696d697400010824556e6c696d697465640000001c4c696d697465640400240118576569676874000100002502082c73746167696e675f78636d4c56657273696f6e65644d756c7469417373657400010808563204002902013876323a3a4d756c746941737365740001000856330400cc013876333a3a4d756c74694173736574000300002902102c73746167696e675f78636d087632286d756c74696173736574284d756c74694173736574000008010869642d02011c4173736574496400010c66756e3102012c46756e676962696c69747900002d02102c73746167696e675f78636d087632286d756c746961737365741c4173736574496400010820436f6e63726574650400050201344d756c74694c6f636174696f6e000000204162737472616374040034011c5665633c75383e000100003102102c73746167696e675f78636d087632286d756c746961737365742c46756e676962696c6974790001082046756e6769626c650400bc0110753132380000002c4e6f6e46756e6769626c650400350201344173736574496e7374616e6365000100003502102c73746167696e675f78636d087632286d756c74696173736574344173736574496e7374616e636500011c24556e646566696e656400000014496e6465780400bc01107531323800010018417272617934040044011c5b75383b20345d0002001841727261793804000101011c5b75383b20385d0003001c417272617931360400050101205b75383b2031365d0004001c4172726179333204000401205b75383b2033325d00050010426c6f62040034011c5665633c75383e0006000039020000023d02003d02000004080d0118004102082c73746167696e675f78636d5056657273696f6e65644d756c746941737365747300010808563204004502013c76323a3a4d756c74694173736574730001000856330400c4013c76333a3a4d756c7469417373657473000300004502102c73746167696e675f78636d087632286d756c746961737365742c4d756c7469417373657473000004004902013c5665633c4d756c746941737365743e000049020000022902004d020c2c6f726d6c5f746f6b656e73186d6f64756c651043616c6c040454000114207472616e736665720c011064657374dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74bc0128543a3a42616c616e636500000464536565205b6050616c6c65743a3a7472616e73666572605d2e307472616e736665725f616c6c0c011064657374dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500012c63757272656e63795f69640d010134543a3a43757272656e637949640001286b6565705f616c69766535010110626f6f6c00010474536565205b6050616c6c65743a3a7472616e736665725f616c6c605d2e4c7472616e736665725f6b6565705f616c6976650c011064657374dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74bc0128543a3a42616c616e636500020490536565205b6050616c6c65743a3a7472616e736665725f6b6565705f616c697665605d2e38666f7263655f7472616e73666572100118736f75726365dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500011064657374dd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500012c63757272656e63795f69640d010134543a3a43757272656e63794964000118616d6f756e74bc0128543a3a42616c616e63650003047c536565205b6050616c6c65743a3a666f7263655f7472616e73666572605d2e2c7365745f62616c616e636510010c77686fdd01018c3c543a3a4c6f6f6b7570206173205374617469634c6f6f6b75703e3a3a536f7572636500012c63757272656e63795f69640d010134543a3a43757272656e637949640001206e65775f66726565bc0128543a3a42616c616e63650001306e65775f7265736572766564bc0128543a3a42616c616e636500040470536565205b6050616c6c65743a3a7365745f62616c616e6365605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e51020c3c70616c6c65745f6964656e746974791870616c6c65741043616c6c040454000148346164645f72656769737472617204011c6163636f756e74dd0101504163636f756e7449644c6f6f6b75704f663c543e00000478536565205b6050616c6c65743a3a6164645f726567697374726172605d2e307365745f6964656e74697479040110696e666f550201a4426f783c4964656e74697479496e666f3c543a3a4d61784164646974696f6e616c4669656c64733e3e00010474536565205b6050616c6c65743a3a7365745f6964656e74697479605d2e207365745f7375627304011073756273dd0201645665633c28543a3a4163636f756e7449642c2044617461293e00020464536565205b6050616c6c65743a3a7365745f73756273605d2e38636c6561725f6964656e746974790003047c536565205b6050616c6c65743a3a636c6561725f6964656e74697479605d2e44726571756573745f6a756467656d656e740801247265675f696e646578e00138526567697374726172496e64657800011c6d61785f666565bc013042616c616e63654f663c543e00040488536565205b6050616c6c65743a3a726571756573745f6a756467656d656e74605d2e3863616e63656c5f726571756573740401247265675f696e646578100138526567697374726172496e6465780005047c536565205b6050616c6c65743a3a63616e63656c5f72657175657374605d2e1c7365745f666565080114696e646578e00138526567697374726172496e64657800010c666565bc013042616c616e63654f663c543e00060460536565205b6050616c6c65743a3a7365745f666565605d2e387365745f6163636f756e745f6964080114696e646578e00138526567697374726172496e64657800010c6e6577dd0101504163636f756e7449644c6f6f6b75704f663c543e0007047c536565205b6050616c6c65743a3a7365745f6163636f756e745f6964605d2e287365745f6669656c6473080114696e646578e00138526567697374726172496e6465780001186669656c6473e50201384964656e746974794669656c64730008046c536565205b6050616c6c65743a3a7365745f6669656c6473605d2e4470726f766964655f6a756467656d656e741001247265675f696e646578e00138526567697374726172496e646578000118746172676574dd0101504163636f756e7449644c6f6f6b75704f663c543e0001246a756467656d656e74ed02015c4a756467656d656e743c42616c616e63654f663c543e3e0001206964656e7469747930011c543a3a4861736800090488536565205b6050616c6c65743a3a70726f766964655f6a756467656d656e74605d2e346b696c6c5f6964656e74697479040118746172676574dd0101504163636f756e7449644c6f6f6b75704f663c543e000a0478536565205b6050616c6c65743a3a6b696c6c5f6964656e74697479605d2e1c6164645f73756208010c737562dd0101504163636f756e7449644c6f6f6b75704f663c543e000110646174616102011044617461000b0460536565205b6050616c6c65743a3a6164645f737562605d2e2872656e616d655f73756208010c737562dd0101504163636f756e7449644c6f6f6b75704f663c543e000110646174616102011044617461000c046c536565205b6050616c6c65743a3a72656e616d655f737562605d2e2872656d6f76655f73756204010c737562dd0101504163636f756e7449644c6f6f6b75704f663c543e000d046c536565205b6050616c6c65743a3a72656d6f76655f737562605d2e20717569745f737562000e0464536565205b6050616c6c65743a3a717569745f737562605d2e5c666f7263655f696e736572745f6964656e7469746965730401286964656e746974696573f10201985665633c28543a3a4163636f756e7449642c20526567697374726174696f6e4f663c543e293e000f04a0536565205b6050616c6c65743a3a666f7263655f696e736572745f6964656e746974696573605d2e5c666f7263655f72656d6f76655f6964656e7469746965730401286964656e746974696573e50101445665633c543a3a4163636f756e7449643e001004a0536565205b6050616c6c65743a3a666f7263655f72656d6f76655f6964656e746974696573605d2e38666f7263655f7365745f7375627304011073756273090301785665633c5375624163636f756e747342794163636f756e7449643c543e3e0011047c536565205b6050616c6c65743a3a666f7263655f7365745f73756273605d2e04704964656e746974792070616c6c6574206465636c61726174696f6e2e55020c3c70616c6c65745f6964656e74697479147479706573304964656e74697479496e666f04284669656c644c696d697400002401286164646974696f6e616c59020190426f756e6465645665633c28446174612c2044617461292c204669656c644c696d69743e00011c646973706c617961020110446174610001146c6567616c610201104461746100010c776562610201104461746100011072696f746102011044617461000114656d61696c610201104461746100013c7067705f66696e6765727072696e74d90201404f7074696f6e3c5b75383b2032305d3e000114696d616765610201104461746100011c747769747465726102011044617461000059020c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454015d02045300000400d50201185665633c543e00005d0200000408610261020061020c3c70616c6c65745f6964656e746974791474797065731044617461000198104e6f6e650000001052617730040065020000010010526177310400690200000200105261773204006d0200000300105261773304007102000004001052617734040044000005001052617735040075020000060010526177360400790200000700105261773704007d02000008001052617738040001010000090010526177390400810200000a001452617731300400850200000b001452617731310400890200000c0014526177313204008d0200000d001452617731330400910200000e001452617731340400950200000f001452617731350400990200001000145261773136040005010000110014526177313704009d02000012001452617731380400a102000013001452617731390400a502000014001452617732300400ec000015001452617732310400a902000016001452617732320400ad02000017001452617732330400b102000018001452617732340400b502000019001452617732350400b90200001a001452617732360400bd0200001b001452617732370400c10200001c001452617732380400c50200001d001452617732390400c90200001e001452617733300400cd0200001f001452617733310400d10200002000145261773332040004000021002c426c616b6554776f323536040004000022001853686132353604000400002300244b656363616b323536040004000024002c53686154687265653235360400040000250000650200000300000000080069020000030100000008006d020000030200000008007102000003030000000800750200000305000000080079020000030600000008007d02000003070000000800810200000309000000080085020000030a000000080089020000030b00000008008d020000030c000000080091020000030d000000080095020000030e000000080099020000030f00000008009d02000003110000000800a102000003120000000800a502000003130000000800a902000003150000000800ad02000003160000000800b102000003170000000800b502000003180000000800b902000003190000000800bd020000031a0000000800c1020000031b0000000800c5020000031c0000000800c9020000031d0000000800cd020000031e0000000800d1020000031f0000000800d5020000025d0200d90204184f7074696f6e04045401ec0108104e6f6e6500000010536f6d650400ec0000010000dd02000002e10200e1020000040800610200e5020c3c70616c6c65745f6964656e7469747914747970657320426974466c61677304045401e9020004002c01344964656e746974794669656c640000e9020c3c70616c6c65745f6964656e74697479147479706573344964656e746974794669656c640001201c446973706c6179000100144c6567616c0002000c5765620004001052696f7400080014456d61696c0010003850677046696e6765727072696e7400200014496d6167650040001c5477697474657200800000ed020c3c70616c6c65745f6964656e74697479147479706573244a756467656d656e74041c42616c616e63650118011c1c556e6b6e6f776e0000001c46656550616964040018011c42616c616e636500010028526561736f6e61626c65000200244b6e6f776e476f6f64000300244f75744f6644617465000400284c6f775175616c697479000500244572726f6e656f757300060000f102000002f50200f5020000040800f90200f9020c3c70616c6c65745f6964656e7469747914747970657330526567697374726174696f6e0c1c42616c616e63650118344d61784a756467656d656e7473004c4d61784164646974696f6e616c4669656c647300000c01286a756467656d656e7473fd0201fc426f756e6465645665633c28526567697374726172496e6465782c204a756467656d656e743c42616c616e63653e292c204d61784a756467656d656e74733e00011c6465706f73697418011c42616c616e6365000110696e666f550201844964656e74697479496e666f3c4d61784164646974696f6e616c4669656c64733e0000fd020c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454010103045300000400050301185665633c543e000001030000040810ed0200050300000201030009030000020d03000d0300000408001103001103000004081815030015030c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401e102045300000400dd0201185665633c543e000019030c3c70616c6c65745f707265696d6167651870616c6c65741043616c6c040454000110346e6f74655f707265696d616765040114627974657334011c5665633c75383e00000478536565205b6050616c6c65743a3a6e6f74655f707265696d616765605d2e3c756e6e6f74655f707265696d6167650401106861736830011c543a3a4861736800010480536565205b6050616c6c65743a3a756e6e6f74655f707265696d616765605d2e40726571756573745f707265696d6167650401106861736830011c543a3a4861736800020484536565205b6050616c6c65743a3a726571756573745f707265696d616765605d2e48756e726571756573745f707265696d6167650401106861736830011c543a3a486173680003048c536565205b6050616c6c65743a3a756e726571756573745f707265696d616765605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e1d030c4070616c6c65745f64656d6f63726163791870616c6c65741043616c6c04045400014c1c70726f706f736508012070726f706f73616c59010140426f756e64656443616c6c4f663c543e00011476616c7565bc013042616c616e63654f663c543e00000460536565205b6050616c6c65743a3a70726f706f7365605d2e187365636f6e6404012070726f706f73616ce0012450726f70496e6465780001045c536565205b6050616c6c65743a3a7365636f6e64605d2e10766f74650801247265665f696e646578e0013c5265666572656e64756d496e646578000110766f7465250101644163636f756e74566f74653c42616c616e63654f663c543e3e00020454536565205b6050616c6c65743a3a766f7465605d2e40656d657267656e63795f63616e63656c0401247265665f696e64657810013c5265666572656e64756d496e64657800030484536565205b6050616c6c65743a3a656d657267656e63795f63616e63656c605d2e4065787465726e616c5f70726f706f736504012070726f706f73616c59010140426f756e64656443616c6c4f663c543e00040484536565205b6050616c6c65743a3a65787465726e616c5f70726f706f7365605d2e6465787465726e616c5f70726f706f73655f6d616a6f7269747904012070726f706f73616c59010140426f756e64656443616c6c4f663c543e000504a8536565205b6050616c6c65743a3a65787465726e616c5f70726f706f73655f6d616a6f72697479605d2e6065787465726e616c5f70726f706f73655f64656661756c7404012070726f706f73616c59010140426f756e64656443616c6c4f663c543e000604a4536565205b6050616c6c65743a3a65787465726e616c5f70726f706f73655f64656661756c74605d2e28666173745f747261636b0c013470726f706f73616c5f6861736830011048323536000134766f74696e675f706572696f64100144426c6f636b4e756d626572466f723c543e00011464656c6179100144426c6f636b4e756d626572466f723c543e0007046c536565205b6050616c6c65743a3a666173745f747261636b605d2e347665746f5f65787465726e616c04013470726f706f73616c5f686173683001104832353600080478536565205b6050616c6c65743a3a7665746f5f65787465726e616c605d2e4463616e63656c5f7265666572656e64756d0401247265665f696e646578e0013c5265666572656e64756d496e64657800090488536565205b6050616c6c65743a3a63616e63656c5f7265666572656e64756d605d2e2064656c65676174650c0108746fdd0101504163636f756e7449644c6f6f6b75704f663c543e000128636f6e76696374696f6e21030128436f6e76696374696f6e00011c62616c616e636518013042616c616e63654f663c543e000a0464536565205b6050616c6c65743a3a64656c6567617465605d2e28756e64656c6567617465000b046c536565205b6050616c6c65743a3a756e64656c6567617465605d2e58636c6561725f7075626c69635f70726f706f73616c73000c049c536565205b6050616c6c65743a3a636c6561725f7075626c69635f70726f706f73616c73605d2e18756e6c6f636b040118746172676574dd0101504163636f756e7449644c6f6f6b75704f663c543e000d045c536565205b6050616c6c65743a3a756e6c6f636b605d2e2c72656d6f76655f766f7465040114696e64657810013c5265666572656e64756d496e646578000e0470536565205b6050616c6c65743a3a72656d6f76655f766f7465605d2e4472656d6f76655f6f746865725f766f7465080118746172676574dd0101504163636f756e7449644c6f6f6b75704f663c543e000114696e64657810013c5265666572656e64756d496e646578000f0488536565205b6050616c6c65743a3a72656d6f76655f6f746865725f766f7465605d2e24626c61636b6c69737408013470726f706f73616c5f686173683001104832353600013c6d617962655f7265665f696e6465782503015c4f7074696f6e3c5265666572656e64756d496e6465783e00100468536565205b6050616c6c65743a3a626c61636b6c697374605d2e3c63616e63656c5f70726f706f73616c04012870726f705f696e646578e0012450726f70496e64657800110480536565205b6050616c6c65743a3a63616e63656c5f70726f706f73616c605d2e307365745f6d657461646174610801146f776e65722d0101344d657461646174614f776e65720001286d617962655f68617368290301504f7074696f6e3c507265696d616765486173683e00120474536565205b6050616c6c65743a3a7365745f6d65746164617461605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e21030c4070616c6c65745f64656d6f637261637928636f6e76696374696f6e28436f6e76696374696f6e00011c104e6f6e65000000204c6f636b65643178000100204c6f636b65643278000200204c6f636b65643378000300204c6f636b65643478000400204c6f636b65643578000500204c6f636b6564367800060000250304184f7074696f6e04045401100108104e6f6e6500000010536f6d650400100000010000290304184f7074696f6e04045401300108104e6f6e6500000010536f6d6504003000000100002d030c4470616c6c65745f636f6c6c6563746976651870616c6c65741043616c6c0804540004490001182c7365745f6d656d626572730c012c6e65775f6d656d62657273e50101445665633c543a3a4163636f756e7449643e0001147072696d65b001504f7074696f6e3c543a3a4163636f756e7449643e0001246f6c645f636f756e7410012c4d656d626572436f756e7400000470536565205b6050616c6c65743a3a7365745f6d656d62657273605d2e1c6578656375746508012070726f706f73616c5d01017c426f783c3c5420617320436f6e6669673c493e3e3a3a50726f706f73616c3e0001306c656e6774685f626f756e64e0010c75333200010460536565205b6050616c6c65743a3a65786563757465605d2e1c70726f706f73650c01247468726573686f6c64e0012c4d656d626572436f756e7400012070726f706f73616c5d01017c426f783c3c5420617320436f6e6669673c493e3e3a3a50726f706f73616c3e0001306c656e6774685f626f756e64e0010c75333200020460536565205b6050616c6c65743a3a70726f706f7365605d2e10766f74650c012070726f706f73616c30011c543a3a48617368000114696e646578e0013450726f706f73616c496e64657800011c617070726f766535010110626f6f6c00030454536565205b6050616c6c65743a3a766f7465605d2e4c646973617070726f76655f70726f706f73616c04013470726f706f73616c5f6861736830011c543a3a4861736800050490536565205b6050616c6c65743a3a646973617070726f76655f70726f706f73616c605d2e14636c6f736510013470726f706f73616c5f6861736830011c543a3a48617368000114696e646578e0013450726f706f73616c496e64657800015470726f706f73616c5f7765696768745f626f756e642401185765696768740001306c656e6774685f626f756e64e0010c75333200060458536565205b6050616c6c65743a3a636c6f7365605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e31030c4470616c6c65745f636f6c6c6563746976651870616c6c65741043616c6c0804540004490001182c7365745f6d656d626572730c012c6e65775f6d656d62657273e50101445665633c543a3a4163636f756e7449643e0001147072696d65b001504f7074696f6e3c543a3a4163636f756e7449643e0001246f6c645f636f756e7410012c4d656d626572436f756e7400000470536565205b6050616c6c65743a3a7365745f6d656d62657273605d2e1c6578656375746508012070726f706f73616c5d01017c426f783c3c5420617320436f6e6669673c493e3e3a3a50726f706f73616c3e0001306c656e6774685f626f756e64e0010c75333200010460536565205b6050616c6c65743a3a65786563757465605d2e1c70726f706f73650c01247468726573686f6c64e0012c4d656d626572436f756e7400012070726f706f73616c5d01017c426f783c3c5420617320436f6e6669673c493e3e3a3a50726f706f73616c3e0001306c656e6774685f626f756e64e0010c75333200020460536565205b6050616c6c65743a3a70726f706f7365605d2e10766f74650c012070726f706f73616c30011c543a3a48617368000114696e646578e0013450726f706f73616c496e64657800011c617070726f766535010110626f6f6c00030454536565205b6050616c6c65743a3a766f7465605d2e4c646973617070726f76655f70726f706f73616c04013470726f706f73616c5f6861736830011c543a3a4861736800050490536565205b6050616c6c65743a3a646973617070726f76655f70726f706f73616c605d2e14636c6f736510013470726f706f73616c5f6861736830011c543a3a48617368000114696e646578e0013450726f706f73616c496e64657800015470726f706f73616c5f7765696768745f626f756e642401185765696768740001306c656e6774685f626f756e64e0010c75333200060458536565205b6050616c6c65743a3a636c6f7365605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e35030c4470616c6c65745f6d656d626572736869701870616c6c65741043616c6c08045400044900011c286164645f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0000046c536565205b6050616c6c65743a3a6164645f6d656d626572605d2e3472656d6f76655f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e00010478536565205b6050616c6c65743a3a72656d6f76655f6d656d626572605d2e2c737761705f6d656d62657208011872656d6f7665dd0101504163636f756e7449644c6f6f6b75704f663c543e00010c616464dd0101504163636f756e7449644c6f6f6b75704f663c543e00020470536565205b6050616c6c65743a3a737761705f6d656d626572605d2e3472657365745f6d656d6265727304011c6d656d62657273e50101445665633c543a3a4163636f756e7449643e00030478536565205b6050616c6c65743a3a72657365745f6d656d62657273605d2e286368616e67655f6b657904010c6e6577dd0101504163636f756e7449644c6f6f6b75704f663c543e0004046c536565205b6050616c6c65743a3a6368616e67655f6b6579605d2e247365745f7072696d6504010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e00050468536565205b6050616c6c65743a3a7365745f7072696d65605d2e2c636c6561725f7072696d6500060470536565205b6050616c6c65743a3a636c6561725f7072696d65605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e39030c4470616c6c65745f6d656d626572736869701870616c6c65741043616c6c08045400044900011c286164645f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0000046c536565205b6050616c6c65743a3a6164645f6d656d626572605d2e3472656d6f76655f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e00010478536565205b6050616c6c65743a3a72656d6f76655f6d656d626572605d2e2c737761705f6d656d62657208011872656d6f7665dd0101504163636f756e7449644c6f6f6b75704f663c543e00010c616464dd0101504163636f756e7449644c6f6f6b75704f663c543e00020470536565205b6050616c6c65743a3a737761705f6d656d626572605d2e3472657365745f6d656d6265727304011c6d656d62657273e50101445665633c543a3a4163636f756e7449643e00030478536565205b6050616c6c65743a3a72657365745f6d656d62657273605d2e286368616e67655f6b657904010c6e6577dd0101504163636f756e7449644c6f6f6b75704f663c543e0004046c536565205b6050616c6c65743a3a6368616e67655f6b6579605d2e247365745f7072696d6504010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e00050468536565205b6050616c6c65743a3a7365745f7072696d65605d2e2c636c6561725f7072696d6500060470536565205b6050616c6c65743a3a636c6561725f7072696d65605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e3d030c6070616c6c65745f72616e6b65645f636f6c6c6563746976651870616c6c65741043616c6c080454000449000118286164645f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0000046c536565205b6050616c6c65743a3a6164645f6d656d626572605d2e3870726f6d6f74655f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0001047c536565205b6050616c6c65743a3a70726f6d6f74655f6d656d626572605d2e3464656d6f74655f6d656d62657204010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e00020478536565205b6050616c6c65743a3a64656d6f74655f6d656d626572605d2e3472656d6f76655f6d656d62657208010c77686fdd0101504163636f756e7449644c6f6f6b75704f663c543e0001206d696e5f72616e6b4901011052616e6b00030478536565205b6050616c6c65743a3a72656d6f76655f6d656d626572605d2e10766f7465080110706f6c6c100144506f6c6c496e6465784f663c542c20493e00010c61796535010110626f6f6c00040454536565205b6050616c6c65743a3a766f7465605d2e30636c65616e75705f706f6c6c080128706f6c6c5f696e646578100144506f6c6c496e6465784f663c542c20493e00010c6d617810010c75333200050474536565205b6050616c6c65743a3a636c65616e75705f706f6c6c605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e41030c4070616c6c65745f7265666572656e64611870616c6c65741043616c6c080454000449000124187375626d69740c013c70726f706f73616c5f6f726967696e4503015c426f783c50616c6c6574734f726967696e4f663c543e3e00012070726f706f73616c5901014c426f756e64656443616c6c4f663c542c20493e000140656e6163746d656e745f6d6f6d656e746d03017c446973706174636854696d653c426c6f636b4e756d626572466f723c543e3e0000045c536565205b6050616c6c65743a3a7375626d6974605d2e58706c6163655f6465636973696f6e5f6465706f736974040114696e64657810013c5265666572656e64756d496e6465780001049c536565205b6050616c6c65743a3a706c6163655f6465636973696f6e5f6465706f736974605d2e5c726566756e645f6465636973696f6e5f6465706f736974040114696e64657810013c5265666572656e64756d496e646578000204a0536565205b6050616c6c65743a3a726566756e645f6465636973696f6e5f6465706f736974605d2e1863616e63656c040114696e64657810013c5265666572656e64756d496e6465780003045c536565205b6050616c6c65743a3a63616e63656c605d2e106b696c6c040114696e64657810013c5265666572656e64756d496e64657800040454536565205b6050616c6c65743a3a6b696c6c605d2e406e756467655f7265666572656e64756d040114696e64657810013c5265666572656e64756d496e64657800050484536565205b6050616c6c65743a3a6e756467655f7265666572656e64756d605d2e486f6e655f66657765725f6465636964696e67040114747261636b4901013c547261636b49644f663c542c20493e0006048c536565205b6050616c6c65743a3a6f6e655f66657765725f6465636964696e67605d2e64726566756e645f7375626d697373696f6e5f6465706f736974040114696e64657810013c5265666572656e64756d496e646578000704a8536565205b6050616c6c65743a3a726566756e645f7375626d697373696f6e5f6465706f736974605d2e307365745f6d65746164617461080114696e64657810013c5265666572656e64756d496e6465780001286d617962655f68617368290301504f7074696f6e3c507265696d616765486173683e00080474536565205b6050616c6c65743a3a7365745f6d65746164617461605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e450308306f70616c5f72756e74696d65304f726967696e43616c6c65720001201873797374656d0400490301746672616d655f73797374656d3a3a4f726967696e3c52756e74696d653e0000001c436f756e63696c04004d0301010170616c6c65745f636f6c6c6563746976653a3a4f726967696e3c52756e74696d652c2070616c6c65745f636f6c6c6563746976653a3a496e7374616e6365313e002b0048546563686e6963616c436f6d6d69747465650400510301010170616c6c65745f636f6c6c6563746976653a3a4f726967696e3c52756e74696d652c2070616c6c65745f636f6c6c6563746976653a3a496e7374616e6365323e002c001c4f726967696e7304005503016870616c6c65745f676f765f6f726967696e733a3a4f726967696e0063002c506f6c6b61646f7458636d04005903014870616c6c65745f78636d3a3a4f726967696e0033002843756d756c757358636d04005d03016863756d756c75735f70616c6c65745f78636d3a3a4f726967696e00340020457468657265756d04006103015c70616c6c65745f657468657265756d3a3a4f726967696e00650010566f69640400690301410173656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a0a5f5f707269766174653a3a566f69640007000049030c346672616d655f737570706f7274206469737061746368245261774f726967696e04244163636f756e7449640100010c10526f6f74000000185369676e656404000001244163636f756e744964000100104e6f6e65000200004d03084470616c6c65745f636f6c6c656374697665245261774f726967696e08244163636f756e7449640100044900010c1c4d656d62657273080010012c4d656d626572436f756e74000010012c4d656d626572436f756e74000000184d656d62657204000001244163636f756e744964000100205f5068616e746f6d000200005103084470616c6c65745f636f6c6c656374697665245261774f726967696e08244163636f756e7449640100044900010c1c4d656d62657273080010012c4d656d626572436f756e74000010012c4d656d626572436f756e74000000184d656d62657204000001244163636f756e744964000100205f5068616e746f6d0002000055030c4870616c6c65745f676f765f6f726967696e731870616c6c6574184f726967696e0001045446656c6c6f777368697050726f706f736974696f6e0000000059030c2870616c6c65745f78636d1870616c6c6574184f726967696e0001080c58636d0400d401344d756c74694c6f636174696f6e00000020526573706f6e73650400d401344d756c74694c6f636174696f6e000100005d030c4863756d756c75735f70616c6c65745f78636d1870616c6c6574184f726967696e0001081452656c6179000000405369626c696e6750617261636861696e0400ad010118506172614964000100006103083c70616c6c65745f657468657265756d245261774f726967696e0001044c457468657265756d5472616e73616374696f6e04006503011048313630000000006503083c7072696d69746976655f7479706573104831363000000400ec01205b75383b2032305d00006903081c73705f636f726510566f6964000100006d0310346672616d655f737570706f727418747261697473207363686564756c6530446973706174636854696d65042c426c6f636b4e756d62657201100108084174040010012c426c6f636b4e756d626572000000144166746572040010012c426c6f636b4e756d6265720001000071030c4070616c6c65745f7363686564756c65721870616c6c65741043616c6c040454000118207363686564756c651001107768656e100144426c6f636b4e756d626572466f723c543e0001386d617962655f706572696f646963750301ac4f7074696f6e3c7363686564756c653a3a506572696f643c426c6f636b4e756d626572466f723c543e3e3e0001207072696f726974790801487363686564756c653a3a5072696f7269747900011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00000464536565205b6050616c6c65743a3a7363686564756c65605d2e1863616e63656c0801107768656e100144426c6f636b4e756d626572466f723c543e000114696e64657810010c7533320001045c536565205b6050616c6c65743a3a63616e63656c605d2e387363686564756c655f6e616d656414010869640401205461736b4e616d650001107768656e100144426c6f636b4e756d626572466f723c543e0001386d617962655f706572696f646963750301ac4f7074696f6e3c7363686564756c653a3a506572696f643c426c6f636b4e756d626572466f723c543e3e3e0001207072696f726974790801487363686564756c653a3a5072696f7269747900011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e0002047c536565205b6050616c6c65743a3a7363686564756c655f6e616d6564605d2e3063616e63656c5f6e616d656404010869640401205461736b4e616d6500030474536565205b6050616c6c65743a3a63616e63656c5f6e616d6564605d2e387363686564756c655f61667465721001146166746572100144426c6f636b4e756d626572466f723c543e0001386d617962655f706572696f646963750301ac4f7074696f6e3c7363686564756c653a3a506572696f643c426c6f636b4e756d626572466f723c543e3e3e0001207072696f726974790801487363686564756c653a3a5072696f7269747900011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e0004047c536565205b6050616c6c65743a3a7363686564756c655f6166746572605d2e507363686564756c655f6e616d65645f616674657214010869640401205461736b4e616d650001146166746572100144426c6f636b4e756d626572466f723c543e0001386d617962655f706572696f646963750301ac4f7074696f6e3c7363686564756c653a3a506572696f643c426c6f636b4e756d626572466f723c543e3e3e0001207072696f726974790801487363686564756c653a3a5072696f7269747900011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00050494536565205b6050616c6c65743a3a7363686564756c655f6e616d65645f6166746572605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e750304184f7074696f6e0404540179030108104e6f6e6500000010536f6d650400790300000100007903000004081010007d030c6463756d756c75735f70616c6c65745f78636d705f71756575651870616c6c65741043616c6c04045400012448736572766963655f6f766572776569676874080114696e6465782c013c4f766572776569676874496e6465780001307765696768745f6c696d69742401185765696768740000048c536565205b6050616c6c65743a3a736572766963655f6f766572776569676874605d2e5473757370656e645f78636d5f657865637574696f6e00010498536565205b6050616c6c65743a3a73757370656e645f78636d5f657865637574696f6e605d2e50726573756d655f78636d5f657865637574696f6e00020494536565205b6050616c6c65743a3a726573756d655f78636d5f657865637574696f6e605d2e607570646174655f73757370656e645f7468726573686f6c6404010c6e657710010c753332000304a4536565205b6050616c6c65743a3a7570646174655f73757370656e645f7468726573686f6c64605d2e547570646174655f64726f705f7468726573686f6c6404010c6e657710010c75333200040498536565205b6050616c6c65743a3a7570646174655f64726f705f7468726573686f6c64605d2e5c7570646174655f726573756d655f7468726573686f6c6404010c6e657710010c753332000504a0536565205b6050616c6c65743a3a7570646174655f726573756d655f7468726573686f6c64605d2e5c7570646174655f7468726573686f6c645f77656967687404010c6e6577240118576569676874000604a0536565205b6050616c6c65743a3a7570646174655f7468726573686f6c645f776569676874605d2e707570646174655f7765696768745f72657374726963745f646563617904010c6e6577240118576569676874000704b4536565205b6050616c6c65743a3a7570646174655f7765696768745f72657374726963745f6465636179605d2e847570646174655f78636d705f6d61785f696e646976696475616c5f77656967687404010c6e6577240118576569676874000804c8536565205b6050616c6c65743a3a7570646174655f78636d705f6d61785f696e646976696475616c5f776569676874605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e81030c2870616c6c65745f78636d1870616c6c65741043616c6c04045400012c1073656e64080110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00011c6d65737361676585030154426f783c56657273696f6e656458636d3c28293e3e00000454536565205b6050616c6c65743a3a73656e64605d2e3c74656c65706f72745f617373657473100110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00012c62656e65666963696172790102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00011861737365747341020164426f783c56657273696f6e65644d756c74694173736574733e0001386665655f61737365745f6974656d10010c75333200010480536565205b6050616c6c65743a3a74656c65706f72745f617373657473605d2e5c726573657276655f7472616e736665725f617373657473100110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00012c62656e65666963696172790102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00011861737365747341020164426f783c56657273696f6e65644d756c74694173736574733e0001386665655f61737365745f6974656d10010c753332000204a0536565205b6050616c6c65743a3a726573657276655f7472616e736665725f617373657473605d2e1c6578656375746508011c6d657373616765050401c0426f783c56657273696f6e656458636d3c3c5420617320537973436f6e6669673e3a3a52756e74696d6543616c6c3e3e0001286d61785f77656967687424011857656967687400030460536565205b6050616c6c65743a3a65786563757465605d2e44666f7263655f78636d5f76657273696f6e0801206c6f636174696f6ed40148426f783c4d756c74694c6f636174696f6e3e00011c76657273696f6e10012858636d56657273696f6e00040488536565205b6050616c6c65743a3a666f7263655f78636d5f76657273696f6e605d2e64666f7263655f64656661756c745f78636d5f76657273696f6e0401446d617962655f78636d5f76657273696f6e250301484f7074696f6e3c58636d56657273696f6e3e000504a8536565205b6050616c6c65743a3a666f7263655f64656661756c745f78636d5f76657273696f6e605d2e78666f7263655f7375627363726962655f76657273696f6e5f6e6f746966790401206c6f636174696f6e0102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000604bc536565205b6050616c6c65743a3a666f7263655f7375627363726962655f76657273696f6e5f6e6f74696679605d2e80666f7263655f756e7375627363726962655f76657273696f6e5f6e6f746966790401206c6f636174696f6e0102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e000704c4536565205b6050616c6c65743a3a666f7263655f756e7375627363726962655f76657273696f6e5f6e6f74696679605d2e7c6c696d697465645f726573657276655f7472616e736665725f617373657473140110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00012c62656e65666963696172790102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00011861737365747341020164426f783c56657273696f6e65644d756c74694173736574733e0001386665655f61737365745f6974656d10010c7533320001307765696768745f6c696d69742102012c5765696768744c696d6974000804c0536565205b6050616c6c65743a3a6c696d697465645f726573657276655f7472616e736665725f617373657473605d2e5c6c696d697465645f74656c65706f72745f617373657473140110646573740102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00012c62656e65666963696172790102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e00011861737365747341020164426f783c56657273696f6e65644d756c74694173736574733e0001386665655f61737365745f6974656d10010c7533320001307765696768745f6c696d69742102012c5765696768744c696d6974000904a0536565205b6050616c6c65743a3a6c696d697465645f74656c65706f72745f617373657473605d2e40666f7263655f73757370656e73696f6e04012473757370656e64656435010110626f6f6c000a0484536565205b6050616c6c65743a3a666f7263655f73757370656e73696f6e605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e8503082c73746167696e675f78636d3056657273696f6e656458636d042c52756e74696d6543616c6c00010808563204008903015076323a3a58636d3c52756e74696d6543616c6c3e0002000856330400bd03015076333a3a58636d3c52756e74696d6543616c6c3e0003000089030c2c73746167696e675f78636d0876320c58636d042c52756e74696d6543616c6c000004008d0301745665633c496e737472756374696f6e3c52756e74696d6543616c6c3e3e00008d0300000291030091030c2c73746167696e675f78636d0876322c496e737472756374696f6e042c52756e74696d6543616c6c000170345769746864726177417373657404004502012c4d756c7469417373657473000000545265736572766541737365744465706f736974656404004502012c4d756c7469417373657473000100585265636569766554656c65706f72746564417373657404004502012c4d756c7469417373657473000200345175657279526573706f6e73650c012071756572795f696428011c51756572794964000120726573706f6e736595030120526573706f6e73650001286d61785f77656967687428010c753634000300345472616e7366657241737365740801186173736574734502012c4d756c746941737365747300012c62656e6566696369617279050201344d756c74694c6f636174696f6e000400505472616e736665725265736572766541737365740c01186173736574734502012c4d756c746941737365747300011064657374050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e000500205472616e736163740c012c6f726967696e5f74797065a50301284f726967696e4b696e64000158726571756972655f7765696768745f61745f6d6f737428010c75363400011063616c6ca9030168446f75626c65456e636f6465643c52756e74696d6543616c6c3e0006006448726d704e65774368616e6e656c4f70656e526571756573740c011873656e646572e0010c7533320001406d61785f6d6573736167655f73697a65e0010c7533320001306d61785f6361706163697479e0010c7533320007004c48726d704368616e6e656c4163636570746564040124726563697069656e74e0010c7533320008004848726d704368616e6e656c436c6f73696e670c0124696e69746961746f72e0010c75333200011873656e646572e0010c753332000124726563697069656e74e0010c7533320009002c436c6561724f726967696e000a003444657363656e644f726967696e040009020154496e746572696f724d756c74694c6f636174696f6e000b002c5265706f72744572726f720c012071756572795f696428011c5175657279496400011064657374050201344d756c74694c6f636174696f6e00014c6d61785f726573706f6e73655f77656967687428010c753634000c00304465706f73697441737365740c0118617373657473ad0301404d756c7469417373657446696c7465720001286d61785f617373657473e0010c75333200012c62656e6566696369617279050201344d756c74694c6f636174696f6e000d004c4465706f736974526573657276654173736574100118617373657473ad0301404d756c7469417373657446696c7465720001286d61785f617373657473e0010c75333200011064657374050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e000e003445786368616e6765417373657408011067697665ad0301404d756c7469417373657446696c74657200011c726563656976654502012c4d756c7469417373657473000f005c496e6974696174655265736572766557697468647261770c0118617373657473ad0301404d756c7469417373657446696c74657200011c72657365727665050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e00100040496e69746961746554656c65706f72740c0118617373657473ad0301404d756c7469417373657446696c74657200011064657374050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e001100305175657279486f6c64696e6710012071756572795f696428011c5175657279496400011064657374050201344d756c74694c6f636174696f6e000118617373657473ad0301404d756c7469417373657446696c74657200014c6d61785f726573706f6e73655f77656967687428010c75363400120030427579457865637574696f6e08011066656573290201284d756c746941737365740001307765696768745f6c696d6974b903012c5765696768744c696d697400130034526566756e64537572706c75730014003c5365744572726f7248616e646c657204008903014058636d3c52756e74696d6543616c6c3e0015002c536574417070656e64697804008903014058636d3c52756e74696d6543616c6c3e00160028436c6561724572726f7200170028436c61696d41737365740801186173736574734502012c4d756c74694173736574730001187469636b6574050201344d756c74694c6f636174696f6e0018001054726170040028010c7536340019004053756273637269626556657273696f6e08012071756572795f696428011c5175657279496400014c6d61785f726573706f6e73655f77656967687428010c753634001a0048556e73756273637269626556657273696f6e001b000095030c2c73746167696e675f78636d08763220526573706f6e7365000110104e756c6c0000001841737365747304004502012c4d756c74694173736574730001003c457865637574696f6e526573756c740400990301504f7074696f6e3c287533322c204572726f72293e0002001c56657273696f6e040010013873757065723a3a56657273696f6e00030000990304184f7074696f6e040454019d030108104e6f6e6500000010536f6d6504009d0300000100009d030000040810a10300a103102c73746167696e675f78636d08763218747261697473144572726f72000168204f766572666c6f7700000034556e696d706c656d656e74656400010060556e74727573746564526573657276654c6f636174696f6e00020064556e7472757374656454656c65706f72744c6f636174696f6e000300444d756c74694c6f636174696f6e46756c6c000400684d756c74694c6f636174696f6e4e6f74496e7665727469626c65000500244261644f726967696e0006003c496e76616c69644c6f636174696f6e0007003441737365744e6f74466f756e64000800544661696c6564546f5472616e7361637441737365740009003c4e6f74576974686472617761626c65000a00484c6f636174696f6e43616e6e6f74486f6c64000b0054457863656564734d61784d65737361676553697a65000c005844657374696e6174696f6e556e737570706f72746564000d00245472616e73706f7274000e0028556e726f757461626c65000f0030556e6b6e6f776e436c61696d001000384661696c6564546f4465636f6465001100404d6178576569676874496e76616c6964001200384e6f74486f6c64696e674665657300130030546f6f457870656e73697665001400105472617004002c010c7536340015004c556e68616e646c656458636d56657273696f6e001600485765696768744c696d69745265616368656404002c01185765696768740017001c426172726965720018004c5765696768744e6f74436f6d70757461626c6500190000a5030c2c73746167696e675f78636d087632284f726967696e4b696e64000110184e617469766500000040536f7665726569676e4163636f756e74000100245375706572757365720002000c58636d00030000a9030c2c73746167696e675f78636d38646f75626c655f656e636f64656434446f75626c65456e636f646564040454000004011c656e636f64656434011c5665633c75383e0000ad03102c73746167696e675f78636d087632286d756c74696173736574404d756c7469417373657446696c74657200010820446566696e69746504004502012c4d756c74694173736574730000001057696c640400b103013857696c644d756c7469417373657400010000b103102c73746167696e675f78636d087632286d756c746961737365743857696c644d756c746941737365740001080c416c6c00000014416c6c4f6608010869642d02011c4173736574496400010c66756eb503013c57696c6446756e676962696c69747900010000b503102c73746167696e675f78636d087632286d756c746961737365743c57696c6446756e676962696c6974790001082046756e6769626c650000002c4e6f6e46756e6769626c6500010000b9030c2c73746167696e675f78636d0876322c5765696768744c696d697400010824556e6c696d697465640000001c4c696d69746564040028010c75363400010000bd030c2c73746167696e675f78636d0876330c58636d041043616c6c00000400c10301585665633c496e737472756374696f6e3c43616c6c3e3e0000c103000002c50300c5030c2c73746167696e675f78636d0876332c496e737472756374696f6e041043616c6c0001c034576974686472617741737365740400c4012c4d756c7469417373657473000000545265736572766541737365744465706f73697465640400c4012c4d756c7469417373657473000100585265636569766554656c65706f7274656441737365740400c4012c4d756c7469417373657473000200345175657279526573706f6e736510012071756572795f696428011c51756572794964000120726573706f6e7365c9030120526573706f6e73650001286d61785f77656967687424011857656967687400011c71756572696572f10301544f7074696f6e3c4d756c74694c6f636174696f6e3e000300345472616e736665724173736574080118617373657473c4012c4d756c746941737365747300012c62656e6566696369617279d401344d756c74694c6f636174696f6e000400505472616e736665725265736572766541737365740c0118617373657473c4012c4d756c746941737365747300011064657374d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e000500205472616e736163740c012c6f726967696e5f6b696e64a50301284f726967696e4b696e64000158726571756972655f7765696768745f61745f6d6f737424011857656967687400011063616c6ca903014c446f75626c65456e636f6465643c43616c6c3e0006006448726d704e65774368616e6e656c4f70656e526571756573740c011873656e646572e0010c7533320001406d61785f6d6573736167655f73697a65e0010c7533320001306d61785f6361706163697479e0010c7533320007004c48726d704368616e6e656c4163636570746564040124726563697069656e74e0010c7533320008004848726d704368616e6e656c436c6f73696e670c0124696e69746961746f72e0010c75333200011873656e646572e0010c753332000124726563697069656e74e0010c7533320009002c436c6561724f726967696e000a003444657363656e644f726967696e0400d80154496e746572696f724d756c74694c6f636174696f6e000b002c5265706f72744572726f720400f50301445175657279526573706f6e7365496e666f000c00304465706f7369744173736574080118617373657473f90301404d756c7469417373657446696c74657200012c62656e6566696369617279d401344d756c74694c6f636174696f6e000d004c4465706f7369745265736572766541737365740c0118617373657473f90301404d756c7469417373657446696c74657200011064657374d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e000e003445786368616e676541737365740c011067697665f90301404d756c7469417373657446696c74657200011077616e74c4012c4d756c746941737365747300011c6d6178696d616c35010110626f6f6c000f005c496e6974696174655265736572766557697468647261770c0118617373657473f90301404d756c7469417373657446696c74657200011c72657365727665d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e00100040496e69746961746554656c65706f72740c0118617373657473f90301404d756c7469417373657446696c74657200011064657374d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e001100345265706f7274486f6c64696e67080134726573706f6e73655f696e666ff50301445175657279526573706f6e7365496e666f000118617373657473f90301404d756c7469417373657446696c74657200120030427579457865637574696f6e08011066656573cc01284d756c746941737365740001307765696768745f6c696d69742102012c5765696768744c696d697400130034526566756e64537572706c75730014003c5365744572726f7248616e646c65720400bd03012458636d3c43616c6c3e0015002c536574417070656e6469780400bd03012458636d3c43616c6c3e00160028436c6561724572726f7200170028436c61696d4173736574080118617373657473c4012c4d756c74694173736574730001187469636b6574d401344d756c74694c6f636174696f6e0018001054726170040028010c7536340019004053756273637269626556657273696f6e08012071756572795f696428011c5175657279496400014c6d61785f726573706f6e73655f776569676874240118576569676874001a0048556e73756273637269626556657273696f6e001b00244275726e41737365740400c4012c4d756c7469417373657473001c002c45787065637441737365740400c4012c4d756c7469417373657473001d00304578706563744f726967696e0400f10301544f7074696f6e3c4d756c74694c6f636174696f6e3e001e002c4578706563744572726f720400cd0301504f7074696f6e3c287533322c204572726f72293e001f00504578706563745472616e736163745374617475730400e90301384d617962654572726f72436f64650020002c517565727950616c6c657408012c6d6f64756c655f6e616d6534011c5665633c75383e000134726573706f6e73655f696e666ff50301445175657279526573706f6e7365496e666f0021003045787065637450616c6c6574140114696e646578e0010c7533320001106e616d6534011c5665633c75383e00012c6d6f64756c655f6e616d6534011c5665633c75383e00012c63726174655f6d616a6f72e0010c75333200013c6d696e5f63726174655f6d696e6f72e0010c753332002200505265706f72745472616e736163745374617475730400f50301445175657279526573706f6e7365496e666f0023004c436c6561725472616e736163745374617475730024003c556e6976657273616c4f726967696e0400dc01204a756e6374696f6e002500344578706f72744d6573736167650c011c6e6574776f726be801244e6574776f726b496400012c64657374696e6174696f6ed80154496e746572696f724d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e002600244c6f636b41737365740801146173736574cc01284d756c74694173736574000120756e6c6f636b6572d401344d756c74694c6f636174696f6e0027002c556e6c6f636b41737365740801146173736574cc01284d756c74694173736574000118746172676574d401344d756c74694c6f636174696f6e002800384e6f7465556e6c6f636b61626c650801146173736574cc01284d756c746941737365740001146f776e6572d401344d756c74694c6f636174696f6e0029003452657175657374556e6c6f636b0801146173736574cc01284d756c746941737365740001186c6f636b6572d401344d756c74694c6f636174696f6e002a002c536574466565734d6f64650401306a69745f776974686472617735010110626f6f6c002b0020536574546f70696304000401205b75383b2033325d002c0028436c656172546f706963002d002c416c6961734f726967696e0400d401344d756c74694c6f636174696f6e002e003c556e70616964457865637574696f6e0801307765696768745f6c696d69742102012c5765696768744c696d6974000130636865636b5f6f726967696ef10301544f7074696f6e3c4d756c74694c6f636174696f6e3e002f0000c9030c2c73746167696e675f78636d08763320526573706f6e7365000118104e756c6c000000184173736574730400c4012c4d756c74694173736574730001003c457865637574696f6e526573756c740400cd0301504f7074696f6e3c287533322c204572726f72293e0002001c56657273696f6e040010013873757065723a3a56657273696f6e0003002c50616c6c657473496e666f0400d9030198426f756e6465645665633c50616c6c6574496e666f2c204d617850616c6c657473496e666f3e000400384469737061746368526573756c740400e90301384d617962654572726f72436f646500050000cd0304184f7074696f6e04045401d1030108104e6f6e6500000010536f6d650400d1030000010000d1030000040810d50300d503102c73746167696e675f78636d08763318747261697473144572726f720001a0204f766572666c6f7700000034556e696d706c656d656e74656400010060556e74727573746564526573657276654c6f636174696f6e00020064556e7472757374656454656c65706f72744c6f636174696f6e000300304c6f636174696f6e46756c6c000400544c6f636174696f6e4e6f74496e7665727469626c65000500244261644f726967696e0006003c496e76616c69644c6f636174696f6e0007003441737365744e6f74466f756e64000800544661696c6564546f5472616e7361637441737365740009003c4e6f74576974686472617761626c65000a00484c6f636174696f6e43616e6e6f74486f6c64000b0054457863656564734d61784d65737361676553697a65000c005844657374696e6174696f6e556e737570706f72746564000d00245472616e73706f7274000e0028556e726f757461626c65000f0030556e6b6e6f776e436c61696d001000384661696c6564546f4465636f6465001100404d6178576569676874496e76616c6964001200384e6f74486f6c64696e674665657300130030546f6f457870656e73697665001400105472617004002c010c753634001500404578706563746174696f6e46616c73650016003850616c6c65744e6f74466f756e64001700304e616d654d69736d617463680018004c56657273696f6e496e636f6d70617469626c6500190050486f6c64696e67576f756c644f766572666c6f77001a002c4578706f72744572726f72001b00385265616e63686f724661696c6564001c00184e6f4465616c001d0028466565734e6f744d6574001e00244c6f636b4572726f72001f00304e6f5065726d697373696f6e00200028556e616e63686f726564002100384e6f744465706f73697461626c650022004c556e68616e646c656458636d56657273696f6e002300485765696768744c696d69745265616368656404002401185765696768740024001c426172726965720025004c5765696768744e6f74436f6d70757461626c650026004445786365656473537461636b4c696d697400270000d9030c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401dd03045300000400e50301185665633c543e0000dd030c2c73746167696e675f78636d0876332850616c6c6574496e666f0000180114696e646578e0010c7533320001106e616d65e1030180426f756e6465645665633c75382c204d617850616c6c65744e616d654c656e3e00012c6d6f64756c655f6e616d65e1030180426f756e6465645665633c75382c204d617850616c6c65744e616d654c656e3e0001146d616a6f72e0010c7533320001146d696e6f72e0010c7533320001147061746368e0010c7533320000e1030c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000e503000002dd0300e9030c2c73746167696e675f78636d087633384d617962654572726f72436f646500010c1c53756363657373000000144572726f720400ed03018c426f756e6465645665633c75382c204d617844697370617463684572726f724c656e3e000100385472756e63617465644572726f720400ed03018c426f756e6465645665633c75382c204d617844697370617463684572726f724c656e3e00020000ed030c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000f10304184f7074696f6e04045401d40108104e6f6e6500000010536f6d650400d40000010000f5030c2c73746167696e675f78636d087633445175657279526573706f6e7365496e666f00000c012c64657374696e6174696f6ed401344d756c74694c6f636174696f6e00012071756572795f696428011c517565727949640001286d61785f7765696768742401185765696768740000f903102c73746167696e675f78636d087633286d756c74696173736574404d756c7469417373657446696c74657200010820446566696e6974650400c4012c4d756c74694173736574730000001057696c640400fd03013857696c644d756c7469417373657400010000fd03102c73746167696e675f78636d087633286d756c746961737365743857696c644d756c746941737365740001100c416c6c00000014416c6c4f660801086964d0011c4173736574496400010c66756e0104013c57696c6446756e676962696c69747900010028416c6c436f756e7465640400e0010c75333200020030416c6c4f66436f756e7465640c01086964d0011c4173736574496400010c66756e0104013c57696c6446756e676962696c697479000114636f756e74e0010c753332000300000104102c73746167696e675f78636d087633286d756c746961737365743c57696c6446756e676962696c6974790001082046756e6769626c650000002c4e6f6e46756e6769626c65000100000504082c73746167696e675f78636d3056657273696f6e656458636d042c52756e74696d6543616c6c00010808563204000904015076323a3a58636d3c52756e74696d6543616c6c3e00020008563304001904015076333a3a58636d3c52756e74696d6543616c6c3e0003000009040c2c73746167696e675f78636d0876320c58636d042c52756e74696d6543616c6c000004000d0401745665633c496e737472756374696f6e3c52756e74696d6543616c6c3e3e00000d0400000211040011040c2c73746167696e675f78636d0876322c496e737472756374696f6e042c52756e74696d6543616c6c000170345769746864726177417373657404004502012c4d756c7469417373657473000000545265736572766541737365744465706f736974656404004502012c4d756c7469417373657473000100585265636569766554656c65706f72746564417373657404004502012c4d756c7469417373657473000200345175657279526573706f6e73650c012071756572795f696428011c51756572794964000120726573706f6e736595030120526573706f6e73650001286d61785f77656967687428010c753634000300345472616e7366657241737365740801186173736574734502012c4d756c746941737365747300012c62656e6566696369617279050201344d756c74694c6f636174696f6e000400505472616e736665725265736572766541737365740c01186173736574734502012c4d756c746941737365747300011064657374050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e000500205472616e736163740c012c6f726967696e5f74797065a50301284f726967696e4b696e64000158726571756972655f7765696768745f61745f6d6f737428010c75363400011063616c6c15040168446f75626c65456e636f6465643c52756e74696d6543616c6c3e0006006448726d704e65774368616e6e656c4f70656e526571756573740c011873656e646572e0010c7533320001406d61785f6d6573736167655f73697a65e0010c7533320001306d61785f6361706163697479e0010c7533320007004c48726d704368616e6e656c4163636570746564040124726563697069656e74e0010c7533320008004848726d704368616e6e656c436c6f73696e670c0124696e69746961746f72e0010c75333200011873656e646572e0010c753332000124726563697069656e74e0010c7533320009002c436c6561724f726967696e000a003444657363656e644f726967696e040009020154496e746572696f724d756c74694c6f636174696f6e000b002c5265706f72744572726f720c012071756572795f696428011c5175657279496400011064657374050201344d756c74694c6f636174696f6e00014c6d61785f726573706f6e73655f77656967687428010c753634000c00304465706f73697441737365740c0118617373657473ad0301404d756c7469417373657446696c7465720001286d61785f617373657473e0010c75333200012c62656e6566696369617279050201344d756c74694c6f636174696f6e000d004c4465706f736974526573657276654173736574100118617373657473ad0301404d756c7469417373657446696c7465720001286d61785f617373657473e0010c75333200011064657374050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e000e003445786368616e6765417373657408011067697665ad0301404d756c7469417373657446696c74657200011c726563656976654502012c4d756c7469417373657473000f005c496e6974696174655265736572766557697468647261770c0118617373657473ad0301404d756c7469417373657446696c74657200011c72657365727665050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e00100040496e69746961746554656c65706f72740c0118617373657473ad0301404d756c7469417373657446696c74657200011064657374050201344d756c74694c6f636174696f6e00010c78636d8903011c58636d3c28293e001100305175657279486f6c64696e6710012071756572795f696428011c5175657279496400011064657374050201344d756c74694c6f636174696f6e000118617373657473ad0301404d756c7469417373657446696c74657200014c6d61785f726573706f6e73655f77656967687428010c75363400120030427579457865637574696f6e08011066656573290201284d756c746941737365740001307765696768745f6c696d6974b903012c5765696768744c696d697400130034526566756e64537572706c75730014003c5365744572726f7248616e646c657204000904014058636d3c52756e74696d6543616c6c3e0015002c536574417070656e64697804000904014058636d3c52756e74696d6543616c6c3e00160028436c6561724572726f7200170028436c61696d41737365740801186173736574734502012c4d756c74694173736574730001187469636b6574050201344d756c74694c6f636174696f6e0018001054726170040028010c7536340019004053756273637269626556657273696f6e08012071756572795f696428011c5175657279496400014c6d61785f726573706f6e73655f77656967687428010c753634001a0048556e73756273637269626556657273696f6e001b000015040c2c73746167696e675f78636d38646f75626c655f656e636f64656434446f75626c65456e636f646564040454000004011c656e636f64656434011c5665633c75383e000019040c2c73746167696e675f78636d0876330c58636d041043616c6c000004001d0401585665633c496e737472756374696f6e3c43616c6c3e3e00001d0400000221040021040c2c73746167696e675f78636d0876332c496e737472756374696f6e041043616c6c0001c034576974686472617741737365740400c4012c4d756c7469417373657473000000545265736572766541737365744465706f73697465640400c4012c4d756c7469417373657473000100585265636569766554656c65706f7274656441737365740400c4012c4d756c7469417373657473000200345175657279526573706f6e736510012071756572795f696428011c51756572794964000120726573706f6e7365c9030120526573706f6e73650001286d61785f77656967687424011857656967687400011c71756572696572f10301544f7074696f6e3c4d756c74694c6f636174696f6e3e000300345472616e736665724173736574080118617373657473c4012c4d756c746941737365747300012c62656e6566696369617279d401344d756c74694c6f636174696f6e000400505472616e736665725265736572766541737365740c0118617373657473c4012c4d756c746941737365747300011064657374d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e000500205472616e736163740c012c6f726967696e5f6b696e64a50301284f726967696e4b696e64000158726571756972655f7765696768745f61745f6d6f737424011857656967687400011063616c6c1504014c446f75626c65456e636f6465643c43616c6c3e0006006448726d704e65774368616e6e656c4f70656e526571756573740c011873656e646572e0010c7533320001406d61785f6d6573736167655f73697a65e0010c7533320001306d61785f6361706163697479e0010c7533320007004c48726d704368616e6e656c4163636570746564040124726563697069656e74e0010c7533320008004848726d704368616e6e656c436c6f73696e670c0124696e69746961746f72e0010c75333200011873656e646572e0010c753332000124726563697069656e74e0010c7533320009002c436c6561724f726967696e000a003444657363656e644f726967696e0400d80154496e746572696f724d756c74694c6f636174696f6e000b002c5265706f72744572726f720400f50301445175657279526573706f6e7365496e666f000c00304465706f7369744173736574080118617373657473f90301404d756c7469417373657446696c74657200012c62656e6566696369617279d401344d756c74694c6f636174696f6e000d004c4465706f7369745265736572766541737365740c0118617373657473f90301404d756c7469417373657446696c74657200011064657374d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e000e003445786368616e676541737365740c011067697665f90301404d756c7469417373657446696c74657200011077616e74c4012c4d756c746941737365747300011c6d6178696d616c35010110626f6f6c000f005c496e6974696174655265736572766557697468647261770c0118617373657473f90301404d756c7469417373657446696c74657200011c72657365727665d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e00100040496e69746961746554656c65706f72740c0118617373657473f90301404d756c7469417373657446696c74657200011064657374d401344d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e001100345265706f7274486f6c64696e67080134726573706f6e73655f696e666ff50301445175657279526573706f6e7365496e666f000118617373657473f90301404d756c7469417373657446696c74657200120030427579457865637574696f6e08011066656573cc01284d756c746941737365740001307765696768745f6c696d69742102012c5765696768744c696d697400130034526566756e64537572706c75730014003c5365744572726f7248616e646c657204001904012458636d3c43616c6c3e0015002c536574417070656e64697804001904012458636d3c43616c6c3e00160028436c6561724572726f7200170028436c61696d4173736574080118617373657473c4012c4d756c74694173736574730001187469636b6574d401344d756c74694c6f636174696f6e0018001054726170040028010c7536340019004053756273637269626556657273696f6e08012071756572795f696428011c5175657279496400014c6d61785f726573706f6e73655f776569676874240118576569676874001a0048556e73756273637269626556657273696f6e001b00244275726e41737365740400c4012c4d756c7469417373657473001c002c45787065637441737365740400c4012c4d756c7469417373657473001d00304578706563744f726967696e0400f10301544f7074696f6e3c4d756c74694c6f636174696f6e3e001e002c4578706563744572726f720400cd0301504f7074696f6e3c287533322c204572726f72293e001f00504578706563745472616e736163745374617475730400e90301384d617962654572726f72436f64650020002c517565727950616c6c657408012c6d6f64756c655f6e616d6534011c5665633c75383e000134726573706f6e73655f696e666ff50301445175657279526573706f6e7365496e666f0021003045787065637450616c6c6574140114696e646578e0010c7533320001106e616d6534011c5665633c75383e00012c6d6f64756c655f6e616d6534011c5665633c75383e00012c63726174655f6d616a6f72e0010c75333200013c6d696e5f63726174655f6d696e6f72e0010c753332002200505265706f72745472616e736163745374617475730400f50301445175657279526573706f6e7365496e666f0023004c436c6561725472616e736163745374617475730024003c556e6976657273616c4f726967696e0400dc01204a756e6374696f6e002500344578706f72744d6573736167650c011c6e6574776f726be801244e6574776f726b496400012c64657374696e6174696f6ed80154496e746572696f724d756c74694c6f636174696f6e00010c78636dbd03011c58636d3c28293e002600244c6f636b41737365740801146173736574cc01284d756c74694173736574000120756e6c6f636b6572d401344d756c74694c6f636174696f6e0027002c556e6c6f636b41737365740801146173736574cc01284d756c74694173736574000118746172676574d401344d756c74694c6f636174696f6e002800384e6f7465556e6c6f636b61626c650801146173736574cc01284d756c746941737365740001146f776e6572d401344d756c74694c6f636174696f6e0029003452657175657374556e6c6f636b0801146173736574cc01284d756c746941737365740001186c6f636b6572d401344d756c74694c6f636174696f6e002a002c536574466565734d6f64650401306a69745f776974686472617735010110626f6f6c002b0020536574546f70696304000401205b75383b2033325d002c0028436c656172546f706963002d002c416c6961734f726967696e0400d401344d756c74694c6f636174696f6e002e003c556e70616964457865637574696f6e0801307765696768745f6c696d69742102012c5765696768744c696d6974000130636865636b5f6f726967696ef10301544f7074696f6e3c4d756c74694c6f636174696f6e3e002f000025040c4863756d756c75735f70616c6c65745f78636d1870616c6c65741043616c6c040454000100040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e29040c6063756d756c75735f70616c6c65745f646d705f71756575651870616c6c65741043616c6c04045400010448736572766963655f6f766572776569676874080114696e6465782c013c4f766572776569676874496e6465780001307765696768745f6c696d69742401185765696768740000048c536565205b6050616c6c65743a3a736572766963655f6f766572776569676874605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e2d040c4070616c6c65745f696e666c6174696f6e1870616c6c65741043616c6c0404540001043c73746172745f696e666c6174696f6e04016c696e666c6174696f6e5f73746172745f72656c61795f626c6f636b100144426c6f636b4e756d626572466f723c543e00000480536565205b6050616c6c65743a3a73746172745f696e666c6174696f6e605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e31040c3470616c6c65745f756e697175651870616c6c65741043616c6c040454000180446372656174655f636f6c6c656374696f6e10013c636f6c6c656374696f6e5f6e616d65350401d4426f756e6465645665633c7531362c20436f6e73745533323c4d41585f434f4c4c454354494f4e5f4e414d455f4c454e4754483e3e000158636f6c6c656374696f6e5f6465736372697074696f6e3d0401f0426f756e6465645665633c7531362c20436f6e73745533323c4d41585f434f4c4c454354494f4e5f4445534352495054494f4e5f4c454e4754483e3e000130746f6b656e5f707265666978410401c4426f756e6465645665633c75382c20436f6e73745533323c4d41585f544f4b454e5f5052454649585f4c454e4754483e3e0001106d6f646545040138436f6c6c656374696f6e4d6f646500000488536565205b6050616c6c65743a3a6372656174655f636f6c6c656374696f6e605d2e506372656174655f636f6c6c656374696f6e5f6578040110646174614904019c437265617465436f6c6c656374696f6e446174613c543a3a43726f73734163636f756e7449643e00010494536565205b6050616c6c65743a3a6372656174655f636f6c6c656374696f6e5f6578605d2e4864657374726f795f636f6c6c656374696f6e040134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640002048c536565205b6050616c6c65743a3a64657374726f795f636f6c6c656374696f6e605d2e446164645f746f5f616c6c6f775f6c697374080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c616464726573734d040144543a3a43726f73734163636f756e74496400030488536565205b6050616c6c65743a3a6164645f746f5f616c6c6f775f6c697374605d2e5872656d6f76655f66726f6d5f616c6c6f775f6c697374080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c616464726573734d040144543a3a43726f73734163636f756e7449640004049c536565205b6050616c6c65743a3a72656d6f76655f66726f6d5f616c6c6f775f6c697374605d2e5c6368616e67655f636f6c6c656374696f6e5f6f776e6572080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001246e65775f6f776e6572000130543a3a4163636f756e744964000504a0536565205b6050616c6c65743a3a6368616e67655f636f6c6c656374696f6e5f6f776e6572605d2e506164645f636f6c6c656374696f6e5f61646d696e080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001306e65775f61646d696e5f69644d040144543a3a43726f73734163636f756e74496400060494536565205b6050616c6c65743a3a6164645f636f6c6c656374696f6e5f61646d696e605d2e5c72656d6f76655f636f6c6c656374696f6e5f61646d696e080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001286163636f756e745f69644d040144543a3a43726f73734163636f756e744964000704a0536565205b6050616c6c65743a3a72656d6f76655f636f6c6c656374696f6e5f61646d696e605d2e587365745f636f6c6c656374696f6e5f73706f6e736f72080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400012c6e65775f73706f6e736f72000130543a3a4163636f756e7449640008049c536565205b6050616c6c65743a3a7365745f636f6c6c656374696f6e5f73706f6e736f72605d2e4c636f6e6669726d5f73706f6e736f7273686970040134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400090490536565205b6050616c6c65743a3a636f6e6669726d5f73706f6e736f7273686970605d2e6472656d6f76655f636f6c6c656374696f6e5f73706f6e736f72040134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e4964000a04a8536565205b6050616c6c65743a3a72656d6f76655f636f6c6c656374696f6e5f73706f6e736f72605d2e2c6372656174655f6974656d0c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001146f776e65724d040144543a3a43726f73734163636f756e74496400011064617461c10401384372656174654974656d44617461000b0470536565205b6050616c6c65743a3a6372656174655f6974656d605d2e546372656174655f6d756c7469706c655f6974656d730c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001146f776e65724d040144543a3a43726f73734163636f756e7449640001286974656d735f64617461d104014c5665633c4372656174654974656d446174613e000c0498536565205b6050616c6c65743a3a6372656174655f6d756c7469706c655f6974656d73605d2e647365745f636f6c6c656374696f6e5f70726f70657274696573080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400012870726f70657274696573b50401345665633c50726f70657274793e000d04a8536565205b6050616c6c65743a3a7365745f636f6c6c656374696f6e5f70726f70657274696573605d2e7064656c6574655f636f6c6c656374696f6e5f70726f70657274696573080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400013470726f70657274795f6b657973d50401405665633c50726f70657274794b65793e000e04b4536565205b6050616c6c65743a3a64656c6574655f636f6c6c656374696f6e5f70726f70657274696573605d2e507365745f746f6b656e5f70726f706572746965730c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e4964000120746f6b656e5f6964d904011c546f6b656e496400012870726f70657274696573b50401345665633c50726f70657274793e000f0494536565205b6050616c6c65743a3a7365745f746f6b656e5f70726f70657274696573605d2e5c64656c6574655f746f6b656e5f70726f706572746965730c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e4964000120746f6b656e5f6964d904011c546f6b656e496400013470726f70657274795f6b657973d50401405665633c50726f70657274794b65793e001004a0536565205b6050616c6c65743a3a64656c6574655f746f6b656e5f70726f70657274696573605d2e787365745f746f6b656e5f70726f70657274795f7065726d697373696f6e73080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400015070726f70657274795f7065726d697373696f6e73a50401685665633c50726f70657274794b65795065726d697373696f6e3e001104bc536565205b6050616c6c65743a3a7365745f746f6b656e5f70726f70657274795f7065726d697373696f6e73605d2e606372656174655f6d756c7469706c655f6974656d735f6578080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011064617461dd04018c4372656174654974656d4578446174613c543a3a43726f73734163636f756e7449643e001204a4536565205b6050616c6c65743a3a6372656174655f6d756c7469706c655f6974656d735f6578605d2e687365745f7472616e73666572735f656e61626c65645f666c6167080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011476616c756535010110626f6f6c001304ac536565205b6050616c6c65743a3a7365745f7472616e73666572735f656e61626c65645f666c6167605d2e246275726e5f6974656d0c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c6974656d5f6964d904011c546f6b656e496400011476616c75651801107531323800140468536565205b6050616c6c65743a3a6275726e5f6974656d605d2e246275726e5f66726f6d100134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011066726f6d4d040144543a3a43726f73734163636f756e74496400011c6974656d5f6964d904011c546f6b656e496400011476616c75651801107531323800150468536565205b6050616c6c65743a3a6275726e5f66726f6d605d2e207472616e73666572100124726563697069656e744d040144543a3a43726f73734163636f756e744964000134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c6974656d5f6964d904011c546f6b656e496400011476616c75651801107531323800160464536565205b6050616c6c65743a3a7472616e73666572605d2e1c617070726f766510011c7370656e6465724d040144543a3a43726f73734163636f756e744964000134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c6974656d5f6964d904011c546f6b656e4964000118616d6f756e741801107531323800170460536565205b6050616c6c65743a3a617070726f7665605d2e30617070726f76655f66726f6d14011066726f6d4d040144543a3a43726f73734163636f756e744964000108746f4d040144543a3a43726f73734163636f756e744964000134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c6974656d5f6964d904011c546f6b656e4964000118616d6f756e741801107531323800180474536565205b6050616c6c65743a3a617070726f76655f66726f6d605d2e347472616e736665725f66726f6d14011066726f6d4d040144543a3a43726f73734163636f756e744964000124726563697069656e744d040144543a3a43726f73734163636f756e744964000134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c6974656d5f6964d904011c546f6b656e496400011476616c75651801107531323800190478536565205b6050616c6c65743a3a7472616e736665725f66726f6d605d2e547365745f636f6c6c656374696f6e5f6c696d697473080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001246e65775f6c696d69745d040140436f6c6c656374696f6e4c696d697473001a0498536565205b6050616c6c65743a3a7365745f636f6c6c656374696f6e5f6c696d697473605d2e687365745f636f6c6c656374696f6e5f7065726d697373696f6e73080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001386e65775f7065726d697373696f6e71040154436f6c6c656374696f6e5065726d697373696f6e73001b04ac536565205b6050616c6c65743a3a7365745f636f6c6c656374696f6e5f7065726d697373696f6e73605d2e2c7265706172746974696f6e0c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e4964000120746f6b656e5f6964d904011c546f6b656e4964000118616d6f756e7418011075313238001c0470536565205b6050616c6c65743a3a7265706172746974696f6e605d2e547365745f616c6c6f77616e63655f666f725f616c6c0c0134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640001206f70657261746f724d040144543a3a43726f73734163636f756e74496400011c617070726f766535010110626f6f6c001d0498536565205b6050616c6c65743a3a7365745f616c6c6f77616e63655f666f725f616c6c605d2e5c666f7263655f7265706169725f636f6c6c656374696f6e040134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e4964001e04a0536565205b6050616c6c65743a3a666f7263655f7265706169725f636f6c6c656374696f6e605d2e44666f7263655f7265706169725f6974656d080134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e496400011c6974656d5f6964d904011c546f6b656e4964001f0488536565205b6050616c6c65743a3a666f7263655f7265706169725f6974656d605d2e04d85479706520616c69617320746f2050616c6c65742c20746f206265207573656420627920636f6e7374727563745f72756e74696d652e35040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454014901045300000400390401185665633c543e000039040000024901003d040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454014901045300000400390401185665633c543e000041040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e00004504083c75705f646174615f7374727563747338436f6c6c656374696f6e4d6f646500010c0c4e46540000002046756e6769626c650400080134446563696d616c506f696e747300010028526546756e6769626c65000200004904083c75705f646174615f7374727563747350437265617465436f6c6c656374696f6e44617461043843726f73734163636f756e744964014d04003001106d6f646545040138436f6c6c656374696f6e4d6f6465000118616363657373510401484f7074696f6e3c4163636573734d6f64653e0001106e616d6535040138436f6c6c656374696f6e4e616d6500012c6465736372697074696f6e3d040154436f6c6c656374696f6e4465736372697074696f6e000130746f6b656e5f70726566697841040154436f6c6c656374696f6e546f6b656e5072656669780001186c696d697473590401604f7074696f6e3c436f6c6c656374696f6e4c696d6974733e00012c7065726d697373696f6e736d0401744f7074696f6e3c436f6c6c656374696f6e5065726d697373696f6e733e000168746f6b656e5f70726f70657274795f7065726d697373696f6e7395040188436f6c6c656374696f6e50726f706572746965735065726d697373696f6e7356656300012870726f70657274696573a904015c436f6c6c656374696f6e50726f7065727469657356656300012861646d696e5f6c697374b904014c5665633c43726f73734163636f756e7449643e00013c70656e64696e675f73706f6e736f72bd0401584f7074696f6e3c43726f73734163636f756e7449643e000114666c6167736902013c436f6c6c656374696f6e466c61677300004d040c2870616c6c65745f65766d1c6163636f756e745c426173696343726f73734163636f756e7449645265707204244163636f756e744964010001082453756273747261746504000001244163636f756e74496400000020457468657265756d0400650301104831363000010000510404184f7074696f6e0404540155040108104e6f6e6500000010536f6d650400550400000100005504083c75705f646174615f73747275637473284163636573734d6f6465000108184e6f726d616c00000024416c6c6f774c69737400010000590404184f7074696f6e040454015d040108104e6f6e6500000010536f6d6504005d0400000100005d04083c75705f646174615f7374727563747340436f6c6c656374696f6e4c696d69747300002401746163636f756e745f746f6b656e5f6f776e6572736869705f6c696d69742503012c4f7074696f6e3c7533323e00014c73706f6e736f7265645f646174615f73697a652503012c4f7074696f6e3c7533323e00016473706f6e736f7265645f646174615f726174655f6c696d69746104016c4f7074696f6e3c53706f6e736f72696e67526174654c696d69743e00012c746f6b656e5f6c696d69742503012c4f7074696f6e3c7533323e00016073706f6e736f725f7472616e736665725f74696d656f75742503012c4f7074696f6e3c7533323e00015c73706f6e736f725f617070726f76655f74696d656f75742503012c4f7074696f6e3c7533323e0001486f776e65725f63616e5f7472616e73666572690401304f7074696f6e3c626f6f6c3e0001446f776e65725f63616e5f64657374726f79690401304f7074696f6e3c626f6f6c3e0001447472616e73666572735f656e61626c6564690401304f7074696f6e3c626f6f6c3e0000610404184f7074696f6e0404540165040108104e6f6e6500000010536f6d650400650400000100006504083c75705f646174615f737472756374734c53706f6e736f72696e67526174654c696d69740001084853706f6e736f72696e6744697361626c656400000018426c6f636b73040010010c75333200010000690404184f7074696f6e0404540135010108104e6f6e6500000010536f6d650400350100000100006d0404184f7074696f6e0404540171040108104e6f6e6500000010536f6d650400710400000100007104083c75705f646174615f7374727563747354436f6c6c656374696f6e5065726d697373696f6e7300000c0118616363657373510401484f7074696f6e3c4163636573734d6f64653e0001246d696e745f6d6f6465690401304f7074696f6e3c626f6f6c3e00011c6e657374696e67750401684f7074696f6e3c4e657374696e675065726d697373696f6e733e0000750404184f7074696f6e0404540179040108104e6f6e6500000010536f6d650400790400000100007904083c75705f646174615f73747275637473484e657374696e675065726d697373696f6e7300000c012c746f6b656e5f6f776e657235010110626f6f6c000140636f6c6c656374696f6e5f61646d696e35010110626f6f6c000128726573747269637465647d0401684f7074696f6e3c4f776e6572526573747269637465645365743e00007d0404184f7074696f6e0404540181040108104e6f6e6500000010536f6d650400810400000100008104083c75705f646174615f73747275637473484f776e657252657374726963746564536574000004008504015c4f776e657252657374726963746564536574496e6e6572000085040c4c626f756e6465645f636f6c6c656374696f6e7344626f756e6465645f62747265655f7365743c426f756e64656442547265655365740804540189040453000004008d04012c42547265655365743c543e00008904083c75705f646174615f7374727563747330436f6c6c656374696f6e49640000040010010c75333200008d04042042547265655365740404540189040004009104000000910400000289040095040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454019904045300000400a50401185665633c543e00009904083c75705f646174615f737472756374735450726f70657274794b65795065726d697373696f6e000008010c6b65799d04012c50726f70657274794b65790001287065726d697373696f6ea104014850726f70657274795065726d697373696f6e00009d040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000a104083c75705f646174615f737472756374734850726f70657274795065726d697373696f6e00000c011c6d757461626c6535010110626f6f6c000140636f6c6c656374696f6e5f61646d696e35010110626f6f6c00012c746f6b656e5f6f776e657235010110626f6f6c0000a504000002990400a9040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401ad04045300000400b50401185665633c543e0000ad04083c75705f646174615f737472756374732050726f7065727479000008010c6b65799d04012c50726f70657274794b657900011476616c7565b104013450726f706572747956616c75650000b1040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000b504000002ad0400b9040000024d0400bd0404184f7074696f6e040454014d040108104e6f6e6500000010536f6d6504004d040000010000c104083c75705f646174615f73747275637473384372656174654974656d4461746100010c0c4e46540400c50401344372656174654e6674446174610000002046756e6769626c650400c904014843726561746546756e6769626c654461746100010028526546756e6769626c650400cd040150437265617465526546756e6769626c654461746100020000c504083c75705f646174615f73747275637473344372656174654e667444617461000004012870726f70657274696573a904015c436f6c6c656374696f6e50726f706572746965735665630000c904083c75705f646174615f737472756374734843726561746546756e6769626c6544617461000004011476616c7565180110753132380000cd04083c75705f646174615f7374727563747350437265617465526546756e6769626c654461746100000801187069656365731801107531323800012870726f70657274696573a904015c436f6c6c656374696f6e50726f706572746965735665630000d104000002c10400d5040000029d0400d904083c75705f646174615f737472756374731c546f6b656e49640000040010010c7533320000dd04083c75705f646174615f73747275637473404372656174654974656d457844617461043843726f73734163636f756e744964014d0401100c4e46540400e104012d01426f756e6465645665633c4372656174654e66744578446174613c43726f73734163636f756e7449643e2c20436f6e73745533323c0a4d41585f4954454d535f5045525f42415443483e3e0000002046756e6769626c650400ed04011101426f756e64656442547265654d61703c43726f73734163636f756e7449642c20753132382c20436f6e73745533323c4d41585f4954454d535f5045525f42415443483e3e0001005c526566756e6769626c654d756c7469706c654974656d730400fd04016501426f756e6465645665633c437265617465526566756e6769626c65457853696e676c654f776e65723c43726f73734163636f756e7449643e2c20436f6e73745533323c0a4d41585f4954454d535f5045525f42415443483e3e00020060526566756e6769626c654d756c7469706c654f776e6572730400090501c0437265617465526566756e6769626c6545784d756c7469706c654f776e6572733c43726f73734163636f756e7449643e00030000e1040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401e504045300000400e90401185665633c543e0000e504083c75705f646174615f737472756374733c4372656174654e6674457844617461043843726f73734163636f756e744964014d040008012870726f70657274696573a904015c436f6c6c656374696f6e50726f706572746965735665630001146f776e65724d04013843726f73734163636f756e7449640000e904000002e50400ed040c4c626f756e6465645f636f6c6c656374696f6e7344626f756e6465645f62747265655f6d61703c426f756e64656442547265654d61700c044b014d0404560118045300000400f104013842547265654d61703c4b2c20563e0000f104042042547265654d617008044b014d0404560118000400f504000000f504000002f90400f904000004084d041800fd040c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454010105045300000400050501185665633c543e00000105083c75705f646174615f7374727563747374437265617465526566756e6769626c65457853696e676c654f776e6572043843726f73734163636f756e744964014d04000c0110757365724d04013843726f73734163636f756e7449640001187069656365731801107531323800012870726f70657274696573a904015c436f6c6c656374696f6e50726f70657274696573566563000005050000020105000905083c75705f646174615f7374727563747380437265617465526566756e6769626c6545784d756c7469706c654f776e657273043843726f73734163636f756e744964014d04000801147573657273ed04011101426f756e64656442547265654d61703c43726f73734163636f756e7449642c20753132382c20436f6e73745533323c4d41585f4954454d535f5045525f42415443483e3e00012870726f70657274696573a904015c436f6c6c656374696f6e50726f7065727469657356656300000d050c5070616c6c65745f636f6e66696775726174696f6e1870616c6c65741043616c6c040454000118987365745f7765696768745f746f5f6665655f636f656666696369656e745f6f76657272696465040114636f6566661105012c4f7074696f6e3c7536343e000004dc536565205b6050616c6c65743a3a7365745f7765696768745f746f5f6665655f636f656666696369656e745f6f76657272696465605d2e687365745f6d696e5f6761735f70726963655f6f76657272696465040114636f6566661105012c4f7074696f6e3c7536343e000104ac536565205b6050616c6c65743a3a7365745f6d696e5f6761735f70726963655f6f76657272696465605d2ea07365745f6170705f70726f6d6f74696f6e5f636f6e66696775726174696f6e5f6f76657272696465040134636f6e66696775726174696f6e150501b041707050726f6d6f74696f6e436f6e66696775726174696f6e3c426c6f636b4e756d626572466f723c543e3e000304e4536565205b6050616c6c65743a3a7365745f6170705f70726f6d6f74696f6e5f636f6e66696775726174696f6e5f6f76657272696465605d2ea07365745f636f6c6c61746f725f73656c656374696f6e5f646573697265645f636f6c6c61746f727304010c6d61782503012c4f7074696f6e3c7533323e000404e4536565205b6050616c6c65743a3a7365745f636f6c6c61746f725f73656c656374696f6e5f646573697265645f636f6c6c61746f7273605d2e8c7365745f636f6c6c61746f725f73656c656374696f6e5f6c6963656e73655f626f6e64040118616d6f756e74250501784f7074696f6e3c3c5420617320436f6e6669673e3a3a42616c616e63653e000504d0536565205b6050616c6c65743a3a7365745f636f6c6c61746f725f73656c656374696f6e5f6c6963656e73655f626f6e64605d2e947365745f636f6c6c61746f725f73656c656374696f6e5f6b69636b5f7468726573686f6c640401247468726573686f6c64250301644f7074696f6e3c426c6f636b4e756d626572466f723c543e3e000604d8536565205b6050616c6c65743a3a7365745f636f6c6c61746f725f73656c656374696f6e5f6b69636b5f7468726573686f6c64605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e110504184f7074696f6e040454012c0108104e6f6e6500000010536f6d6504002c00000100001505085070616c6c65745f636f6e66696775726174696f6e6441707050726f6d6f74696f6e436f6e66696775726174696f6e042c426c6f636b4e756d626572011000100158726563616c63756c6174696f6e5f696e74657276616c2503014c4f7074696f6e3c426c6f636b4e756d6265723e00014070656e64696e675f696e74657276616c2503014c4f7074696f6e3c426c6f636b4e756d6265723e00013c696e74657276616c5f696e636f6d651905013c4f7074696f6e3c50657262696c6c3e00016c6d61785f7374616b6572735f7065725f63616c63756c6174696f6e210501284f7074696f6e3c75383e0000190504184f7074696f6e040454011d050108104e6f6e6500000010536f6d6504001d0500000100001d050c3473705f61726974686d65746963287065725f7468696e67731c50657262696c6c0000040010010c7533320000210504184f7074696f6e04045401080108104e6f6e6500000010536f6d650400080000010000250504184f7074696f6e04045401180108104e6f6e6500000010536f6d65040018000001000029050c4070616c6c65745f7374727563747572651870616c6c65741043616c6c040454000100040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e2d050c5070616c6c65745f6170705f70726f6d6f74696f6e1870616c6c65741043616c6c040454000128447365745f61646d696e5f6164647265737304011461646d696e4d040144543a3a43726f73734163636f756e74496400000488536565205b6050616c6c65743a3a7365745f61646d696e5f61646472657373605d2e147374616b65040118616d6f756e7418013042616c616e63654f663c543e00010458536565205b6050616c6c65743a3a7374616b65605d2e2c756e7374616b655f616c6c00020470536565205b6050616c6c65743a3a756e7374616b655f616c6c605d2e3c756e7374616b655f7061727469616c040118616d6f756e7418013042616c616e63654f663c543e00080480536565205b6050616c6c65743a3a756e7374616b655f7061727469616c605d2e4873706f6e736f725f636f6c6c656374696f6e040134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e49640003048c536565205b6050616c6c65743a3a73706f6e736f725f636f6c6c656374696f6e605d2e6873746f705f73706f6e736f72696e675f636f6c6c656374696f6e040134636f6c6c656374696f6e5f696489040130436f6c6c656374696f6e4964000404ac536565205b6050616c6c65743a3a73746f705f73706f6e736f72696e675f636f6c6c656374696f6e605d2e4073706f6e736f725f636f6e747261637404012c636f6e74726163745f6964650301104831363000050484536565205b6050616c6c65743a3a73706f6e736f725f636f6e7472616374605d2e6073746f705f73706f6e736f72696e675f636f6e747261637404012c636f6e74726163745f69646503011048313630000604a4536565205b6050616c6c65743a3a73746f705f73706f6e736f72696e675f636f6e7472616374605d2e387061796f75745f7374616b6572730401387374616b6572735f6e756d626572210501284f7074696f6e3c75383e0007047c536565205b6050616c6c65743a3a7061796f75745f7374616b657273605d2e34666f7263655f756e7374616b6504013870656e64696e675f626c6f636b73310501585665633c426c6f636b4e756d626572466f723c543e3e00090478536565205b6050616c6c65743a3a666f7263655f756e7374616b65605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e3105000002100035050c5470616c6c65745f666f726569676e5f617373657473186d6f64756c651043616c6c0404540001085872656769737465725f666f726569676e5f61737365740c01146f776e6572000130543a3a4163636f756e7449640001206c6f636174696f6e0102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e0001206d6574616461746139050180426f783c41737365744d657461646174613c42616c616e63654f663c543e3e3e0000049c536565205b6050616c6c65743a3a72656769737465725f666f726569676e5f6173736574605d2e507570646174655f666f726569676e5f61737365740c0140666f726569676e5f61737365745f6964100138466f726569676e417373657449640001206c6f636174696f6e0102016c426f783c56657273696f6e65644d756c74694c6f636174696f6e3e0001206d6574616461746139050180426f783c41737365744d657461646174613c42616c616e63654f663c543e3e3e00010494536565205b6050616c6c65743a3a7570646174655f666f726569676e5f6173736574605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e39050c5470616c6c65745f666f726569676e5f617373657473186d6f64756c653441737365744d65746164617461041c42616c616e63650118001001106e616d653d05012441737365744e616d6500011873796d626f6c4105012c417373657453796d626f6c000120646563696d616c73080108753800013c6d696e696d616c5f62616c616e636518011c42616c616e636500003d050c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e000041050c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e000045050c2870616c6c65745f65766d1870616c6c65741043616c6c04045400011020776974686472617708011c61646472657373650301104831363000011476616c756518013042616c616e63654f663c543e00000464536565205b6050616c6c65743a3a7769746864726177605d2e1063616c6c240118736f7572636565030110483136300001187461726765746503011048313630000114696e70757434011c5665633c75383e00011476616c756549050110553235360001246761735f6c696d69742c010c75363400013c6d61785f6665655f7065725f67617349050110553235360001606d61785f7072696f726974795f6665655f7065725f676173510501304f7074696f6e3c553235363e0001146e6f6e6365510501304f7074696f6e3c553235363e00012c6163636573735f6c697374550501585665633c28483136302c205665633c483235363e293e00010454536565205b6050616c6c65743a3a63616c6c605d2e18637265617465200118736f757263656503011048313630000110696e697434011c5665633c75383e00011476616c756549050110553235360001246761735f6c696d69742c010c75363400013c6d61785f6665655f7065725f67617349050110553235360001606d61785f7072696f726974795f6665655f7065725f676173510501304f7074696f6e3c553235363e0001146e6f6e6365510501304f7074696f6e3c553235363e00012c6163636573735f6c697374550501585665633c28483136302c205665633c483235363e293e0002045c536565205b6050616c6c65743a3a637265617465605d2e1c63726561746532240118736f757263656503011048313630000110696e697434011c5665633c75383e00011073616c743001104832353600011476616c756549050110553235360001246761735f6c696d69742c010c75363400013c6d61785f6665655f7065725f67617349050110553235360001606d61785f7072696f726974795f6665655f7065725f676173510501304f7074696f6e3c553235363e0001146e6f6e6365510501304f7074696f6e3c553235363e00012c6163636573735f6c697374550501585665633c28483136302c205665633c483235363e293e00030460536565205b6050616c6c65743a3a63726561746532605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e4905083c7072696d69746976655f74797065731055323536000004004d0501205b7536343b20345d00004d05000003040000002c00510504184f7074696f6e0404540149050108104e6f6e6500000010536f6d65040049050000010000550500000259050059050000040865035d05005d05000002300061050c3c70616c6c65745f657468657265756d1870616c6c65741043616c6c040454000104207472616e7361637404012c7472616e73616374696f6e6505012c5472616e73616374696f6e00000464536565205b6050616c6c65743a3a7472616e73616374605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e65050c20657468657265756d2c7472616e73616374696f6e345472616e73616374696f6e563200010c184c65676163790400690501444c65676163795472616e73616374696f6e0000001c45495032393330040079050148454950323933305472616e73616374696f6e0001001c45495031353539040085050148454950313535395472616e73616374696f6e0002000069050c20657468657265756d2c7472616e73616374696f6e444c65676163795472616e73616374696f6e00001c01146e6f6e636549050110553235360001246761735f707269636549050110553235360001246761735f6c696d69744905011055323536000118616374696f6e6d0501445472616e73616374696f6e416374696f6e00011476616c75654905011055323536000114696e70757434011442797465730001247369676e6174757265710501505472616e73616374696f6e5369676e617475726500006d050c20657468657265756d2c7472616e73616374696f6e445472616e73616374696f6e416374696f6e0001081043616c6c04006503011048313630000000184372656174650001000071050c20657468657265756d2c7472616e73616374696f6e505472616e73616374696f6e5369676e617475726500000c010476750501545472616e73616374696f6e5265636f76657279496400010472300110483235360001047330011048323536000075050c20657468657265756d2c7472616e73616374696f6e545472616e73616374696f6e5265636f766572794964000004002c010c753634000079050c20657468657265756d2c7472616e73616374696f6e48454950323933305472616e73616374696f6e00002c0120636861696e5f69642c010c7536340001146e6f6e636549050110553235360001246761735f707269636549050110553235360001246761735f6c696d69744905011055323536000118616374696f6e6d0501445472616e73616374696f6e416374696f6e00011476616c75654905011055323536000114696e707574340114427974657300012c6163636573735f6c6973747d0501284163636573734c6973740001306f64645f795f70617269747935010110626f6f6c0001047230011048323536000104733001104832353600007d0500000281050081050c20657468657265756d2c7472616e73616374696f6e384163636573734c6973744974656d000008011c616464726573736503011c4164647265737300013073746f726167655f6b6579735d0501245665633c483235363e000085050c20657468657265756d2c7472616e73616374696f6e48454950313535395472616e73616374696f6e0000300120636861696e5f69642c010c7536340001146e6f6e636549050110553235360001606d61785f7072696f726974795f6665655f7065725f676173490501105532353600013c6d61785f6665655f7065725f67617349050110553235360001246761735f6c696d69744905011055323536000118616374696f6e6d0501445472616e73616374696f6e416374696f6e00011476616c75654905011055323536000114696e707574340114427974657300012c6163636573735f6c6973747d0501284163636573734c6973740001306f64645f795f70617269747935010110626f6f6c00010472300110483235360001047330011048323536000089050c6c70616c6c65745f65766d5f636f6e74726163745f68656c706572731870616c6c65741043616c6c040454000104706d6967726174655f66726f6d5f73656c665f73706f6e736f72696e670401246164647265737365738d0501245665633c483136303e000004b4536565205b6050616c6c65743a3a6d6967726174655f66726f6d5f73656c665f73706f6e736f72696e67605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e8d0500000265030091050c5070616c6c65745f65766d5f6d6967726174696f6e1870616c6c65741043616c6c04045400011814626567696e04011c61646472657373650301104831363000000458536565205b6050616c6c65743a3a626567696e605d2e207365745f6461746108011c61646472657373650301104831363000011064617461950501445665633c28483235362c2048323536293e00010464536565205b6050616c6c65743a3a7365745f64617461605d2e1866696e69736808011c616464726573736503011048313630000110636f646534011c5665633c75383e0002045c536565205b6050616c6c65743a3a66696e697368605d2e3c696e736572745f6574685f6c6f67730401106c6f67739d0501485665633c657468657265756d3a3a4c6f673e00030480536565205b6050616c6c65743a3a696e736572745f6574685f6c6f6773605d2e34696e736572745f6576656e74730401186576656e74736d0101305665633c5665633c75383e3e00040478536565205b6050616c6c65743a3a696e736572745f6576656e7473605d2e4072656d6f76655f726d726b5f6461746100050484536565205b6050616c6c65743a3a72656d6f76655f726d726b5f64617461605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e95050000029905009905000004083030009d05000002a10500a1050c20657468657265756d0c6c6f670c4c6f6700000c011c616464726573736503011048313630000118746f706963735d0501245665633c483235363e0001106461746134011442797465730000a5050c4870616c6c65745f6d61696e74656e616e63651870616c6c65741043616c6c04045400010818656e61626c650000045c536565205b6050616c6c65743a3a656e61626c65605d2e1c64697361626c6500010460536565205b6050616c6c65743a3a64697361626c65605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ea9050c3870616c6c65745f7574696c6974791870616c6c65741043616c6c04045400011814626174636804011463616c6c73ad05017c5665633c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00000458536565205b6050616c6c65743a3a6261746368605d2e3461735f64657269766174697665080114696e6465784901010c75313600011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00010478536565205b6050616c6c65743a3a61735f64657269766174697665605d2e2462617463685f616c6c04011463616c6c73ad05017c5665633c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00020468536565205b6050616c6c65743a3a62617463685f616c6c605d2e2c64697370617463685f617308012461735f6f726967696e45030154426f783c543a3a50616c6c6574734f726967696e3e00011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00030470536565205b6050616c6c65743a3a64697370617463685f6173605d2e2c666f7263655f626174636804011463616c6c73ad05017c5665633c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00040470536565205b6050616c6c65743a3a666f7263655f6261746368605d2e2c776974685f77656967687408011063616c6c5d01017c426f783c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00011877656967687424011857656967687400050470536565205b6050616c6c65743a3a776974685f776569676874605d2e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732ead050000025d0100b1050c4470616c6c65745f746573745f7574696c731870616c6c65741043616c6c04045400011818656e61626c6500000454536565206050616c6c65743a3a656e61626c65602e387365745f746573745f76616c756504011476616c756510010c75333200010474536565206050616c6c65743a3a7365745f746573745f76616c7565602e6c7365745f746573745f76616c75655f616e645f726f6c6c6261636b04011476616c756510010c753332000204a8536565206050616c6c65743a3a7365745f746573745f76616c75655f616e645f726f6c6c6261636b602e38696e635f746573745f76616c756500030474536565206050616c6c65743a3a696e635f746573745f76616c7565602e346a7573745f74616b655f66656500040470536565206050616c6c65743a3a6a7573745f74616b655f666565602e2462617463685f616c6c04011463616c6c73ad05017c5665633c3c5420617320436f6e6669673e3a3a52756e74696d6543616c6c3e00050460536565206050616c6c65743a3a62617463685f616c6c602e040d01436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732eb5050c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000b9050c4070616c6c65745f7363686564756c65721870616c6c6574144576656e74040454000118245363686564756c65640801107768656e100144426c6f636b4e756d626572466f723c543e000114696e64657810010c753332000004505363686564756c656420736f6d65207461736b2e2043616e63656c65640801107768656e100144426c6f636b4e756d626572466f723c543e000114696e64657810010c7533320001044c43616e63656c656420736f6d65207461736b2e28446973706174636865640c01107461736b790301785461736b416464726573733c426c6f636b4e756d626572466f723c543e3e00010869648801404f7074696f6e3c5461736b4e616d653e000118726573756c74a801384469737061746368526573756c74000204544469737061746368656420736f6d65207461736b2e3c43616c6c556e617661696c61626c650801107461736b790301785461736b416464726573733c426c6f636b4e756d626572466f723c543e3e00010869648801404f7074696f6e3c5461736b4e616d653e00030429015468652063616c6c20666f72207468652070726f7669646564206861736820776173206e6f7420666f756e6420736f20746865207461736b20686173206265656e2061626f727465642e38506572696f6469634661696c65640801107461736b790301785461736b416464726573733c426c6f636b4e756d626572466f723c543e3e00010869648801404f7074696f6e3c5461736b4e616d653e0004043d0154686520676976656e207461736b2077617320756e61626c6520746f2062652072656e657765642073696e636520746865206167656e64612069732066756c6c206174207468617420626c6f636b2e545065726d616e656e746c794f7665727765696768740801107461736b790301785461736b416464726573733c426c6f636b4e756d626572466f723c543e3e00010869648801404f7074696f6e3c5461736b4e616d653e000504f054686520676976656e207461736b2063616e206e657665722062652065786563757465642073696e6365206974206973206f7665727765696768742e04304576656e747320747970652ebd050c6463756d756c75735f70616c6c65745f78636d705f71756575651870616c6c6574144576656e7404045400011c1c537563636573730c01306d6573736167655f6861736804011c58636d486173680001286d6573736167655f696404011c58636d4861736800011877656967687424011857656967687400000464536f6d652058434d20776173206578656375746564206f6b2e104661696c1001306d6573736167655f6861736804011c58636d486173680001286d6573736167655f696404011c58636d486173680001146572726f72d503012058636d4572726f7200011877656967687424011857656967687400010440536f6d652058434d206661696c65642e2842616456657273696f6e0401306d6573736167655f6861736804011c58636d48617368000204544261642058434d2076657273696f6e20757365642e24426164466f726d61740401306d6573736167655f6861736804011c58636d48617368000304504261642058434d20666f726d617420757365642e3c58636d704d65737361676553656e740401306d6573736167655f6861736804011c58636d48617368000404c0416e2048524d50206d657373616765207761732073656e7420746f2061207369626c696e672070617261636861696e2e484f766572776569676874456e71756575656410011873656e646572ad01011850617261496400011c73656e745f617410014052656c6179426c6f636b4e756d626572000114696e6465782c013c4f766572776569676874496e6465780001207265717569726564240118576569676874000504d4416e2058434d2065786365656465642074686520696e646976696475616c206d65737361676520776569676874206275646765742e484f7665727765696768745365727669636564080114696e6465782c013c4f766572776569676874496e646578000110757365642401185765696768740006044101416e2058434d2066726f6d20746865206f7665727765696768742071756575652077617320657865637574656420776974682074686520676976656e2061637475616c2077656967687420757365642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574c1050c2870616c6c65745f78636d1870616c6c6574144576656e7404045400015c24417474656d7074656404011c6f7574636f6d65c505015078636d3a3a6c61746573743a3a4f7574636f6d65000004a8457865637574696f6e206f6620616e2058434d206d6573736167652077617320617474656d707465642e1053656e741001186f726967696ed401344d756c74694c6f636174696f6e00012c64657374696e6174696f6ed401344d756c74694c6f636174696f6e00011c6d657373616765bd03011c58636d3c28293e0001286d6573736167655f696404011c58636d486173680001045c412058434d206d657373616765207761732073656e742e48556e6578706563746564526573706f6e73650801186f726967696ed401344d756c74694c6f636174696f6e00012071756572795f69642c011c5175657279496400020c5901517565727920726573706f6e736520726563656976656420776869636820646f6573206e6f74206d61746368206120726567697374657265642071756572792e2054686973206d61792062652062656361757365206155016d61746368696e6720717565727920776173206e6576657220726567697374657265642c206974206d617920626520626563617573652069742069732061206475706c696361746520726573706f6e73652c206f727062656361757365207468652071756572792074696d6564206f75742e34526573706f6e7365526561647908012071756572795f69642c011c51756572794964000120726573706f6e7365c9030120526573706f6e73650003085d01517565727920726573706f6e736520686173206265656e20726563656976656420616e6420697320726561647920666f722074616b696e672077697468206074616b655f726573706f6e7365602e205468657265206973806e6f2072656769737465726564206e6f74696669636174696f6e2063616c6c2e204e6f7469666965640c012071756572795f69642c011c5175657279496400013070616c6c65745f696e646578080108753800012863616c6c5f696e64657808010875380004085901517565727920726573706f6e736520686173206265656e20726563656976656420616e642071756572792069732072656d6f7665642e205468652072656769737465726564206e6f74696669636174696f6e20686173a86265656e206469737061746368656420616e64206578656375746564207375636365737366756c6c792e404e6f746966794f76657277656967687414012071756572795f69642c011c5175657279496400013070616c6c65745f696e646578080108753800012863616c6c5f696e646578080108753800013461637475616c5f77656967687424011857656967687400014c6d61785f62756467657465645f77656967687424011857656967687400050c4901517565727920726573706f6e736520686173206265656e20726563656976656420616e642071756572792069732072656d6f7665642e205468652072656769737465726564206e6f74696669636174696f6e5901636f756c64206e6f742062652064697370617463686564206265636175736520746865206469737061746368207765696768742069732067726561746572207468616e20746865206d6178696d756d20776569676874e46f726967696e616c6c7920627564676574656420627920746869732072756e74696d6520666f722074686520717565727920726573756c742e4c4e6f7469667944697370617463684572726f720c012071756572795f69642c011c5175657279496400013070616c6c65745f696e646578080108753800012863616c6c5f696e64657808010875380006085501517565727920726573706f6e736520686173206265656e20726563656976656420616e642071756572792069732072656d6f7665642e2054686572652077617320612067656e6572616c206572726f722077697468886469737061746368696e6720746865206e6f74696669636174696f6e2063616c6c2e484e6f746966794465636f64654661696c65640c012071756572795f69642c011c5175657279496400013070616c6c65745f696e646578080108753800012863616c6c5f696e646578080108753800070c5101517565727920726573706f6e736520686173206265656e20726563656976656420616e642071756572792069732072656d6f7665642e205468652064697370617463682077617320756e61626c6520746f20626559016465636f64656420696e746f2061206043616c6c603b2074686973206d696768742062652064756520746f2064697370617463682066756e6374696f6e20686176696e672061207369676e6174757265207768696368946973206e6f742060286f726967696e2c20517565727949642c20526573706f6e736529602e40496e76616c6964526573706f6e6465720c01186f726967696ed401344d756c74694c6f636174696f6e00012071756572795f69642c011c5175657279496400014465787065637465645f6c6f636174696f6ef10301544f7074696f6e3c4d756c74694c6f636174696f6e3e00080c5901457870656374656420717565727920726573706f6e736520686173206265656e2072656365697665642062757420746865206f726967696e206c6f636174696f6e206f662074686520726573706f6e736520646f657355016e6f74206d6174636820746861742065787065637465642e205468652071756572792072656d61696e73207265676973746572656420666f722061206c617465722c2076616c69642c20726573706f6e736520746f6c626520726563656976656420616e642061637465642075706f6e2e5c496e76616c6964526573706f6e64657256657273696f6e0801186f726967696ed401344d756c74694c6f636174696f6e00012071756572795f69642c011c5175657279496400091c5101457870656374656420717565727920726573706f6e736520686173206265656e2072656365697665642062757420746865206578706563746564206f726967696e206c6f636174696f6e20706c6163656420696e4d0173746f7261676520627920746869732072756e74696d652070726576696f75736c792063616e6e6f74206265206465636f6465642e205468652071756572792072656d61696e7320726567697374657265642e0041015468697320697320756e6578706563746564202873696e63652061206c6f636174696f6e20706c6163656420696e2073746f7261676520696e20612070726576696f75736c7920657865637574696e674d0172756e74696d652073686f756c64206265207265616461626c65207072696f7220746f2071756572792074696d656f75742920616e642064616e6765726f75732073696e63652074686520706f737369626c79590176616c696420726573706f6e73652077696c6c2062652064726f707065642e204d616e75616c20676f7665726e616e636520696e74657276656e74696f6e2069732070726f6261626c7920676f696e6720746f2062651c6e65656465642e34526573706f6e736554616b656e04012071756572795f69642c011c51756572794964000a04c8526563656976656420717565727920726573706f6e736520686173206265656e207265616420616e642072656d6f7665642e34417373657473547261707065640c011068617368300110483235360001186f726967696ed401344d756c74694c6f636174696f6e0001186173736574734102015056657273696f6e65644d756c7469417373657473000b04b8536f6d65206173736574732068617665206265656e20706c6163656420696e20616e20617373657420747261702e5456657273696f6e4368616e67654e6f74696669656410012c64657374696e6174696f6ed401344d756c74694c6f636174696f6e000118726573756c7410012858636d56657273696f6e000110636f7374c4012c4d756c74694173736574730001286d6573736167655f696404011c58636d48617368000c0c2501416e2058434d2076657273696f6e206368616e6765206e6f74696669636174696f6e206d65737361676520686173206265656e20617474656d7074656420746f2062652073656e742e00e054686520636f7374206f662073656e64696e672069742028626f726e652062792074686520636861696e2920697320696e636c756465642e5c537570706f7274656456657273696f6e4368616e6765640801206c6f636174696f6ed401344d756c74694c6f636174696f6e00011c76657273696f6e10012858636d56657273696f6e000d08390154686520737570706f727465642076657273696f6e206f662061206c6f636174696f6e20686173206265656e206368616e6765642e2054686973206d69676874206265207468726f75676820616ec06175746f6d61746963206e6f74696669636174696f6e206f722061206d616e75616c20696e74657276656e74696f6e2e504e6f7469667954617267657453656e644661696c0c01206c6f636174696f6ed401344d756c74694c6f636174696f6e00012071756572795f69642c011c517565727949640001146572726f72d503012058636d4572726f72000e0859014120676976656e206c6f636174696f6e2077686963682068616420612076657273696f6e206368616e676520737562736372697074696f6e207761732064726f70706564206f77696e6720746f20616e206572726f727c73656e64696e6720746865206e6f74696669636174696f6e20746f2069742e644e6f746966795461726765744d6967726174696f6e4661696c0801206c6f636174696f6e0102015856657273696f6e65644d756c74694c6f636174696f6e00012071756572795f69642c011c51756572794964000f0859014120676976656e206c6f636174696f6e2077686963682068616420612076657273696f6e206368616e676520737562736372697074696f6e207761732064726f70706564206f77696e6720746f20616e206572726f72b46d6967726174696e6720746865206c6f636174696f6e20746f206f7572206e65772058434d20666f726d61742e54496e76616c69645175657269657256657273696f6e0801186f726967696ed401344d756c74694c6f636174696f6e00012071756572795f69642c011c5175657279496400101c5501457870656374656420717565727920726573706f6e736520686173206265656e20726563656976656420627574207468652065787065637465642071756572696572206c6f636174696f6e20706c6163656420696e4d0173746f7261676520627920746869732072756e74696d652070726576696f75736c792063616e6e6f74206265206465636f6465642e205468652071756572792072656d61696e7320726567697374657265642e0041015468697320697320756e6578706563746564202873696e63652061206c6f636174696f6e20706c6163656420696e2073746f7261676520696e20612070726576696f75736c7920657865637574696e674d0172756e74696d652073686f756c64206265207265616461626c65207072696f7220746f2071756572792074696d656f75742920616e642064616e6765726f75732073696e63652074686520706f737369626c79590176616c696420726573706f6e73652077696c6c2062652064726f707065642e204d616e75616c20676f7665726e616e636520696e74657276656e74696f6e2069732070726f6261626c7920676f696e6720746f2062651c6e65656465642e38496e76616c6964517565726965721001186f726967696ed401344d756c74694c6f636174696f6e00012071756572795f69642c011c5175657279496400014065787065637465645f71756572696572d401344d756c74694c6f636174696f6e0001506d617962655f61637475616c5f71756572696572f10301544f7074696f6e3c4d756c74694c6f636174696f6e3e00110c5d01457870656374656420717565727920726573706f6e736520686173206265656e20726563656976656420627574207468652071756572696572206c6f636174696f6e206f662074686520726573706f6e736520646f657351016e6f74206d61746368207468652065787065637465642e205468652071756572792072656d61696e73207265676973746572656420666f722061206c617465722c2076616c69642c20726573706f6e736520746f6c626520726563656976656420616e642061637465642075706f6e2e5056657273696f6e4e6f74696679537461727465640c012c64657374696e6174696f6ed401344d756c74694c6f636174696f6e000110636f7374c4012c4d756c74694173736574730001286d6573736167655f696404011c58636d486173680012085901412072656d6f746520686173207265717565737465642058434d2076657273696f6e206368616e6765206e6f74696669636174696f6e2066726f6d20757320616e64207765206861766520686f6e6f7265642069742e1d01412076657273696f6e20696e666f726d6174696f6e206d6573736167652069732073656e7420746f207468656d20616e642069747320636f737420697320696e636c756465642e5856657273696f6e4e6f746966795265717565737465640c012c64657374696e6174696f6ed401344d756c74694c6f636174696f6e000110636f7374c4012c4d756c74694173736574730001286d6573736167655f696404011c58636d486173680013043d015765206861766520726571756573746564207468617420612072656d6f746520636861696e2073656e642075732058434d2076657273696f6e206368616e6765206e6f74696669636174696f6e732e6056657273696f6e4e6f74696679556e7265717565737465640c012c64657374696e6174696f6ed401344d756c74694c6f636174696f6e000110636f7374c4012c4d756c74694173736574730001286d6573736167655f696404011c58636d4861736800140825015765206861766520726571756573746564207468617420612072656d6f746520636861696e2073746f70732073656e64696e672075732058434d2076657273696f6e206368616e6765386e6f74696669636174696f6e732e204665657350616964080118706179696e67d401344d756c74694c6f636174696f6e00011066656573c4012c4d756c7469417373657473001504310146656573207765726520706169642066726f6d2061206c6f636174696f6e20666f7220616e206f7065726174696f6e20286f6674656e20666f72207573696e67206053656e6458636d60292e34417373657473436c61696d65640c011068617368300110483235360001186f726967696ed401344d756c74694c6f636174696f6e0001186173736574734102015056657273696f6e65644d756c7469417373657473001604c0536f6d65206173736574732068617665206265656e20636c61696d65642066726f6d20616e2061737365742074726170047c54686520604576656e746020656e756d206f6620746869732070616c6c6574c505102c73746167696e675f78636d087633187472616974731c4f7574636f6d6500010c20436f6d706c657465040024011857656967687400000028496e636f6d706c65746508002401185765696768740000d50301144572726f72000100144572726f720400d50301144572726f7200020000c9050c4863756d756c75735f70616c6c65745f78636d1870616c6c6574144576656e7404045400010c34496e76616c6964466f726d617404000401205b75383b2033325d00000880446f776e77617264206d65737361676520697320696e76616c69642058434d2e205c5b206964205c5d48556e737570706f7274656456657273696f6e04000401205b75383b2033325d000108bc446f776e77617264206d65737361676520697320756e737570706f727465642076657273696f6e206f662058434d2e205c5b206964205c5d404578656375746564446f776e7761726408000401205b75383b2033325d0000c505011c4f7574636f6d65000208c4446f776e77617264206d65737361676520657865637574656420776974682074686520676976656e206f7574636f6d652e445c5b2069642c206f7574636f6d65205c5d047c54686520604576656e746020656e756d206f6620746869732070616c6c6574cd050c6063756d756c75735f70616c6c65745f646d705f71756575651870616c6c6574144576656e7404045400011c34496e76616c6964466f726d61740401306d6573736167655f6861736804011c58636d4861736800000480446f776e77617264206d65737361676520697320696e76616c69642058434d2e48556e737570706f7274656456657273696f6e0401306d6573736167655f6861736804011c58636d48617368000104bc446f776e77617264206d65737361676520697320756e737570706f727465642076657273696f6e206f662058434d2e404578656375746564446f776e776172640c01306d6573736167655f6861736804011c58636d486173680001286d6573736167655f696404011c58636d4861736800011c6f7574636f6d65c505011c4f7574636f6d65000204c4446f776e77617264206d65737361676520657865637574656420776974682074686520676976656e206f7574636f6d652e3c5765696768744578686175737465641001306d6573736167655f6861736804011c58636d486173680001286d6573736167655f696404011c58636d4861736800014072656d61696e696e675f77656967687424011857656967687400013c72657175697265645f776569676874240118576569676874000304f054686520776569676874206c696d697420666f722068616e646c696e6720646f776e77617264206d657373616765732077617320726561636865642e484f766572776569676874456e7175657565641001306d6573736167655f6861736804011c58636d486173680001286d6573736167655f696404011c58636d486173680001406f7665727765696768745f696e6465782c013c4f766572776569676874496e64657800013c72657175697265645f7765696768742401185765696768740004041901446f776e77617264206d657373616765206973206f76657277656967687420616e642077617320706c6163656420696e20746865206f7665727765696768742071756575652e484f76657277656967687453657276696365640801406f7665727765696768745f696e6465782c013c4f766572776569676874496e64657800012c7765696768745f75736564240118576569676874000504e0446f776e77617264206d6573736167652066726f6d20746865206f766572776569676874207175657565207761732065786563757465642e504d61784d657373616765734578686175737465640401306d6573736167655f6861736804011c58636d48617368000604d0546865206d6178696d756d206e756d626572206f6620646f776e77617264206d657373616765732077617320726561636865642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574d1050c5070616c6c65745f636f6e66696775726174696f6e1870616c6c6574144576656e7404045400010c4c4e657744657369726564436f6c6c61746f7273040144646573697265645f636f6c6c61746f72732503012c4f7074696f6e3c7533323e000000584e6577436f6c6c61746f724c6963656e7365426f6e64040124626f6e645f636f7374250501484f7074696f6e3c543a3a42616c616e63653e000100604e6577436f6c6c61746f724b69636b5468726573686f6c640401406c656e6774685f696e5f626c6f636b73250301644f7074696f6e3c426c6f636b4e756d626572466f723c543e3e000200047c54686520604576656e746020656e756d206f6620746869732070616c6c6574d5050c3470616c6c65745f636f6d6d6f6e1870616c6c6574144576656e7404045400015844436f6c6c656374696f6e437265617465640c0089040130436f6c6c656374696f6e496404dc476c6f62616c6c7920756e69717565206964656e746966696572206f66206e65776c79206372656174656420636f6c6c656374696f6e2e000801087538049c5b60436f6c6c656374696f6e4d6f6465605d20636f6e76657274656420696e746f205f75385f2e00000130543a3a4163636f756e7449640444436f6c6c656374696f6e206f776e65722e0004684e657720636f6c6c656374696f6e2077617320637265617465644c436f6c6c656374696f6e44657374726f796564040089040130436f6c6c656374696f6e496404a4476c6f62616c6c7920756e69717565206964656e746966696572206f6620636f6c6c656374696f6e2e0104704e657720636f6c6c656374696f6e207761732064657374726f7965642c4974656d43726561746564100089040130436f6c6c656374696f6e496404b04964206f662074686520636f6c6c656374696f6e207768657265206974656d2077617320637265617465642e00d904011c546f6b656e496404b04964206f6620616e206974656d2e20556e697175652077697468696e2074686520636f6c6c656374696f6e2e004d040144543a3a43726f73734163636f756e744964046c4f776e6572206f66206e65776c792063726561746564206974656d00180110753132380440416c77617973203120666f72204e46540204544e6577206974656d2077617320637265617465642e344974656d44657374726f796564100089040130436f6c6c656374696f6e496404b84964206f662074686520636f6c6c656374696f6e207768657265206974656d207761732064657374726f7965642e00d904011c546f6b656e496404644964656e746966696572206f66206275726e6564204e46542e004d040144543a3a43726f73734163636f756e744964049057686963682075736572206861732064657374726f7965642069747320746f6b656e732e001801107531323804c8416d6f756e74206f6620746f6b656e207069656365732064657374726f65642e20416c77617973203120666f72204e46542e03046c436f6c6c656374696f6e206974656d20776173206275726e65642e205472616e73666572140089040130436f6c6c656374696f6e496404a44964206f6620636f6c6c656374696f6e20746f207768696368206974656d2069732062656c6f6e672e00d904011c546f6b656e496404384964206f6620616e206974656d2e004d040144543a3a43726f73734163636f756e744964045c4f726967696e616c206f776e6572206f66206974656d2e004d040144543a3a43726f73734163636f756e74496404484e6577206f776e6572206f66206974656d2e001801107531323804d0416d6f756e74206f6620746f6b656e20706965636573207472616e7366657265642e20416c77617973203120666f72204e46542e0404504974656d20776173207472616e7366657272656420417070726f766564140089040130436f6c6c656374696f6e496404a44964206f6620636f6c6c656374696f6e20746f207768696368206974656d2069732062656c6f6e672e00d904011c546f6b656e496404384964206f6620616e206974656d2e004d040144543a3a43726f73734163636f756e744964045c4f726967696e616c206f776e6572206f66206974656d2e004d040144543a3a43726f73734163636f756e7449640498496420666f722077686963682074686520617070726f76616c20776173206772616e7465642e001801107531323804d0416d6f756e74206f6620746f6b656e20706965636573207472616e7366657265642e20416c77617973203120666f72204e46542e05041101416d6f756e7420706965636573206f6620746f6b656e206f776e6564206279206073656e646572602077617320617070726f76656420666f7220607370656e646572602e38417070726f766564466f72416c6c100089040130436f6c6c656374696f6e496404a44964206f6620636f6c6c656374696f6e20746f207768696368206974656d2069732062656c6f6e672e004d040144543a3a43726f73734163636f756e74496404484f776e6572206f6620612077616c6c65742e004d040144543a3a43726f73734163636f756e74496404d0496420666f72207768696368206f70657261746f722073746174757320776173206772616e746564206f72207265776f6b65642e0035010110626f6f6c04984973206f70657261746f7220737461747573206772616e746564206f72207265766f6b65643f0604050141206073656e6465726020617070726f766573206f7065726174696f6e73206f6e20616c6c206f776e656420746f6b656e7320666f7220607370656e646572602e54436f6c6c656374696f6e50726f7065727479536574080089040130436f6c6c656374696f6e496404c04964206f6620636f6c6c656374696f6e20746f2077686963682070726f706572747920686173206265656e207365742e009d04012c50726f70657274794b657904685468652070726f7065727479207468617420776173207365742e0704c054686520636f6c6c6574696f6e2070726f706572747920686173206265656e206164646564206f72206564697465642e64436f6c6c656374696f6e50726f706572747944656c65746564080089040130436f6c6c656374696f6e496404d04964206f6620636f6c6c656374696f6e20746f2077686963682070726f706572747920686173206265656e2064656c657465642e009d04012c50726f70657274794b657904785468652070726f70657274792074686174207761732064656c657465642e0804785468652070726f706572747920686173206265656e2064656c657465642e40546f6b656e50726f70657274795365740c0089040130436f6c6c656374696f6e496404f84964656e746966696572206f662074686520636f6c6c656374696f6e2077686f736520746f6b656e20686173207468652070726f7065727479207365742e00d904011c546f6b656e496404a454686520746f6b656e20666f72207768696368207468652070726f706572747920776173207365742e009d04012c50726f70657274794b657904685468652070726f7065727479207468617420776173207365742e0904b054686520746f6b656e2070726f706572747920686173206265656e206164646564206f72206564697465642e50546f6b656e50726f706572747944656c657465640c0089040130436f6c6c656374696f6e49640409014964656e746966696572206f662074686520636f6c6c656374696f6e2077686f736520746f6b656e20686173207468652070726f70657274792064656c657465642e00d904011c546f6b656e496404b454686520746f6b656e20666f72207768696368207468652070726f7065727479207761732064656c657465642e009d04012c50726f70657274794b657904785468652070726f70657274792074686174207761732064656c657465642e0a049054686520746f6b656e2070726f706572747920686173206265656e2064656c657465642e5450726f70657274795065726d697373696f6e536574080089040130436f6c6c656374696f6e496404ec4944206f6620636f6c6c656374696f6e20746f2077686963682070726f7065727479207065726d697373696f6e20686173206265656e207365742e009d04012c50726f70657274794b657904945468652070726f7065727479207065726d697373696f6e207468617420776173207365742e0b04ec54686520746f6b656e2070726f7065727479207065726d697373696f6e206f66206120636f6c6c656374696f6e20686173206265656e207365742e54416c6c6f774c697374416464726573734164646564080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e004d040144543a3a43726f73734163636f756e744964047441646472657373206f6620746865206164646564206163636f756e742e0c0490416464726573732077617320616464656420746f2074686520616c6c6f77206c6973742e5c416c6c6f774c6973744164647265737352656d6f766564080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e004d040144543a3a43726f73734163636f756e744964047c41646472657373206f66207468652072656d6f766564206163636f756e742e0d04a041646472657373207761732072656d6f7665642066726f6d2074686520616c6c6f77206c6973742e50436f6c6c656374696f6e41646d696e4164646564080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e004d040144543a3a43726f73734163636f756e744964043841646d696e20616464726573732e0e046c436f6c6c656374696f6e2061646d696e207761732061646465642e58436f6c6c656374696f6e41646d696e52656d6f766564080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e004d040144543a3a43726f73734163636f756e744964045852656d6f7665642061646d696e20616464726573732e0f0474436f6c6c656374696f6e2061646d696e207761732072656d6f7665642e48436f6c6c656374696f6e4c696d6974536574040089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e10046c436f6c6c656374696f6e206c696d6974732077657265207365742e58436f6c6c656374696f6e4f776e65724368616e676564080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e00000130543a3a4163636f756e74496404484e6577206f776e657220616464726573732e110474436f6c6c656374696f6e206f776e656420776173206368616e6765642e5c436f6c6c656374696f6e5065726d697373696f6e536574040089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e120480436f6c6c656374696f6e207065726d697373696f6e732077657265207365742e50436f6c6c656374696f6e53706f6e736f72536574080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e00000130543a3a4163636f756e74496404504e65772073706f6e736f7220616464726573732e13046c436f6c6c656374696f6e2073706f6e736f7220776173207365742e5053706f6e736f7273686970436f6e6669726d6564080089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e00000130543a3a4163636f756e74496404504e65772073706f6e736f7220616464726573732e1404604e65772073706f6e736f722077617320636f6e6669726d2e60436f6c6c656374696f6e53706f6e736f7252656d6f766564040089040130436f6c6c656374696f6e496404784944206f662074686520616666656374656420636f6c6c656374696f6e2e15047c436f6c6c656374696f6e2073706f6e736f72207761732072656d6f7665642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574d9050c4070616c6c65745f7374727563747572651870616c6c6574144576656e740404540001042045786563757465640400a801384469737061746368526573756c740000049445786563757465642063616c6c206f6e20626568616c66206f662074686520746f6b656e2e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574dd050c5070616c6c65745f6170705f70726f6d6f74696f6e1870616c6c6574144576656e74040454000110505374616b696e67526563616c63756c6174696f6e0c00000130543a3a4163636f756e7449640458416e20726563616c63756c61746564207374616b65720018013042616c616e63654f663c543e049042617365206f6e20776869636820696e7465726573742069732063616c63756c617465640018013042616c616e63654f663c543e0468416d6f756e74206f66206163637275656420696e74657265737400188c5374616b696e6720726563616c63756c6174696f6e2077617320706572666f726d6564002c2320417267756d656e74738c2a204163636f756e7449643a206163636f756e74206f6620746865207374616b65722e782a2042616c616e6365203a20726563616c63756c6174696f6e2062617365602a2042616c616e6365203a20746f74616c20696e636f6d65145374616b650800000130543a3a4163636f756e744964000018013042616c616e63654f663c543e000114545374616b696e672077617320706572666f726d6564002c2320417267756d656e7473882a204163636f756e7449643a206163636f756e74206f6620746865207374616b6572682a2042616c616e6365203a207374616b696e6720616d6f756e741c556e7374616b650800000130543a3a4163636f756e744964000018013042616c616e63654f663c543e0002145c556e7374616b696e672077617320706572666f726d6564002c2320417267756d656e7473882a204163636f756e7449643a206163636f756e74206f6620746865207374616b6572702a2042616c616e6365203a20756e7374616b696e6720616d6f756e742053657441646d696e0400000130543a3a4163636f756e744964000310445468652061646d696e2077617320736574002c2320417267756d656e7473a42a204163636f756e7449643a206163636f756e742061646472657373206f66207468652061646d696e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574e1050c5470616c6c65745f666f726569676e5f617373657473186d6f64756c65144576656e7404045400011058466f726569676e4173736574526567697374657265640c012061737365745f6964100138466f726569676e4173736574496400013461737365745f61646472657373d401344d756c74694c6f636174696f6e0001206d657461646174613905016c41737365744d657461646174613c42616c616e63654f663c543e3e0000047454686520666f726569676e20617373657420726567697374657265642e4c466f726569676e4173736574557064617465640c012061737365745f6964100138466f726569676e4173736574496400013461737365745f61646472657373d401344d756c74694c6f636174696f6e0001206d657461646174613905016c41737365744d657461646174613c42616c616e63654f663c543e3e0001046854686520666f726569676e20617373657420757064617465642e3c41737365745265676973746572656408012061737365745f69640d01011c417373657449640001206d657461646174613905016c41737365744d657461646174613c42616c616e63654f663c543e3e0002045454686520617373657420726567697374657265642e3041737365745570646174656408012061737365745f69640d01011c417373657449640001206d657461646174613905016c41737365744d657461646174613c42616c616e63654f663c543e3e0003044854686520617373657420757064617465642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574e5050c2870616c6c65745f65766d1870616c6c6574144576656e740404540001140c4c6f6704010c6c6f67a105010c4c6f670000047c457468657265756d206576656e74732066726f6d20636f6e7472616374732e1c4372656174656404011c616464726573736503011048313630000104b44120636f6e747261637420686173206265656e206372656174656420617420676976656e20616464726573732e34437265617465644661696c656404011c61646472657373650301104831363000020405014120636f6e74726163742077617320617474656d7074656420746f20626520637265617465642c206275742074686520657865637574696f6e206661696c65642e20457865637574656404011c616464726573736503011048313630000304f84120636f6e747261637420686173206265656e206578656375746564207375636365737366756c6c79207769746820737461746573206170706c6965642e3845786563757465644661696c656404011c61646472657373650301104831363000040465014120636f6e747261637420686173206265656e2065786563757465642077697468206572726f72732e20537461746573206172652072657665727465642077697468206f6e6c79206761732066656573206170706c6965642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574e9050c3c70616c6c65745f657468657265756d1870616c6c6574144576656e7400010420457865637574656414011066726f6d6503011048313630000108746f65030110483136300001407472616e73616374696f6e5f686173683001104832353600012c657869745f726561736f6eed05012845786974526561736f6e00012865787472615f6461746134011c5665633c75383e000004c8416e20657468657265756d207472616e73616374696f6e20776173207375636365737366756c6c792065786563757465642e047c54686520604576656e746020656e756d206f6620746869732070616c6c6574ed050c2065766d5f636f7265146572726f722845786974526561736f6e0001101c537563636565640400f105012c4578697453756363656564000000144572726f720400f5050124457869744572726f72000100185265766572740400050601284578697452657665727400020014466174616c04000906012445786974466174616c00030000f1050c2065766d5f636f7265146572726f722c457869745375636365656400010c1c53746f707065640000002052657475726e656400010020537569636964656400020000f5050c2065766d5f636f7265146572726f7224457869744572726f7200014038537461636b556e646572666c6f7700000034537461636b4f766572666c6f770001002c496e76616c69644a756d7000020030496e76616c696452616e67650003004444657369676e61746564496e76616c69640004002c43616c6c546f6f446565700005003c437265617465436f6c6c6973696f6e0006004c437265617465436f6e74726163744c696d69740007002c496e76616c6964436f64650400f90501184f70636f6465000f002c4f75744f664f6666736574000800204f75744f66476173000900244f75744f6646756e64000a002c5043556e646572666c6f77000b002c437265617465456d707479000c00144f746865720400fd050144436f773c277374617469632c207374723e000d00204d61784e6f6e6365000e0000f9050c2065766d5f636f7265186f70636f6465184f70636f64650000040008010875380000fd05040c436f7704045401010600040001060000000106000005020005060c2065766d5f636f7265146572726f7228457869745265766572740001042052657665727465640000000009060c2065766d5f636f7265146572726f722445786974466174616c000110304e6f74537570706f7274656400000048556e68616e646c6564496e746572727570740001004043616c6c4572726f724173466174616c0400f5050124457869744572726f72000200144f746865720400fd050144436f773c277374617469632c207374723e000300000d060c6c70616c6c65745f65766d5f636f6e74726163745f68656c706572731870616c6c6574144576656e7404045400010c48436f6e747261637453706f6e736f725365740800650301104831363004b0436f6e74726163742061646472657373206f662074686520616666656374656420636f6c6c656374696f6e2e00000130543a3a4163636f756e74496404504e65772073706f6e736f7220616464726573732e000464436f6e74726163742073706f6e736f7220776173207365742e70436f6e747261637453706f6e736f7273686970436f6e6669726d65640800650301104831363004b0436f6e74726163742061646472657373206f662074686520616666656374656420636f6c6c656374696f6e2e00000130543a3a4163636f756e74496404504e65772073706f6e736f7220616464726573732e0104604e65772073706f6e736f722077617320636f6e6669726d2e58436f6e747261637453706f6e736f7252656d6f7665640400650301104831363004b0436f6e74726163742061646472657373206f662074686520616666656374656420636f6c6c656374696f6e2e02047c436f6c6c656374696f6e2073706f6e736f72207761732072656d6f7665642e047c54686520604576656e746020656e756d206f6620746869732070616c6c657411060c5070616c6c65745f65766d5f6d6967726174696f6e1870616c6c6574144576656e7404045400010424546573744576656e74000004f054686973206576656e74206973207573656420696e2062656e63686d61726b696e6720616e642063616e206265207573656420666f72207465737473047c54686520604576656e746020656e756d206f6620746869732070616c6c657415060c4870616c6c65745f6d61696e74656e616e63651870616c6c6574144576656e74040454000108484d61696e74656e616e6365456e61626c65640000004c4d61696e74656e616e636544697361626c6564000100047c54686520604576656e746020656e756d206f6620746869732070616c6c657419060c3870616c6c65745f7574696c6974791870616c6c6574144576656e74000118404261746368496e746572727570746564080114696e64657810010c7533320001146572726f7264013444697370617463684572726f7200000855014261746368206f66206469737061746368657320646964206e6f7420636f6d706c6574652066756c6c792e20496e646578206f66206669727374206661696c696e6720646973706174636820676976656e2c2061734877656c6c20617320746865206572726f722e384261746368436f6d706c65746564000104c84261746368206f66206469737061746368657320636f6d706c657465642066756c6c792077697468206e6f206572726f722e604261746368436f6d706c65746564576974684572726f7273000204b44261746368206f66206469737061746368657320636f6d706c657465642062757420686173206572726f72732e344974656d436f6d706c657465640003041d01412073696e676c65206974656d2077697468696e2061204261746368206f6620646973706174636865732068617320636f6d706c657465642077697468206e6f206572726f722e284974656d4661696c65640401146572726f7264013444697370617463684572726f720004041101412073696e676c65206974656d2077697468696e2061204261746368206f6620646973706174636865732068617320636f6d706c657465642077697468206572726f722e30446973706174636865644173040118726573756c74a801384469737061746368526573756c7400050458412063616c6c2077617320646973706174636865642e047c54686520604576656e746020656e756d206f6620746869732070616c6c65741d060c4470616c6c65745f746573745f7574696c731870616c6c6574144576656e7404045400010c2856616c756549735365740000003853686f756c64526f6c6c6261636b000100384261746368436f6d706c65746564000200047c54686520604576656e746020656e756d206f6620746869732070616c6c6574210608306672616d655f73797374656d14506861736500010c384170706c7945787472696e736963040010010c7533320000003046696e616c697a6174696f6e00010038496e697469616c697a6174696f6e000200002506000002790300290608306672616d655f73797374656d584c61737452756e74696d6555706772616465496e666f0000080130737065635f76657273696f6ee0014c636f6465633a3a436f6d706163743c7533323e000124737065635f6e616d650106016473705f72756e74696d653a3a52756e74696d65537472696e6700002d060c306672616d655f73797374656d186c696d69747330426c6f636b5765696768747300000c0128626173655f626c6f636b2401185765696768740001246d61785f626c6f636b2401185765696768740001247065725f636c617373310601845065724469737061746368436c6173733c57656967687473506572436c6173733e000031060c346672616d655f737570706f7274206469737061746368405065724469737061746368436c617373040454013506000c01186e6f726d616c350601045400012c6f7065726174696f6e616c35060104540001246d616e6461746f72793506010454000035060c306672616d655f73797374656d186c696d6974733c57656967687473506572436c6173730000100138626173655f65787472696e7369632401185765696768740001346d61785f65787472696e736963390601384f7074696f6e3c5765696768743e0001246d61785f746f74616c390601384f7074696f6e3c5765696768743e0001207265736572766564390601384f7074696f6e3c5765696768743e0000390604184f7074696f6e04045401240108104e6f6e6500000010536f6d6504002400000100003d060c306672616d655f73797374656d186c696d6974732c426c6f636b4c656e677468000004010c6d6178410601545065724469737061746368436c6173733c7533323e000041060c346672616d655f737570706f7274206469737061746368405065724469737061746368436c6173730404540110000c01186e6f726d616c1001045400012c6f7065726174696f6e616c100104540001246d616e6461746f72791001045400004506082873705f776569676874733c52756e74696d6544625765696768740000080110726561642c010c75363400011477726974652c010c75363400004906082873705f76657273696f6e3852756e74696d6556657273696f6e0000200124737065635f6e616d650106013452756e74696d65537472696e67000124696d706c5f6e616d650106013452756e74696d65537472696e67000144617574686f72696e675f76657273696f6e10010c753332000130737065635f76657273696f6e10010c753332000130696d706c5f76657273696f6e10010c753332000110617069734d06011c4170697356656300014c7472616e73616374696f6e5f76657273696f6e10010c75333200013473746174655f76657273696f6e080108753800004d06040c436f77040454015106000400510600000051060000025506005506000004080101100059060c306672616d655f73797374656d1870616c6c6574144572726f720404540001183c496e76616c6964537065634e616d650000081101546865206e616d65206f662073706563696669636174696f6e20646f6573206e6f74206d61746368206265747765656e207468652063757272656e742072756e74696d6550616e6420746865206e65772072756e74696d652e685370656356657273696f6e4e65656473546f496e63726561736500010841015468652073706563696669636174696f6e2076657273696f6e206973206e6f7420616c6c6f77656420746f206465637265617365206265747765656e207468652063757272656e742072756e74696d6550616e6420746865206e65772072756e74696d652e744661696c6564546f4578747261637452756e74696d6556657273696f6e00020cec4661696c656420746f2065787472616374207468652072756e74696d652076657273696f6e2066726f6d20746865206e65772072756e74696d652e0009014569746865722063616c6c696e672060436f72655f76657273696f6e60206f72206465636f64696e67206052756e74696d6556657273696f6e60206661696c65642e4c4e6f6e44656661756c74436f6d706f73697465000304fc537569636964652063616c6c6564207768656e20746865206163636f756e7420686173206e6f6e2d64656661756c7420636f6d706f7369746520646174612e3c4e6f6e5a65726f526566436f756e74000404350154686572652069732061206e6f6e2d7a65726f207265666572656e636520636f756e742070726576656e74696e6720746865206163636f756e742066726f6d206265696e67207075726765642e3043616c6c46696c7465726564000504d0546865206f726967696e2066696c7465722070726576656e74207468652063616c6c20746f20626520646973706174636865642e046c4572726f7220666f72207468652053797374656d2070616c6c65745d0600000261060061060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d48756e696e636c756465645f7365676d656e7420416e636573746f720404480130000c0138757365645f62616e647769647468650601345573656442616e647769647468000138706172615f686561645f68617368290301244f7074696f6e3c483e000160636f6e73756d65645f676f5f61686561645f7369676e616c7906018c4f7074696f6e3c72656c61795f636861696e3a3a55706772616465476f41686561643e000065060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d48756e696e636c756465645f7365676d656e74345573656442616e64776964746800000c0134756d705f6d73675f636f756e7410010c75333200013c756d705f746f74616c5f627974657310010c75333200013468726d705f6f7574676f696e676906018c42547265654d61703c5061726149642c2048726d704368616e6e656c5570646174653e00006906042042547265654d617008044b01ad010456016d0600040071060000006d060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d48756e696e636c756465645f7365676d656e744448726d704368616e6e656c55706461746500000801246d73675f636f756e7410010c75333200012c746f74616c5f627974657310010c75333200007106000002750600750600000408ad016d0600790604184f7074696f6e040454017d060108104e6f6e6500000010536f6d6504007d0600000100007d060c4c706f6c6b61646f745f7072696d6974697665730876353855706772616465476f41686561640001081441626f72740000001c476f41686561640001000081060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d48756e696e636c756465645f7365676d656e74385365676d656e74547261636b65720404480130000c0138757365645f62616e647769647468650601345573656442616e64776964746800013868726d705f77617465726d61726b250301804f7074696f6e3c72656c61795f636861696e3a3a426c6f636b4e756d6265723e000160636f6e73756d65645f676f5f61686561645f7369676e616c7906018c4f7074696f6e3c72656c61795f636861696e3a3a55706772616465476f41686561643e0000850604184f7074696f6e0404540189060108104e6f6e6500000010536f6d6504008906000001000089060c4c706f6c6b61646f745f7072696d69746976657308763548557067726164655265737472696374696f6e0001041c50726573656e74000000008d060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d5072656c61795f73746174655f736e617073686f74584d6573736167696e675374617465536e617073686f740000100130646d715f6d71635f6865616430014472656c61795f636861696e3a3a4861736800019c72656c61795f64697370617463685f71756575655f72656d61696e696e675f63617061636974799106018c52656c61794469737061746368517565756552656d61696e696e674361706163697479000140696e67726573735f6368616e6e656c73950601885665633c285061726149642c20416272696467656448726d704368616e6e656c293e00013c6567726573735f6368616e6e656c73950601885665633c285061726149642c20416272696467656448726d704368616e6e656c293e000091060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d5072656c61795f73746174655f736e617073686f748c52656c61794469737061746368517565756552656d61696e696e674361706163697479000008013c72656d61696e696e675f636f756e7410010c75333200013872656d61696e696e675f73697a6510010c75333200009506000002990600990600000408ad019d06009d060c4c706f6c6b61646f745f7072696d6974697665730876354c416272696467656448726d704368616e6e656c00001801306d61785f636170616369747910010c7533320001386d61785f746f74616c5f73697a6510010c7533320001406d61785f6d6573736167655f73697a6510010c7533320001246d73675f636f756e7410010c753332000128746f74616c5f73697a6510010c7533320001206d71635f68656164290301304f7074696f6e3c486173683e0000a1060c4c706f6c6b61646f745f7072696d697469766573087635644162726964676564486f7374436f6e66696775726174696f6e00002801346d61785f636f64655f73697a6510010c7533320001486d61785f686561645f646174615f73697a6510010c7533320001586d61785f7570776172645f71756575655f636f756e7410010c7533320001546d61785f7570776172645f71756575655f73697a6510010c75333200015c6d61785f7570776172645f6d6573736167655f73697a6510010c7533320001906d61785f7570776172645f6d6573736167655f6e756d5f7065725f63616e64696461746510010c75333200018868726d705f6d61785f6d6573736167655f6e756d5f7065725f63616e64696461746510010c75333200016c76616c69646174696f6e5f757067726164655f636f6f6c646f776e10012c426c6f636b4e756d62657200016076616c69646174696f6e5f757067726164655f64656c617910012c426c6f636b4e756d6265720001506173796e635f6261636b696e675f706172616d73a506018c73757065723a3a7673746167696e673a3a4173796e634261636b696e67506172616d730000a5060c4c706f6c6b61646f745f7072696d697469766573207673746167696e67484173796e634261636b696e67506172616d73000008014c6d61785f63616e6469646174655f646570746810010c753332000150616c6c6f7765645f616e6365737472795f6c656e10010c7533320000a906089463756d756c75735f7072696d6974697665735f70617261636861696e5f696e686572656e74444d6573736167655175657565436861696e0000040030012452656c6179486173680000ad06042042547265654d617008044b01ad01045601a906000400b106000000b106000002b50600b50600000408ad01a90600b906000002bd0600bd060860706f6c6b61646f745f636f72655f7072696d6974697665734c4f7574626f756e6448726d704d6573736167650408496401ad0100080124726563697069656e74ad01010849640001106461746134015073705f7374643a3a7665633a3a5665633c75383e0000c106087c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d60436f646555706772616465417574686f72697a6174696f6e0404540000080124636f64655f6861736830011c543a3a48617368000134636865636b5f76657273696f6e35010110626f6f6c0000c5060c7c63756d756c75735f70616c6c65745f70617261636861696e5f73797374656d1870616c6c6574144572726f720404540001204c4f7665726c617070696e6755706772616465730000041901417474656d707420746f20757067726164652076616c69646174696f6e2066756e6374696f6e207768696c65206578697374696e6720757067726164652070656e64696e672e5050726f686962697465644279506f6c6b61646f740001044d01506f6c6b61646f742063757272656e746c792070726f68696269747320746869732070617261636861696e2066726f6d20757067726164696e67206974732076616c69646174696f6e2066756e6374696f6e2e18546f6f426967000208450154686520737570706c6965642076616c69646174696f6e2066756e6374696f6e2068617320636f6d70696c656420696e746f206120626c6f62206c6172676572207468616e20506f6c6b61646f742069733c77696c6c696e6720746f2072756e2e6856616c69646174696f6e446174614e6f74417661696c61626c650003041d0154686520696e686572656e7420776869636820737570706c696573207468652076616c69646174696f6e206461746120646964206e6f742072756e207468697320626c6f636b2e74486f7374436f6e66696775726174696f6e4e6f74417661696c61626c65000404290154686520696e686572656e7420776869636820737570706c6965732074686520686f737420636f6e66696775726174696f6e20646964206e6f742072756e207468697320626c6f636b2e304e6f745363686564756c6564000504d84e6f2076616c69646174696f6e2066756e6374696f6e20757067726164652069732063757272656e746c79207363686564756c65642e444e6f7468696e67417574686f72697a6564000604904e6f20636f6465207570677261646520686173206265656e20617574686f72697a65642e30556e617574686f72697a6564000704bc54686520676976656e20636f6465207570677261646520686173206e6f74206265656e20617574686f72697a65642e048054686520604572726f726020656e756d206f6620746869732070616c6c65742ec9060c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540100045300000400e50101185665633c543e0000cd060c6470616c6c65745f636f6c6c61746f725f73656c656374696f6e1870616c6c6574144572726f7204045400013444546f6f4d616e7943616e646964617465730000044c546f6f206d616e792063616e646964617465731c556e6b6e6f776e00010434556e6b6e6f776e206572726f72285065726d697373696f6e000204405065726d697373696f6e20697373756554416c7265616479486f6c64696e674c6963656e7365000304945573657220616c726561647920686f6c6473206c6963656e736520746f20636f6c6c617465244e6f4c6963656e73650004049c5573657220646f6573206e6f7420686f6c642061206c6963656e736520746f20636f6c6c61746540416c726561647943616e6469646174650005046c5573657220697320616c726561647920612063616e646964617465304e6f7443616e6469646174650006045c55736572206973206e6f7420612063616e64696461746550546f6f4d616e79496e76756c6e657261626c657300070458546f6f206d616e7920696e76756c6e657261626c65734c546f6f466577496e76756c6e657261626c657300080454546f6f2066657720696e76756c6e657261626c65734c416c7265616479496e76756c6e657261626c650009047c5573657220697320616c726561647920616e20496e76756c6e657261626c653c4e6f74496e76756c6e657261626c65000a046c55736572206973206e6f7420616e20496e76756c6e657261626c655c4e6f4173736f63696174656456616c696461746f724964000b04984163636f756e7420686173206e6f206173736f6369617465642076616c696461746f722049445856616c696461746f724e6f7452656769737465726564000c048856616c696461746f72204944206973206e6f74207965742072656769737465726564048054686520604572726f726020656e756d206f6620746869732070616c6c65742ed106000002d50600d5060000040800cd0100d90600000408dd063400dd060c1c73705f636f72651863727970746f244b65795479706549640000040044011c5b75383b20345d0000e1060c3870616c6c65745f73657373696f6e1870616c6c6574144572726f7204045400011430496e76616c696450726f6f6600000460496e76616c6964206f776e6572736869702070726f6f662e5c4e6f4173736f63696174656456616c696461746f7249640001049c4e6f206173736f6369617465642076616c696461746f7220494420666f72206163636f756e742e344475706c6963617465644b65790002046452656769737465726564206475706c6963617465206b65792e184e6f4b657973000304a44e6f206b65797320617265206173736f63696174656420776974682074686973206163636f756e742e244e6f4163636f756e7400040419014b65792073657474696e67206163636f756e74206973206e6f74206c6976652c20736f206974277320696d706f737369626c6520746f206173736f6369617465206b6579732e04744572726f7220666f72207468652073657373696f6e2070616c6c65742ee5060c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401d101045300000400e90601185665633c543e0000e906000002d10100ed06084873705f636f6e73656e7375735f736c6f747310536c6f74000004002c010c7536340000f10600000408ed061000f5060c4c626f756e6465645f636f6c6c656374696f6e73407765616b5f626f756e6465645f766563385765616b426f756e64656456656308045401f906045300000400010701185665633c543e0000f9060c3c70616c6c65745f62616c616e6365731474797065732c42616c616e63654c6f636b041c42616c616e63650118000c01086964010101384c6f636b4964656e746966696572000118616d6f756e7418011c42616c616e636500011c726561736f6e73fd06011c526561736f6e730000fd060c3c70616c6c65745f62616c616e6365731474797065731c526561736f6e7300010c0c466565000000104d6973630001000c416c6c000200000107000002f9060005070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540109070453000004000d0701185665633c543e000009070c3c70616c6c65745f62616c616e6365731474797065732c52657365727665446174610844526573657276654964656e7469666965720105011c42616c616e6365011800080108696405010144526573657276654964656e746966696572000118616d6f756e7418011c42616c616e636500000d0700000209070011070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454011507045300000400210701185665633c543e000015070c3c70616c6c65745f62616c616e636573147479706573204964416d6f756e74080849640119071c42616c616e63650118000801086964190701084964000118616d6f756e7418011c42616c616e63650000190708306f70616c5f72756e74696d654452756e74696d65486f6c64526561736f6e00010444436f6c6c61746f7253656c656374696f6e04001d07019470616c6c65745f636f6c6c61746f725f73656c656374696f6e3a3a486f6c64526561736f6e001700001d070c6470616c6c65745f636f6c6c61746f725f73656c656374696f6e1870616c6c657428486f6c64526561736f6e0001042c4c6963656e7365426f6e6400000000210700000215070025070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540129070453000004002d0701185665633c543e000029070c3c70616c6c65745f62616c616e636573147479706573204964416d6f756e74080849640105011c42616c616e63650118000801086964050101084964000118616d6f756e7418011c42616c616e636500002d0700000229070031070c3c70616c6c65745f62616c616e6365731870616c6c6574144572726f720804540004490001283856657374696e6742616c616e63650000049c56657374696e672062616c616e636520746f6f206869676820746f2073656e642076616c75652e544c69717569646974795265737472696374696f6e73000104c84163636f756e74206c6971756964697479207265737472696374696f6e732070726576656e74207769746864726177616c2e4c496e73756666696369656e7442616c616e63650002047842616c616e636520746f6f206c6f7720746f2073656e642076616c75652e484578697374656e7469616c4465706f736974000304ec56616c756520746f6f206c6f7720746f20637265617465206163636f756e742064756520746f206578697374656e7469616c206465706f7369742e34457870656e646162696c697479000404905472616e736665722f7061796d656e7420776f756c64206b696c6c206163636f756e742e5c4578697374696e6756657374696e675363686564756c65000504cc412076657374696e67207363686564756c6520616c72656164792065786973747320666f722074686973206163636f756e742e2c446561644163636f756e740006048c42656e6566696369617279206163636f756e74206d757374207072652d65786973742e3c546f6f4d616e795265736572766573000704b84e756d626572206f66206e616d65642072657365727665732065786365656420604d61785265736572766573602e30546f6f4d616e79486f6c6473000804884e756d626572206f6620686f6c64732065786365656420604d6178486f6c6473602e38546f6f4d616e79467265657a6573000904984e756d626572206f6620667265657a65732065786365656420604d6178467265657a6573602e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e35070c3473705f61726974686d657469632c66697865645f706f696e7424466978656455313238000004001801107531323800003907086870616c6c65745f7472616e73616374696f6e5f7061796d656e742052656c6561736573000108245631416e6369656e74000000085632000100003d07083c70616c6c65745f74726561737572792050726f706f73616c08244163636f756e74496401001c42616c616e636501180010012070726f706f7365720001244163636f756e74496400011476616c756518011c42616c616e636500012c62656e65666963696172790001244163636f756e744964000110626f6e6418011c42616c616e6365000041070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540110045300000400310501185665633c543e000045070c3473705f61726974686d65746963287065725f7468696e67731c5065726d696c6c0000040010010c7533320000490708346672616d655f737570706f72742050616c6c65744964000004000101011c5b75383b20385d00004d070c3c70616c6c65745f74726561737572791870616c6c6574144572726f7208045400044900011470496e73756666696369656e7450726f706f7365727342616c616e63650000047850726f706f73657227732062616c616e636520697320746f6f206c6f772e30496e76616c6964496e646578000104904e6f2070726f706f73616c206f7220626f756e7479206174207468617420696e6465782e40546f6f4d616e79417070726f76616c7300020480546f6f206d616e7920617070726f76616c7320696e207468652071756575652e58496e73756666696369656e745065726d697373696f6e0003084501546865207370656e64206f726967696e2069732076616c6964206275742074686520616d6f756e7420697420697320616c6c6f77656420746f207370656e64206973206c6f776572207468616e207468654c616d6f756e7420746f206265207370656e742e4c50726f706f73616c4e6f74417070726f7665640004047c50726f706f73616c20686173206e6f74206265656e20617070726f7665642e04784572726f7220666f72207468652074726561737572792070616c6c65742e51070c2c70616c6c65745f7375646f1870616c6c6574144572726f720404540001042c526571756972655375646f0000047c53656e646572206d75737420626520746865205375646f206163636f756e7404644572726f7220666f7220746865205375646f2070616c6c657455070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401b8045300000400f90101185665633c543e000059070c306f726d6c5f76657374696e67186d6f64756c65144572726f72040454000118445a65726f56657374696e67506572696f640000045856657374696e6720706572696f64206973207a65726f585a65726f56657374696e67506572696f64436f756e740001045c4e756d626572206f66207665737473206973207a65726f64496e73756666696369656e7442616c616e6365546f4c6f636b00020498496e73756666696369656e7420616d6f756e74206f662062616c616e636520746f206c6f636b5c546f6f4d616e7956657374696e675363686564756c6573000304b054686973206163636f756e74206861766520746f6f206d616e792076657374696e67207363686564756c657324416d6f756e744c6f770004049454686520766573746564207472616e7366657220616d6f756e7420697320746f6f206c6f776c4d617856657374696e675363686564756c65734578636565646564000504e44661696c6564206265636175736520746865206d6178696d756d2076657374696e67207363686564756c657320776173206578636565646564048054686520604572726f726020656e756d206f6620746869732070616c6c65742e5d070c306f726d6c5f78746f6b656e73186d6f64756c65144572726f7204045400014c4441737365744861734e6f5265736572766500000478417373657420686173206e6f2072657365727665206c6f636174696f6e2e544e6f7443726f7373436861696e5472616e73666572000104644e6f742063726f73732d636861696e207472616e736665722e2c496e76616c69644465737400020474496e76616c6964207472616e736665722064657374696e6174696f6e2e844e6f7443726f7373436861696e5472616e7366657261626c6543757272656e6379000304a443757272656e6379206973206e6f742063726f73732d636861696e207472616e7366657261626c652e48556e776569676861626c654d657373616765000404b4546865206d65737361676527732077656967687420636f756c64206e6f742062652064657465726d696e65642e4858636d457865637574696f6e4661696c65640005045458434d20657865637574696f6e206661696c65642e3843616e6e6f745265616e63686f72000608e8436f756c64206e6f742072652d616e63686f72207468652061737365747320746f206465636c61726520746865206665657320666f72207468654864657374696e6174696f6e20636861696e2e3c496e76616c6964416e636573747279000704c4436f756c64206e6f742067657420616e636573747279206f662061737365742072657365727665206c6f636174696f6e2e30496e76616c6964417373657400080468546865204d756c7469417373657420697320696e76616c69642e6044657374696e6174696f6e4e6f74496e7665727469626c65000904f05468652064657374696e6174696f6e20604d756c74694c6f636174696f6e602070726f76696465642063616e6e6f7420626520696e7665727465642e2842616456657273696f6e000a08ec5468652076657273696f6e206f6620746865206056657273696f6e6564602076616c75652075736564206973206e6f742061626c6520746f20626530696e7465727072657465642e7444697374696e637452657365727665466f724173736574416e64466565000b08fc57652074726965642073656e64696e672064697374696e637420617373657420616e6420666565206275742074686579206861766520646966666572656e743c7265736572766520636861696e732e1c5a65726f466565000c044054686520666565206973207a65726f2e285a65726f416d6f756e74000d0494546865207472616e73666572696e6720617373657420616d6f756e74206973207a65726f2e58546f6f4d616e794173736574734265696e6753656e74000e04d0546865206e756d626572206f662061737365747320746f2062652073656e74206973206f76657220746865206d6178696d756d2e544173736574496e6465784e6f6e4578697374656e74000f04ec5468652073706563696669656420696e64657820646f6573206e6f7420657869737420696e2061204d756c7469417373657473207374727563742e304665654e6f74456e6f75676800100448466565206973206e6f7420656e6f7567682e644e6f74537570706f727465644d756c74694c6f636174696f6e0011046c4e6f7420737570706f72746564204d756c74694c6f636174696f6e4c4d696e58636d4665654e6f74446566696e6564001204d44d696e58636d466565206e6f74207265676973746572656420666f72206365727461696e2072657365727665206c6f636174696f6e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e610700000408000d010065070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540169070453000004006d0701185665633c543e00006907082c6f726d6c5f746f6b656e732c42616c616e63654c6f636b041c42616c616e63650118000801086964010101384c6f636b4964656e746966696572000118616d6f756e7418011c42616c616e636500006d070000026907007107082c6f726d6c5f746f6b656e732c4163636f756e7444617461041c42616c616e63650118000c01106672656518011c42616c616e6365000120726573657276656418011c42616c616e636500011866726f7a656e18011c42616c616e6365000075070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540179070453000004007d0701185665633c543e00007907082c6f726d6c5f746f6b656e732c52657365727665446174610844526573657276654964656e74696669657201ac1c42616c616e63650118000801086964ac0144526573657276654964656e746966696572000118616d6f756e7418011c42616c616e636500007d0700000279070081070c2c6f726d6c5f746f6b656e73186d6f64756c65144572726f720404540001203442616c616e6365546f6f4c6f77000004585468652062616c616e636520697320746f6f206c6f775c416d6f756e74496e746f42616c616e63654661696c65640001049c43616e6e6f7420636f6e7665727420416d6f756e7420696e746f2042616c616e63652074797065544c69717569646974795265737472696374696f6e73000204d04661696c65642062656361757365206c6971756964697479207265737472696374696f6e732064756520746f206c6f636b696e67404d61784c6f636b734578636565646564000304b44661696c6564206265636175736520746865206d6178696d756d206c6f636b7320776173206578636565646564244b656570416c6976650004048c5472616e736665722f7061796d656e7420776f756c64206b696c6c206163636f756e74484578697374656e7469616c4465706f736974000504e856616c756520746f6f206c6f7720746f20637265617465206163636f756e742064756520746f206578697374656e7469616c206465706f7369742c446561644163636f756e740006048842656e6566696369617279206163636f756e74206d757374207072652d65786973743c546f6f4d616e795265736572766573000700048054686520604572726f726020656e756d206f6620746869732070616c6c65742e8507000004081889070089070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540100045300000400e50101185665633c543e00008d070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454019107045300000400990701185665633c543e0000910704184f7074696f6e0404540195070108104e6f6e6500000010536f6d6504009507000001000095070c3c70616c6c65745f6964656e7469747914747970657334526567697374726172496e666f081c42616c616e63650118244163636f756e7449640100000c011c6163636f756e740001244163636f756e74496400010c66656518011c42616c616e63650001186669656c6473e50201384964656e746974794669656c6473000099070000029107009d070c3c70616c6c65745f6964656e746974791870616c6c6574144572726f7204045400014848546f6f4d616e795375624163636f756e74730000045c546f6f206d616e7920737562732d6163636f756e74732e204e6f74466f756e64000104504163636f756e742069736e277420666f756e642e204e6f744e616d6564000204504163636f756e742069736e2774206e616d65642e28456d707479496e64657800030430456d70747920696e6465782e284665654368616e6765640004043c466565206973206368616e6765642e284e6f4964656e74697479000504484e6f206964656e7469747920666f756e642e3c537469636b794a756467656d656e7400060444537469636b79206a756467656d656e742e384a756467656d656e74476976656e000704404a756467656d656e7420676976656e2e40496e76616c69644a756467656d656e7400080448496e76616c6964206a756467656d656e742e30496e76616c6964496e6465780009045454686520696e64657820697320696e76616c69642e34496e76616c6964546172676574000a04585468652074617267657420697320696e76616c69642e34546f6f4d616e794669656c6473000b046c546f6f206d616e79206164646974696f6e616c206669656c64732e44546f6f4d616e7952656769737472617273000c04e84d6178696d756d20616d6f756e74206f66207265676973747261727320726561636865642e2043616e6e6f742061646420616e79206d6f72652e38416c7265616479436c61696d6564000d04704163636f756e7420494420697320616c7265616479206e616d65642e184e6f74537562000e047053656e646572206973206e6f742061207375622d6163636f756e742e204e6f744f776e6564000f04885375622d6163636f756e742069736e2774206f776e65642062792073656e6465722e744a756467656d656e74466f72446966666572656e744964656e74697479001004d05468652070726f7669646564206a756467656d656e742077617320666f72206120646966666572656e74206964656e746974792e584a756467656d656e745061796d656e744661696c6564001104f84572726f722074686174206f6363757273207768656e20746865726520697320616e20697373756520706179696e6720666f72206a756467656d656e742e048054686520604572726f726020656e756d206f6620746869732070616c6c65742ea107083c70616c6c65745f707265696d616765345265717565737453746174757308244163636f756e74496401001c42616c616e6365011801082c556e72657175657374656408011c6465706f736974a5070150284163636f756e7449642c2042616c616e63652900010c6c656e10010c753332000000245265717565737465640c011c6465706f736974a90701704f7074696f6e3c284163636f756e7449642c2042616c616e6365293e000114636f756e7410010c75333200010c6c656e2503012c4f7074696f6e3c7533323e00010000a50700000408001800a90704184f7074696f6e04045401a5070108104e6f6e6500000010536f6d650400a5070000010000ad0700000408301000b1070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000b5070c3c70616c6c65745f707265696d6167651870616c6c6574144572726f7204045400011818546f6f426967000004a0507265696d61676520697320746f6f206c6172676520746f2073746f7265206f6e2d636861696e2e30416c72656164794e6f746564000104a4507265696d6167652068617320616c7265616479206265656e206e6f746564206f6e2d636861696e2e344e6f74417574686f72697a6564000204c85468652075736572206973206e6f7420617574686f72697a656420746f20706572666f726d207468697320616374696f6e2e204e6f744e6f746564000304fc54686520707265696d6167652063616e6e6f742062652072656d6f7665642073696e636520697420686173206e6f7420796574206265656e206e6f7465642e2452657175657374656400040409014120707265696d616765206d6179206e6f742062652072656d6f766564207768656e20746865726520617265206f75747374616e64696e672072657175657374732e304e6f745265717565737465640005042d0154686520707265696d61676520726571756573742063616e6e6f742062652072656d6f7665642073696e6365206e6f206f75747374616e64696e672072657175657374732065786973742e048054686520604572726f726020656e756d206f6620746869732070616c6c65742eb9070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401bd07045300000400c10701185665633c543e0000bd070000040c1059010000c107000002bd0700c50700000408c9071800c9070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540100045300000400e50101185665633c543e0000cd070c4070616c6c65745f64656d6f6372616379147479706573385265666572656e64756d496e666f0c2c426c6f636b4e756d62657201102050726f706f73616c0159011c42616c616e6365011801081c4f6e676f696e670400d10701c05265666572656e64756d5374617475733c426c6f636b4e756d6265722c2050726f706f73616c2c2042616c616e63653e0000002046696e6973686564080120617070726f76656435010110626f6f6c00010c656e6410012c426c6f636b4e756d62657200010000d1070c4070616c6c65745f64656d6f6372616379147479706573405265666572656e64756d5374617475730c2c426c6f636b4e756d62657201102050726f706f73616c0159011c42616c616e636501180014010c656e6410012c426c6f636b4e756d62657200012070726f706f73616c5901012050726f706f73616c0001247468726573686f6c6421010134566f74655468726573686f6c6400011464656c617910012c426c6f636b4e756d62657200011474616c6c79d507013854616c6c793c42616c616e63653e0000d5070c4070616c6c65745f64656d6f63726163791474797065731454616c6c79041c42616c616e63650118000c01106179657318011c42616c616e63650001106e61797318011c42616c616e636500011c7475726e6f757418011c42616c616e63650000d9070c4070616c6c65745f64656d6f637261637910766f746518566f74696e67101c42616c616e63650118244163636f756e74496401002c426c6f636b4e756d6265720110204d6178566f746573000108184469726563740c0114766f746573dd0701f4426f756e6465645665633c285265666572656e64756d496e6465782c204163636f756e74566f74653c42616c616e63653e292c204d6178566f7465733e00012c64656c65676174696f6e73e907015044656c65676174696f6e733c42616c616e63653e0001147072696f72ed07017c5072696f724c6f636b3c426c6f636b4e756d6265722c2042616c616e63653e0000002844656c65676174696e6714011c62616c616e636518011c42616c616e63650001187461726765740001244163636f756e744964000128636f6e76696374696f6e21030128436f6e76696374696f6e00012c64656c65676174696f6e73e907015044656c65676174696f6e733c42616c616e63653e0001147072696f72ed07017c5072696f724c6f636b3c426c6f636b4e756d6265722c2042616c616e63653e00010000dd070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401e107045300000400e50701185665633c543e0000e1070000040810250100e507000002e10700e9070c4070616c6c65745f64656d6f63726163791474797065732c44656c65676174696f6e73041c42616c616e6365011800080114766f74657318011c42616c616e636500011c6361706974616c18011c42616c616e63650000ed070c4070616c6c65745f64656d6f637261637910766f7465245072696f724c6f636b082c426c6f636b4e756d62657201101c42616c616e6365011800080010012c426c6f636b4e756d626572000018011c42616c616e63650000f107000004085901210100f5070000040810c90700f9070c4070616c6c65745f64656d6f63726163791870616c6c6574144572726f720404540001602056616c75654c6f770000043456616c756520746f6f206c6f773c50726f706f73616c4d697373696e670001045c50726f706f73616c20646f6573206e6f742065786973743c416c726561647943616e63656c65640002049443616e6e6f742063616e63656c207468652073616d652070726f706f73616c207477696365444475706c696361746550726f706f73616c0003045450726f706f73616c20616c7265616479206d6164654c50726f706f73616c426c61636b6c69737465640004046850726f706f73616c207374696c6c20626c61636b6c6973746564444e6f7453696d706c654d616a6f72697479000504a84e6578742065787465726e616c2070726f706f73616c206e6f742073696d706c65206d616a6f726974792c496e76616c69644861736800060430496e76616c69642068617368284e6f50726f706f73616c000704504e6f2065787465726e616c2070726f706f73616c34416c72656164795665746f6564000804984964656e74697479206d6179206e6f74207665746f20612070726f706f73616c207477696365445265666572656e64756d496e76616c696400090484566f746520676976656e20666f7220696e76616c6964207265666572656e64756d2c4e6f6e6557616974696e67000a04504e6f2070726f706f73616c732077616974696e67204e6f74566f746572000b04c454686520676976656e206163636f756e7420646964206e6f7420766f7465206f6e20746865207265666572656e64756d2e304e6f5065726d697373696f6e000c04c8546865206163746f7220686173206e6f207065726d697373696f6e20746f20636f6e647563742074686520616374696f6e2e44416c726561647944656c65676174696e67000d0488546865206163636f756e7420697320616c72656164792064656c65676174696e672e44496e73756666696369656e7446756e6473000e04fc546f6f206869676820612062616c616e6365207761732070726f7669646564207468617420746865206163636f756e742063616e6e6f74206166666f72642e344e6f7444656c65676174696e67000f04a0546865206163636f756e74206973206e6f742063757272656e746c792064656c65676174696e672e28566f74657345786973740010085501546865206163636f756e742063757272656e746c792068617320766f74657320617474616368656420746f20697420616e6420746865206f7065726174696f6e2063616e6e6f74207375636365656420756e74696ce87468657365206172652072656d6f7665642c20656974686572207468726f7567682060756e766f746560206f722060726561705f766f7465602e44496e7374616e744e6f74416c6c6f776564001104d854686520696e7374616e74207265666572656e64756d206f726967696e2069732063757272656e746c7920646973616c6c6f7765642e204e6f6e73656e73650012049444656c65676174696f6e20746f206f6e6573656c66206d616b6573206e6f2073656e73652e3c57726f6e675570706572426f756e6400130450496e76616c696420757070657220626f756e642e3c4d6178566f74657352656163686564001404804d6178696d756d206e756d626572206f6620766f74657320726561636865642e1c546f6f4d616e79001504804d6178696d756d206e756d626572206f66206974656d7320726561636865642e3c566f74696e67506572696f644c6f7700160454566f74696e6720706572696f6420746f6f206c6f7740507265696d6167654e6f7445786973740017047054686520707265696d61676520646f6573206e6f742065786973742e048054686520604572726f726020656e756d206f6620746869732070616c6c65742efd070c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401300453000004005d0501185665633c543e00000108084470616c6c65745f636f6c6c65637469766514566f74657308244163636f756e74496401002c426c6f636b4e756d626572011000140114696e64657810013450726f706f73616c496e6465780001247468726573686f6c6410012c4d656d626572436f756e7400011061796573e50101385665633c4163636f756e7449643e0001106e617973e50101385665633c4163636f756e7449643e00010c656e6410012c426c6f636b4e756d626572000005080c4470616c6c65745f636f6c6c6563746976651870616c6c6574144572726f7208045400044900012c244e6f744d656d6265720000045c4163636f756e74206973206e6f742061206d656d626572444475706c696361746550726f706f73616c0001047c4475706c69636174652070726f706f73616c73206e6f7420616c6c6f7765643c50726f706f73616c4d697373696e670002044c50726f706f73616c206d7573742065786973742857726f6e67496e646578000304404d69736d61746368656420696e646578344475706c6963617465566f7465000404584475706c696361746520766f74652069676e6f72656448416c7265616479496e697469616c697a6564000504804d656d626572732061726520616c726561647920696e697469616c697a65642120546f6f4561726c79000604010154686520636c6f73652063616c6c20776173206d61646520746f6f206561726c792c206265666f72652074686520656e64206f662074686520766f74696e672e40546f6f4d616e7950726f706f73616c73000704fc54686572652063616e206f6e6c792062652061206d6178696d756d206f6620604d617850726f706f73616c7360206163746976652070726f706f73616c732e4c57726f6e6750726f706f73616c576569676874000804d054686520676976656e2077656967687420626f756e6420666f72207468652070726f706f73616c2077617320746f6f206c6f772e4c57726f6e6750726f706f73616c4c656e677468000904d054686520676976656e206c656e67746820626f756e6420666f72207468652070726f706f73616c2077617320746f6f206c6f772e545072696d654163636f756e744e6f744d656d626572000a04745072696d65206163636f756e74206973206e6f742061206d656d626572048054686520604572726f726020656e756d206f6620746869732070616c6c65742e09080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401300453000004005d0501185665633c543e00000d080c4470616c6c65745f636f6c6c6563746976651870616c6c6574144572726f7208045400044900012c244e6f744d656d6265720000045c4163636f756e74206973206e6f742061206d656d626572444475706c696361746550726f706f73616c0001047c4475706c69636174652070726f706f73616c73206e6f7420616c6c6f7765643c50726f706f73616c4d697373696e670002044c50726f706f73616c206d7573742065786973742857726f6e67496e646578000304404d69736d61746368656420696e646578344475706c6963617465566f7465000404584475706c696361746520766f74652069676e6f72656448416c7265616479496e697469616c697a6564000504804d656d626572732061726520616c726561647920696e697469616c697a65642120546f6f4561726c79000604010154686520636c6f73652063616c6c20776173206d61646520746f6f206561726c792c206265666f72652074686520656e64206f662074686520766f74696e672e40546f6f4d616e7950726f706f73616c73000704fc54686572652063616e206f6e6c792062652061206d6178696d756d206f6620604d617850726f706f73616c7360206163746976652070726f706f73616c732e4c57726f6e6750726f706f73616c576569676874000804d054686520676976656e2077656967687420626f756e6420666f72207468652070726f706f73616c2077617320746f6f206c6f772e4c57726f6e6750726f706f73616c4c656e677468000904d054686520676976656e206c656e67746820626f756e6420666f72207468652070726f706f73616c2077617320746f6f206c6f772e545072696d654163636f756e744e6f744d656d626572000a04745072696d65206163636f756e74206973206e6f742061206d656d626572048054686520604572726f726020656e756d206f6620746869732070616c6c65742e11080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540100045300000400e50101185665633c543e000015080c4470616c6c65745f6d656d626572736869701870616c6c6574144572726f7208045400044900010c34416c72656164794d656d62657200000444416c72656164792061206d656d6265722e244e6f744d656d626572000104344e6f742061206d656d6265722e38546f6f4d616e794d656d6265727300020444546f6f206d616e79206d656d626572732e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e19080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e6465645665630804540100045300000400e50101185665633c543e00001d080c4470616c6c65745f6d656d626572736869701870616c6c6574144572726f7208045400044900010c34416c72656164794d656d62657200000444416c72656164792061206d656d6265722e244e6f744d656d626572000104344e6f742061206d656d6265722e38546f6f4d616e794d656d6265727300020444546f6f206d616e79206d656d626572732e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e2108086070616c6c65745f72616e6b65645f636f6c6c656374697665304d656d6265725265636f7264000004011072616e6b4901011052616e6b000025080000040849010000290800000408490110002d080000040810000031080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e000035080c6070616c6c65745f72616e6b65645f636f6c6c6563746976651870616c6c6574144572726f7208045400044900012434416c72656164794d656d626572000004704163636f756e7420697320616c72656164792061206d656d6265722e244e6f744d656d626572000104604163636f756e74206973206e6f742061206d656d6265722e284e6f74506f6c6c696e67000204b854686520676976656e20706f6c6c20696e64657820697320756e6b6e6f776e206f722068617320636c6f7365642e1c4f6e676f696e670003048054686520676976656e20706f6c6c206973207374696c6c206f6e676f696e672e344e6f6e6552656d61696e696e67000404ac546865726520617265206e6f2066757274686572207265636f72647320746f2062652072656d6f7665642e28436f7272757074696f6e00050468556e6578706563746564206572726f7220696e2073746174652e2852616e6b546f6f4c6f7700060494546865206d656d62657227732072616e6b20697320746f6f206c6f7720746f20766f74652e38496e76616c69645769746e6573730007049854686520696e666f726d6174696f6e2070726f766964656420697320696e636f72726563742e304e6f5065726d697373696f6e000804f8546865206f726967696e206973206e6f742073756666696369656e746c792070726976696c6567656420746f20646f20746865206f7065726174696f6e2e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e39080c4070616c6c65745f7265666572656e6461147479706573385265666572656e64756d496e666f201c547261636b49640149013452756e74696d654f726967696e014503184d6f6d656e7401101043616c6c0159011c42616c616e636501181454616c6c79015101244163636f756e74496401003c5363686564756c654164647265737301790301181c4f6e676f696e6704003d08018d015265666572656e64756d5374617475733c547261636b49642c2052756e74696d654f726967696e2c204d6f6d656e742c2043616c6c2c2042616c616e63652c2054616c6c792c0a4163636f756e7449642c205363686564756c65416464726573732c3e00000020417070726f7665640c001001184d6f6d656e7400004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e00004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e0001002052656a65637465640c001001184d6f6d656e7400004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e00004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e0002002443616e63656c6c65640c001001184d6f6d656e7400004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e00004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e0003002054696d65644f75740c001001184d6f6d656e7400004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e00004508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e000400184b696c6c656404001001184d6f6d656e74000500003d080c4070616c6c65745f7265666572656e6461147479706573405265666572656e64756d537461747573201c547261636b49640149013452756e74696d654f726967696e014503184d6f6d656e7401101043616c6c0159011c42616c616e636501181454616c6c79015101244163636f756e74496401003c5363686564756c6541646472657373017903002c0114747261636b4901011c547261636b49640001186f726967696e4503013452756e74696d654f726967696e00012070726f706f73616c5901011043616c6c000124656e6163746d656e746d030150446973706174636854696d653c4d6f6d656e743e0001247375626d69747465641001184d6f6d656e740001487375626d697373696f6e5f6465706f7369744108016c4465706f7369743c4163636f756e7449642c2042616c616e63653e0001406465636973696f6e5f6465706f7369744508018c4f7074696f6e3c4465706f7369743c4163636f756e7449642c2042616c616e63653e3e0001206465636964696e67490801784f7074696f6e3c4465636964696e675374617475733c4d6f6d656e743e3e00011474616c6c795101011454616c6c79000120696e5f717565756535010110626f6f6c000114616c61726d510801844f7074696f6e3c284d6f6d656e742c205363686564756c6541646472657373293e000041080c4070616c6c65745f7265666572656e64611474797065731c4465706f73697408244163636f756e74496401001c42616c616e636501180008010c77686f0001244163636f756e744964000118616d6f756e7418011c42616c616e63650000450804184f7074696f6e0404540141080108104e6f6e6500000010536f6d65040041080000010000490804184f7074696f6e040454014d080108104e6f6e6500000010536f6d6504004d0800000100004d080c4070616c6c65745f7265666572656e6461147479706573384465636964696e67537461747573042c426c6f636b4e756d62657201100008011473696e636510012c426c6f636b4e756d626572000128636f6e6669726d696e672503014c4f7074696f6e3c426c6f636b4e756d6265723e0000510804184f7074696f6e0404540155080108104e6f6e6500000010536f6d650400550800000100005508000004081079030059080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454017903045300000400250601185665633c543e00005d08000002610800610800000408490165080065080c4070616c6c65745f7265666572656e646114747970657324547261636b496e666f081c42616c616e63650118184d6f6d656e740110002401106e616d65010601302627737461746963207374720001306d61785f6465636964696e6710010c7533320001406465636973696f6e5f6465706f73697418011c42616c616e6365000138707265706172655f706572696f641001184d6f6d656e7400013c6465636973696f6e5f706572696f641001184d6f6d656e74000138636f6e6669726d5f706572696f641001184d6f6d656e740001506d696e5f656e6163746d656e745f706572696f641001184d6f6d656e740001306d696e5f617070726f76616c69080114437572766500012c6d696e5f737570706f7274690801144375727665000069080c4070616c6c65745f7265666572656e646114747970657314437572766500010c404c696e65617244656372656173696e670c01186c656e6774681d05011c50657262696c6c000114666c6f6f721d05011c50657262696c6c0001106365696c1d05011c50657262696c6c000000445374657070656444656372656173696e67100114626567696e1d05011c50657262696c6c00010c656e641d05011c50657262696c6c000110737465701d05011c50657262696c6c000118706572696f641d05011c50657262696c6c000100285265636970726f63616c0c0118666163746f726d0801204669786564493634000120785f6f66667365746d0801204669786564493634000120795f6f66667365746d0801204669786564493634000200006d080c3473705f61726974686d657469632c66697865645f706f696e74204669786564493634000004007108010c693634000071080000050c0075080c4070616c6c65745f7265666572656e64611870616c6c6574144572726f72080454000449000134284e6f744f6e676f696e67000004685265666572656e64756d206973206e6f74206f6e676f696e672e284861734465706f736974000104b85265666572656e64756d2773206465636973696f6e206465706f73697420697320616c726561647920706169642e20426164547261636b0002049c54686520747261636b206964656e74696669657220676976656e2077617320696e76616c69642e1046756c6c000304310154686572652061726520616c726561647920612066756c6c20636f6d706c656d656e74206f66207265666572656e646120696e2070726f677265737320666f72207468697320747261636b2e285175657565456d70747900040480546865207175657565206f662074686520747261636b20697320656d7074792e344261645265666572656e64756d000504e4546865207265666572656e64756d20696e6465782070726f766964656420697320696e76616c696420696e207468697320636f6e746578742e2c4e6f7468696e67546f446f000604ac546865726520776173206e6f7468696e6720746f20646f20696e2074686520616476616e63656d656e742e1c4e6f547261636b000704a04e6f20747261636b2065786973747320666f72207468652070726f706f73616c206f726967696e2e28556e66696e69736865640008040101416e79206465706f7369742063616e6e6f7420626520726566756e64656420756e74696c20616674657220746865206465636973696f6e206973206f7665722e304e6f5065726d697373696f6e000904a8546865206465706f73697420726566756e646572206973206e6f7420746865206465706f7369746f722e244e6f4465706f736974000a04cc546865206465706f7369742063616e6e6f7420626520726566756e6465642073696e6365206e6f6e6520776173206d6164652e24426164537461747573000b04d0546865207265666572656e64756d2073746174757320697320696e76616c696420666f722074686973206f7065726174696f6e2e40507265696d6167654e6f744578697374000c047054686520707265696d61676520646f6573206e6f742065786973742e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e79080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454017d08045300000400850801185665633c543e00007d0804184f7074696f6e0404540181080108104e6f6e6500000010536f6d650400810800000100008108084070616c6c65745f7363686564756c6572245363686564756c656414104e616d6501041043616c6c0159012c426c6f636b4e756d62657201103450616c6c6574734f726967696e014503244163636f756e7449640100001401206d617962655f69648801304f7074696f6e3c4e616d653e0001207072696f726974790801487363686564756c653a3a5072696f7269747900011063616c6c5901011043616c6c0001386d617962655f706572696f646963750301944f7074696f6e3c7363686564756c653a3a506572696f643c426c6f636b4e756d6265723e3e0001186f726967696e4503013450616c6c6574734f726967696e000085080000027d080089080c4070616c6c65745f7363686564756c65721870616c6c6574144572726f72040454000114404661696c6564546f5363686564756c65000004644661696c656420746f207363686564756c6520612063616c6c204e6f74466f756e640001047c43616e6e6f742066696e6420746865207363686564756c65642063616c6c2e5c546172676574426c6f636b4e756d626572496e50617374000204a4476976656e2074617267657420626c6f636b206e756d62657220697320696e2074686520706173742e4852657363686564756c654e6f4368616e6765000304f052657363686564756c65206661696c6564206265636175736520697420646f6573206e6f74206368616e6765207363686564756c65642074696d652e144e616d6564000404d0417474656d707420746f207573652061206e6f6e2d6e616d65642066756e6374696f6e206f6e2061206e616d6564207461736b2e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e8d080000029108009108086463756d756c75735f70616c6c65745f78636d705f717565756554496e626f756e644368616e6e656c44657461696c7300000c011873656e646572ad010118506172614964000114737461746595080130496e626f756e6453746174650001406d6573736167655f6d65746164617461990801a85665633c2852656c6179426c6f636b4e756d6265722c2058636d704d657373616765466f726d6174293e00009508086463756d756c75735f70616c6c65745f78636d705f717565756530496e626f756e645374617465000108084f6b0000002453757370656e6465640001000099080000029d08009d080000040810a10800a1080c74706f6c6b61646f745f70617261636861696e5f7072696d697469766573287072696d6974697665734458636d704d657373616765466f726d617400010c60436f6e636174656e6174656456657273696f6e656458636d0000005c436f6e636174656e61746564456e636f646564426c6f620001001c5369676e616c7300020000a50800000408ad011000a908000002ad0800ad08086463756d756c75735f70616c6c65745f78636d705f7175657565584f7574626f756e644368616e6e656c44657461696c730000140124726563697069656e74ad0101185061726149640001147374617465b10801344f7574626f756e6453746174650001347369676e616c735f657869737435010110626f6f6c00012c66697273745f696e6465784901010c7531360001286c6173745f696e6465784901010c7531360000b108086463756d756c75735f70616c6c65745f78636d705f7175657565344f7574626f756e645374617465000108084f6b0000002453757370656e64656400010000b50800000408ad01490100b908086463756d756c75735f70616c6c65745f78636d705f71756575653c5175657565436f6e66696744617461000018014473757370656e645f7468726573686f6c6410010c75333200013864726f705f7468726573686f6c6410010c753332000140726573756d655f7468726573686f6c6410010c7533320001407468726573686f6c645f7765696768742401185765696768740001547765696768745f72657374726963745f646563617924011857656967687400016878636d705f6d61785f696e646976696475616c5f7765696768742401185765696768740000bd080000040cad01103400c1080c6463756d756c75735f70616c6c65745f78636d705f71756575651870616c6c6574144572726f72040454000114304661696c6564546f53656e640000046c4661696c656420746f2073656e642058434d206d6573736167652e3042616458636d4f726967696e0001043c4261642058434d206f726967696e2e1842616458636d000204344261642058434d20646174612e484261644f766572776569676874496e64657800030454426164206f76657277656967687420696e6465782e3c5765696768744f7665724c696d6974000404f850726f76696465642077656967687420697320706f737369626c79206e6f7420656e6f75676820746f206578656375746520746865206d6573736167652e048054686520604572726f726020656e756d206f6620746869732070616c6c65742ec5080c2870616c6c65745f78636d1870616c6c65742c5175657279537461747573042c426c6f636b4e756d6265720110010c1c50656e64696e67100124726573706f6e6465720102015856657273696f6e65644d756c74694c6f636174696f6e00014c6d617962655f6d617463685f71756572696572c90801784f7074696f6e3c56657273696f6e65644d756c74694c6f636174696f6e3e0001306d617962655f6e6f74696679cd0801404f7074696f6e3c2875382c207538293e00011c74696d656f757410012c426c6f636b4e756d6265720000003c56657273696f6e4e6f7469666965720801186f726967696e0102015856657273696f6e65644d756c74694c6f636174696f6e00012469735f61637469766535010110626f6f6c000100145265616479080120726573706f6e7365d508014456657273696f6e6564526573706f6e7365000108617410012c426c6f636b4e756d62657200020000c90804184f7074696f6e0404540101020108104e6f6e6500000010536f6d65040001020000010000cd0804184f7074696f6e04045401d1080108104e6f6e6500000010536f6d650400d1080000010000d10800000408080800d508082c73746167696e675f78636d4456657273696f6e6564526573706f6e736500010808563204009503013076323a3a526573706f6e73650002000856330400c903013076333a3a526573706f6e736500030000d9080000040810010200dd080000040c2c241000e1080c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401e508045300000400e90801185665633c543e0000e5080000040801021000e908000002e50800ed080c2870616c6c65745f78636d1870616c6c65745456657273696f6e4d6967726174696f6e53746167650001105c4d696772617465537570706f7274656456657273696f6e0000005c4d69677261746556657273696f6e4e6f74696669657273000100504e6f7469667943757272656e74546172676574730400f108013c4f7074696f6e3c5665633c75383e3e000200684d696772617465416e644e6f746966794f6c645461726765747300030000f10804184f7074696f6e04045401340108104e6f6e6500000010536f6d650400340000010000f5080000040c1000f90800f908082c73746167696e675f78636d4056657273696f6e6564417373657449640001040856330400d0012c76333a3a4173736574496400030000fd080c2870616c6c65745f78636d1870616c6c65746852656d6f74654c6f636b656446756e6769626c655265636f72640848436f6e73756d65724964656e74696669657201ac304d6178436f6e73756d6572730000100118616d6f756e74180110753132380001146f776e65720102015856657273696f6e65644d756c74694c6f636174696f6e0001186c6f636b65720102015856657273696f6e65644d756c74694c6f636174696f6e000124636f6e73756d657273010901d0426f756e6465645665633c28436f6e73756d65724964656e7469666965722c2075313238292c204d6178436f6e73756d6572733e000001090c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454010509045300000400090901185665633c543e0000050900000408ac180009090000020509000d090c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e646564566563080454011109045300000400150901185665633c543e000011090000040818010200150900000211090019090c2870616c6c65745f78636d1870616c6c6574144572726f720404540001502c556e726561636861626c650000085d0154686520646573697265642064657374696e6174696f6e2077617320756e726561636861626c652c2067656e6572616c6c7920626563617573652074686572652069732061206e6f20776179206f6620726f7574696e6718746f2069742e2c53656e644661696c757265000108410154686572652077617320736f6d65206f746865722069737375652028692e652e206e6f7420746f20646f207769746820726f7574696e672920696e2073656e64696e6720746865206d6573736167652ec8506572686170732061206c61636b206f6620737061636520666f7220627566666572696e6720746865206d6573736167652e2046696c74657265640002049c546865206d65737361676520657865637574696f6e206661696c73207468652066696c7465722e48556e776569676861626c654d657373616765000304b4546865206d65737361676527732077656967687420636f756c64206e6f742062652064657465726d696e65642e6044657374696e6174696f6e4e6f74496e7665727469626c65000404f05468652064657374696e6174696f6e20604d756c74694c6f636174696f6e602070726f76696465642063616e6e6f7420626520696e7665727465642e14456d707479000504805468652061737365747320746f2062652073656e742061726520656d7074792e3843616e6e6f745265616e63686f720006043501436f756c64206e6f742072652d616e63686f72207468652061737365747320746f206465636c61726520746865206665657320666f72207468652064657374696e6174696f6e20636861696e2e34546f6f4d616e79417373657473000704c4546f6f206d616e79206173736574732068617665206265656e20617474656d7074656420666f72207472616e736665722e34496e76616c69644f726967696e000804784f726967696e20697320696e76616c696420666f722073656e64696e672e2842616456657273696f6e00090421015468652076657273696f6e206f6620746865206056657273696f6e6564602076616c75652075736564206973206e6f742061626c6520746f20626520696e7465727072657465642e2c4261644c6f636174696f6e000a08410154686520676976656e206c6f636174696f6e20636f756c64206e6f7420626520757365642028652e672e20626563617573652069742063616e6e6f742062652065787072657373656420696e2074686560646573697265642076657273696f6e206f662058434d292e384e6f537562736372697074696f6e000b04bc546865207265666572656e63656420737562736372697074696f6e20636f756c64206e6f7420626520666f756e642e44416c726561647953756273637269626564000c041101546865206c6f636174696f6e20697320696e76616c69642073696e636520697420616c726561647920686173206120737562736372697074696f6e2066726f6d2075732e30496e76616c69644173736574000d0480496e76616c696420617373657420666f7220746865206f7065726174696f6e2e284c6f7742616c616e6365000e044101546865206f776e657220646f6573206e6f74206f776e2028616c6c29206f662074686520617373657420746861742074686579207769736820746f20646f20746865206f7065726174696f6e206f6e2e30546f6f4d616e794c6f636b73000f04c0546865206173736574206f776e65722068617320746f6f206d616e79206c6f636b73206f6e207468652061737365742e4c4163636f756e744e6f74536f7665726569676e001004310154686520676976656e206163636f756e74206973206e6f7420616e206964656e7469666961626c6520736f7665726569676e206163636f756e7420666f7220616e79206c6f636174696f6e2e28466565734e6f744d65740011042901546865206f7065726174696f6e207265717569726564206665657320746f20626520706169642077686963682074686520696e69746961746f7220636f756c64206e6f74206d6565742e304c6f636b4e6f74466f756e64001204f4412072656d6f7465206c6f636b20776974682074686520636f72726573706f6e64696e67206461746120636f756c64206e6f7420626520666f756e642e14496e557365001304490154686520756e6c6f636b206f7065726174696f6e2063616e6e6f742073756363656564206265636175736520746865726520617265207374696c6c20636f6e73756d657273206f6620746865206c6f636b2e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e1d090c4863756d756c75735f70616c6c65745f78636d1870616c6c6574144572726f72040454000100048054686520604572726f726020656e756d206f6620746869732070616c6c65742e2109086063756d756c75735f70616c6c65745f646d705f717565756528436f6e6669674461746100000401386d61785f696e646976696475616c24011857656967687400002509086063756d756c75735f70616c6c65745f646d705f71756575653450616765496e6465784461746100000c0128626567696e5f7573656410012c50616765436f756e746572000120656e645f7573656410012c50616765436f756e7465720001406f7665727765696768745f636f756e742c013c4f766572776569676874496e646578000029090000022d09002d090000040810340031090c6063756d756c75735f70616c6c65745f646d705f71756575651870616c6c6574144572726f720404540001081c556e6b6e6f776e0000048c546865206d65737361676520696e64657820676976656e20697320756e6b6e6f776e2e244f7665724c696d6974000104310154686520616d6f756e74206f662077656967687420676976656e20697320706f737369626c79206e6f7420656e6f75676820666f7220657865637574696e6720746865206d6573736167652e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e350900000408890400003909000004088904d904003d090000040c8904d904000041090c3470616c6c65745f756e697175651870616c6c6574144572726f7204045400010c8c436f6c6c656374696f6e446563696d616c506f696e744c696d697445786365656465640000045101446563696d616c5f706f696e747320706172616d65746572206d757374206265206c6f776572207468616e205b6075705f646174615f737472756374733a3a4d41585f444543494d414c5f504f494e5453605d2e34456d707479417267756d656e74000104c84c656e677468206f66206974656d732070726f70657274696573206d7573742062652067726561746572207468616e20302ea85265706172746974696f6e43616c6c65644f6e4e6f6e526566756e6769626c65436f6c6c656374696f6e000204dc5265706572746974696f6e206973206f6e6c7920737570706f7274656420627920726566756e6769626c6520636f6c6c656374696f6e2e04a84572726f727320666f722074686520636f6d6d6f6e20556e69717565207472616e73616374696f6e732e45090c5070616c6c65745f636f6e66696775726174696f6e1870616c6c6574144572726f7204045400010464496e636f6e73697374656e74436f6e66696775726174696f6e000000048054686520604572726f726020656e756d206f6620746869732070616c6c65742e4909083c75705f646174615f7374727563747328436f6c6c656374696f6e04244163636f756e7449640100002401146f776e65720001244163636f756e7449640001106d6f646545040138436f6c6c656374696f6e4d6f64650001106e616d6535040138436f6c6c656374696f6e4e616d6500012c6465736372697074696f6e3d040154436f6c6c656374696f6e4465736372697074696f6e000130746f6b656e5f70726566697841040154436f6c6c656374696f6e546f6b656e50726566697800012c73706f6e736f72736869704d09016c53706f6e736f727368697053746174653c4163636f756e7449643e0001186c696d6974735d040140436f6c6c656374696f6e4c696d69747300012c7065726d697373696f6e7371040154436f6c6c656374696f6e5065726d697373696f6e73000114666c6167736902013c436f6c6c656374696f6e466c61677300004d09083c75705f646174615f737472756374734053706f6e736f7273686970537461746504244163636f756e7449640100010c2044697361626c65640000002c556e636f6e6669726d656404000001244163636f756e74496400010024436f6e6669726d656404000001244163636f756e744964000200005109083c75705f646174615f737472756374732850726f7065727469657300000c010c6d61705509017050726f706572746965734d61703c50726f706572747956616c75653e000138636f6e73756d65645f737061636510010c7533320001245f726573657276656410010c75333200005509083c75705f646174615f737472756374733450726f706572746965734d6170041456616c756501b1040004005909011901426f756e64656442547265654d61703c50726f70657274794b65792c2056616c75652c20436f6e73745533323c4d41585f50524f504552544945535f5045525f4954454d3e3e000059090c4c626f756e6465645f636f6c6c656374696f6e7344626f756e6465645f62747265655f6d61703c426f756e64656442547265654d61700c044b019d04045601b1040453000004005d09013842547265654d61703c4b2c20563e00005d09042042547265654d617008044b019d04045601b104000400610900000061090000026509006509000004089d04b104006909083c75705f646174615f737472756374733450726f706572746965734d6170041456616c756501a1040004006d09011901426f756e64656442547265654d61703c50726f70657274794b65792c2056616c75652c20436f6e73745533323c4d41585f50524f504552544945535f5045525f4954454d3e3e00006d090c4c626f756e6465645f636f6c6c656374696f6e7344626f756e6465645f62747265655f6d61703c426f756e64656442547265654d61700c044b019d04045601a1040453000004007109013842547265654d61703c4b2c20563e00007109042042547265654d617008044b019d04045601a104000400750900000075090000027909007909000004089d04a104007d090000040889044d040081090000041485098904d90489098d09008509083c75705f646174615f737472756374733c436f6c6c656374696f6e537461747300000c011c6372656174656410010c75333200012464657374726f79656410010c753332000114616c69766510010c75333200008909083c75705f646174615f7374727563747328546f6b656e4368696c640000080114746f6b656ed904011c546f6b656e4964000128636f6c6c656374696f6e89040130436f6c6c656374696f6e496400008d09082c5068616e746f6d547970653c75705f646174615f73747275637473040454019109000400c10900000091090000040c95099909a109009509083c75705f646174615f7374727563747324546f6b656e44617461043843726f73734163636f756e744964014d04000c012870726f70657274696573b50401345665633c50726f70657274793e0001146f776e6572bd0401584f7074696f6e3c43726f73734163636f756e7449643e0001187069656365731801107531323800009909083c75705f646174615f7374727563747334527063436f6c6c656374696f6e04244163636f756e7449640100003001146f776e65720001244163636f756e7449640001106d6f646545040138436f6c6c656374696f6e4d6f64650001106e616d65390401205665633c7531363e00012c6465736372697074696f6e390401205665633c7531363e000130746f6b656e5f70726566697834011c5665633c75383e00012c73706f6e736f72736869704d09016c53706f6e736f727368697053746174653c4163636f756e7449643e0001186c696d6974735d040140436f6c6c656374696f6e4c696d69747300012c7065726d697373696f6e7371040154436f6c6c656374696f6e5065726d697373696f6e73000168746f6b656e5f70726f70657274795f7065726d697373696f6e73a50401685665633c50726f70657274794b65795065726d697373696f6e3e00012870726f70657274696573b50401345665633c50726f70657274793e000124726561645f6f6e6c7935010110626f6f6c000114666c6167739d090148527063436f6c6c656374696f6e466c61677300009d09083c75705f646174615f7374727563747348527063436f6c6c656374696f6e466c616773000008011c666f726569676e35010110626f6f6c0001386572633732316d6574616461746135010110626f6f6c0000a109084c75705f706f765f657374696d6174655f7270631c506f76496e666f000014012870726f6f665f73697a652c010c753634000148636f6d706163745f70726f6f665f73697a652c010c753634000154636f6d707265737365645f70726f6f665f73697a652c010c75363400011c726573756c7473a50901645665633c4170706c7945787472696e736963526573756c743e0001286b65795f76616c756573b90901445665633c547269654b657956616c75653e0000a509000002a90900a9090418526573756c7408045401a8044501ad090108084f6b0400a8000000000c4572720400ad090000010000ad090c2873705f72756e74696d65507472616e73616374696f6e5f76616c6964697479605472616e73616374696f6e56616c69646974794572726f720001081c496e76616c69640400b1090148496e76616c69645472616e73616374696f6e0000001c556e6b6e6f776e0400b5090148556e6b6e6f776e5472616e73616374696f6e00010000b1090c2873705f72756e74696d65507472616e73616374696f6e5f76616c696469747948496e76616c69645472616e73616374696f6e00012c1043616c6c0000001c5061796d656e7400010018467574757265000200145374616c650003002042616450726f6f6600040044416e6369656e744269727468426c6f636b0005004445786861757374735265736f757263657300060018437573746f6d04000801087538000700304261644d616e6461746f72790008004c4d616e6461746f727956616c69646174696f6e000900244261645369676e6572000a0000b5090c2873705f72756e74696d65507472616e73616374696f6e5f76616c696469747948556e6b6e6f776e5472616e73616374696f6e00010c3043616e6e6f744c6f6f6b75700000004c4e6f556e7369676e656456616c696461746f7200010018437573746f6d0400080108753800020000b909000002bd0900bd09084c75705f706f765f657374696d6174655f72706330547269654b657956616c7565000008010c6b657934011c5665633c75383e00011476616c756534011c5665633c75383e0000c10900000300000000910900c5090c3470616c6c65745f636f6d6d6f6e1870616c6c6574144572726f7204045400019848436f6c6c656374696f6e4e6f74466f756e640000047c5468697320636f6c6c656374696f6e20646f6573206e6f742065786973742e404d7573744265546f6b656e4f776e6572000104b853656e64657220706172616d6574657220616e64206974656d206f776e6572206d75737420626520657175616c2e304e6f5065726d697373696f6e0002047c4e6f207065726d697373696f6e20746f20706572666f726d20616374696f6e7443616e7444657374726f794e6f74456d707479436f6c6c656374696f6e000304b044657374726f79696e67206f6e6c7920656d70747920636f6c6c656374696f6e7320697320616c6c6f7765645c5075626c69634d696e74696e674e6f74416c6c6f7765640004047c436f6c6c656374696f6e206973206e6f7420696e206d696e74206d6f64652e54416464726573734e6f74496e416c6c6f776c6973740005047441646472657373206973206e6f7420696e20616c6c6f77206c6973742e6c436f6c6c656374696f6e4e616d654c696d69744578636565646564000604bc436f6c6c656374696f6e206e616d652063616e206e6f74206265206c6f6e676572207468616e20363320636861722e88436f6c6c656374696f6e4465736372697074696f6e4c696d69744578636565646564000704dc436f6c6c656374696f6e206465736372697074696f6e2063616e206e6f74206265206c6f6e676572207468616e2032353520636861722e88436f6c6c656374696f6e546f6b656e5072656669784c696d69744578636565646564000804b0546f6b656e207072656669782063616e206e6f74206265206c6f6e676572207468616e20313520636861722e74546f74616c436f6c6c656374696f6e734c696d6974457863656564656400090484546f74616c20636f6c6c656374696f6e7320626f756e642065786365656465642e70436f6c6c656374696f6e41646d696e436f756e744578636565646564000a04604578636565646564206d61782061646d696e20636f756e7474436f6c6c656374696f6e4c696d6974426f756e64734578636565646564000b04bc436f6c6c656374696f6e206c696d697420626f756e64732070657220636f6c6c656374696f6e206578636565646564784f776e65725065726d697373696f6e7343616e7442655265766572746564000c040d01547269656420746f20656e61626c65207065726d697373696f6e7320776869636820617265206f6e6c79207065726d697474656420746f2062652064697361626c6564485472616e736665724e6f74416c6c6f776564000d04cc436f6c6c656374696f6e2073657474696e6773206e6f7420616c6c6f77696e67206974656d73207472616e7366657272696e67644163636f756e74546f6b656e4c696d69744578636565646564000e04ac4163636f756e7420746f6b656e206c696d69742065786365656465642070657220636f6c6c656374696f6e70436f6c6c656374696f6e546f6b656e4c696d69744578636565646564000f047c436f6c6c656374696f6e20746f6b656e206c696d6974206578636565646564484d65746164617461466c616746726f7a656e001004504d6574616461746120666c61672066726f7a656e34546f6b656e4e6f74466f756e640011044c4974656d20646f6573206e6f7420657869737440546f6b656e56616c7565546f6f4c6f77001204684974656d2069732062616c616e6365206e6f7420656e6f7567684c417070726f76656456616c7565546f6f4c6f77001304a45265717565737465642076616c7565206973206d6f7265207468616e2074686520617070726f7665646043616e74417070726f76654d6f72655468616e4f776e656400140480547269656420746f20617070726f7665206d6f7265207468616e206f776e6564544164647265737349734e6f744574684d6972726f72001504bc4f6e6c79207370656e64696e672066726f6d20657468206d6972726f7220636f756c6420626520617070726f766564344164647265737349735a65726f001604b843616e2774207472616e7366657220746f6b656e7320746f20657468657265756d207a65726f206164647265737350556e737570706f727465644f7065726174696f6e00170478546865206f7065726174696f6e206973206e6f7420737570706f727465644c4e6f7453756666696369656e74466f756e64730018049c496e73756666696369656e742066756e647320746f20706572666f726d20616e20616374696f6e585573657249734e6f74416c6c6f776564546f4e657374001904985573657220646f6573206e6f74207361746973667920746865206e657374696e672072756c6588536f75726365436f6c6c656374696f6e49734e6f74416c6c6f776564546f4e657374001a0411014f6e6c7920746f6b656e732066726f6d20737065636966696320636f6c6c656374696f6e73206d6179206e65737420746f6b656e7320756e6465722074686973206f6e656c436f6c6c656374696f6e4669656c6453697a654578636565646564001b04e4547269656420746f2073746f7265206d6f72652064617461207468616e20616c6c6f77656420696e20636f6c6c656374696f6e206669656c64484e6f5370616365466f7250726f7065727479001c04b8547269656420746f2073746f7265206d6f72652070726f70657274792064617461207468616e20616c6c6f7765645050726f70657274794c696d697452656163686564001d04b8547269656420746f2073746f7265206d6f72652070726f7065727479206b657973207468616e20616c6c6f7765645050726f70657274794b65794973546f6f4c6f6e67001e046050726f7065727479206b657920697320746f6f206c6f6e6774496e76616c6964436861726163746572496e50726f70657274794b6579001f0415014f6e6c79204153434949206c6574746572732c206469676974732c20616e642073796d626f6c7320605f602c20602d602c20616e6420602e602061726520616c6c6f77656440456d70747950726f70657274794b657900200484456d7074792070726f7065727479206b6579732061726520666f7262696464656e50436f6c6c656374696f6e497345787465726e616c002104ec547269656420746f2061636365737320616e2065787465726e616c20636f6c6c656374696f6e207769746820616e20696e7465726e616c2041504950436f6c6c656374696f6e4973496e7465726e616c002204ec547269656420746f2061636365737320616e20696e7465726e616c20636f6c6c656374696f6e207769746820616e2065787465726e616c2041504958436f6e6669726d53706f6e736f72736869704661696c0023040d01546869732061646472657373206973206e6f74207365742061732073706f6e736f722c2075736520736574436f6c6c656374696f6e53706f6e736f722066697273742e605573657249734e6f74436f6c6c656374696f6e41646d696e002404845468652075736572206973206e6f7420616e2061646d696e6973747261746f722e5446756e6769626c654974656d73486176654e6f4964002504710146756e6769626c6520746f6b656e7320686f6c64206e6f2049442c20616e64207468652064656661756c742076616c7565206f6620546f6b656e496420666f7220612066756e6769626c6520636f6c6c656374696f6e20697320302e048054686520604572726f726020656e756d206f6620746869732070616c6c65742ec9090000040c89044d044d0400cd090c3c70616c6c65745f66756e6769626c651870616c6c6574144572726f72040454000118c04e6f7446756e6769626c654461746155736564546f4d696e7446756e6769626c65436f6c6c656374696f6e546f6b656e000004ec4e6f742046756e6769626c65206974656d2064617461207573656420746f206d696e7420696e2046756e6769626c6520636f6c6c656374696f6e2e6446756e6769626c654974656d73446f6e74486176654461746100010490547269656420746f20736574206461746120666f722066756e6769626c65206974656d2e6046756e6769626c65446973616c6c6f77734e657374696e67000204a046756e6769626c6520746f6b656e20646f6573206e6f7420737570706f7274206e657374696e672e6c53657474696e6750726f706572746965734e6f74416c6c6f7765640003049c53657474696e67206974656d2070726f70657274696573206973206e6f7420616c6c6f7765642e8053657474696e67416c6c6f77616e6365466f72416c6c4e6f74416c6c6f776564000404a453657474696e6720616c6c6f77616e636520666f7220616c6c206973206e6f7420616c6c6f7765642e7046756e6769626c65546f6b656e73417265416c7761797356616c696400050445014f6e6c7920612066756e6769626c6520636f6c6c656374696f6e20636f756c6420626520706f737369626c792062726f6b656e3b20616e792066756e6769626c6520746f6b656e2069732076616c69642e048054686520604572726f726020656e756d206f6620746869732070616c6c65742ed109083c75705f646174615f737472756374732850726f7065727469657300000c010c6d61705509017050726f706572746965734d61703c50726f706572747956616c75653e000138636f6e73756d65645f737061636510010c7533320001245f726573657276656410010c7533320000d5090000040c89044d04d90400d9090000040c8904d9044d0400dd09000004108904d9044d044d0400e1090c4470616c6c65745f726566756e6769626c651870616c6c6574144572726f72040454000114c84e6f74526566756e6769626c654461746155736564546f4d696e7446756e6769626c65436f6c6c656374696f6e546f6b656e000004fc4e6f7420526566756e6769626c65206974656d2064617461207573656420746f206d696e7420696e20526566756e6769626c6520636f6c6c656374696f6e2e5457726f6e67526566756e6769626c655069656365730001047c4d6178696d756d20726566756e676962696c6974792065786365656465642e885265706172746974696f6e5768696c654e6f744f776e696e67416c6c5069656365730002042901526566756e6769626c6520746f6b656e2063616e2774206265207265706172746974696f6e656420627920757365722077686f2069736e2774206f776e7320616c6c207069656365732e68526566756e6769626c65446973616c6c6f77734e657374696e67000304a4526566756e6769626c6520746f6b656e2063616e2774206e657374206f7468657220746f6b656e732e6c53657474696e6750726f706572746965734e6f74416c6c6f7765640004049c53657474696e67206974656d2070726f70657274696573206973206e6f7420616c6c6f7765642e048054686520604572726f726020656e756d206f6620746869732070616c6c65742ee509084870616c6c65745f6e6f6e66756e6769626c65204974656d44617461043843726f73734163636f756e744964014d04000401146f776e65724d04013843726f73734163636f756e7449640000e909000004108904d904ed099d0400ed09083c75705f646174615f737472756374733450726f706572747953636f7065000108104e6f6e6500000010526d726b00010000f1090c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401080453000004003401185665633c543e0000f5090000040c8904d904390900f9090c4870616c6c65745f6e6f6e66756e6769626c651870616c6c6574144572726f7204045400010ccc4e6f744e6f6e66756e6769626c654461746155736564546f4d696e7446756e6769626c65436f6c6c656374696f6e546f6b656e00000405014e6f74204e6f6e66756e6769626c65206974656d2064617461207573656420746f206d696e7420696e204e6f6e66756e6769626c6520636f6c6c656374696f6e2e704e6f6e66756e6769626c654974656d73486176654e6f416d6f756e74000104605573656420616d6f756e74203e20312077697468204e46545c43616e744275726e4e6674576974684368696c6472656e00020480556e61626c6520746f206275726e204e46542077697468206368696c6472656e048054686520604572726f726020656e756d206f6620746869732070616c6c65742efd090c4070616c6c65745f7374727563747572651870616c6c6574144572726f72040454000114444f75726f626f726f73446574656374656400000421015768696c65206e657374696e672c20656e636f756e746572656420616e20616c726561647920636865636b6564206163636f756e742c20646574656374696e672061206c6f6f702e2844657074684c696d697400010445015768696c65206e657374696e672c207265616368656420746865206465707468206c696d6974206f66206e657374696e672c20657863656564696e67207468652070726f7669646564206275646765742e30427265616474684c696d69740002044d015768696c65206e657374696e672c2072656163686564207468652062726561647468206c696d6974206f66206e657374696e672c20657863656564696e67207468652070726f7669646564206275646765742e34546f6b656e4e6f74466f756e64000304d4436f756c646e27742066696e642074686520746f6b656e206f776e6572207468617420697320697473656c66206120746f6b656e2e7043616e744e657374546f6b656e556e646572436f6c6c656374696f6e0004043d01547269656420746f206e65737420746f6b656e20756e64657220636f6c6c656374696f6e20636f6e747261637420616464726573732c20696e7374656164206f6620746f6b656e2061646472657373048054686520604572726f726020656e756d206f6620746869732070616c6c65742e010a00000408001000050a00000408181000090a0c4c626f756e6465645f636f6c6c656374696f6e732c626f756e6465645f76656328426f756e64656456656308045401a5070453000004000d0a01185665633c543e00000d0a000002a50700110a0c5070616c6c65745f6170705f70726f6d6f74696f6e1870616c6c6574144572726f7204045400011c2c41646d696e4e6f74536574000004b84572726f722064756520746f20616374696f6e20726571756972696e672061646d696e20746f206265207365742e304e6f5065726d697373696f6e0001048c4e6f207065726d697373696f6e20746f20706572666f726d20616e20616374696f6e2e484e6f7453756666696369656e7446756e6473000204a0496e73756666696369656e742066756e647320746f20706572666f726d20616e20616374696f6e2e5c50656e64696e67466f72426c6f636b4f766572666c6f7700030499014f6363757273207768656e20612070656e64696e6720756e7374616b652063616e6e6f7420626520616464656420696e207468697320626c6f636b2e2050454e44494e475f4c494d49545f5045525f424c4f434b60206c696d6974732065786365656465642e3453706f6e736f724e6f74536574000404cd01546865206572726f722069732064756520746f20746865206661637420746861742074686520636f6c6c656374696f6e2f636f6e7472616374206d75737420616c72656164792062652073706f6e736f72656420696e206f7264657220746f20706572666f726d2074686520616374696f6e2e64496e73756666696369656e745374616b656442616c616e6365000504b44572726f72732063617573656420627920696e73756666696369656e74207374616b65642062616c616e63652e48496e636f6e73697374656e6379537461746500060419014572726f72732063617573656420627920696e636f7272656374207374617465206f662061207374616b657220696e20636f6e74657874206f66207468652070616c6c65742e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e150a0c5470616c6c65745f666f726569676e5f617373657473186d6f64756c65144572726f720404540001102c4261644c6f636174696f6e000008410154686520676976656e206c6f636174696f6e20636f756c64206e6f7420626520757365642028652e672e20626563617573652069742063616e6e6f742062652065787072657373656420696e2074686560646573697265642076657273696f6e206f662058434d292e504d756c74694c6f636174696f6e45786973746564000104544d756c74694c6f636174696f6e206578697374656440417373657449644e6f744578697374730002044841737365744964206e6f7420657869737473384173736574496445786973746564000304384173736574496420657869737473048054686520604572726f726020656e756d206f6620746869732070616c6c65742e190a082870616c6c65745f65766d30436f64654d65746164617461000008011073697a652c010c753634000110686173683001104832353600001d0a0000040865033000210a0c2870616c6c65745f65766d1870616c6c6574144572726f7204045400012c2842616c616e63654c6f77000004904e6f7420656e6f7567682062616c616e636520746f20706572666f726d20616374696f6e2c4665654f766572666c6f770001048043616c63756c6174696e6720746f74616c20666565206f766572666c6f7765643c5061796d656e744f766572666c6f770002049043616c63756c6174696e6720746f74616c207061796d656e74206f766572666c6f7765643857697468647261774661696c65640003044c576974686472617720666565206661696c6564384761735072696365546f6f4c6f770004045447617320707269636520697320746f6f206c6f772e30496e76616c69644e6f6e6365000504404e6f6e636520697320696e76616c6964384761734c696d6974546f6f4c6f7700060454476173206c696d697420697320746f6f206c6f772e3c4761734c696d6974546f6f4869676800070458476173206c696d697420697320746f6f20686967682e24556e646566696e656400080440556e646566696e6564206572726f722e285265656e7472616e63790009043845564d207265656e7472616e6379685472616e73616374696f6e4d757374436f6d6546726f6d454f41000a04244549502d333630372c048054686520604572726f726020656e756d206f6620746869732070616c6c65742e250a000002290a00290a0000040c65052d0a3d0a002d0a081866705f727063445472616e73616374696f6e53746174757300001c01407472616e73616374696f6e5f68617368300110483235360001447472616e73616374696f6e5f696e64657810010c75333200011066726f6d6503011048313630000108746f310a01304f7074696f6e3c483136303e000140636f6e74726163745f61646472657373310a01304f7074696f6e3c483136303e0001106c6f67739d0501205665633c4c6f673e0001286c6f67735f626c6f6f6d350a0114426c6f6f6d0000310a04184f7074696f6e0404540165030108104e6f6e6500000010536f6d65040065030000010000350a0820657468626c6f6f6d14426c6f6f6d00000400390a01405b75383b20424c4f4f4d5f53495a455d0000390a0000030001000008003d0a0c20657468657265756d1c726563656970742452656365697074563300010c184c65676163790400410a014445495036353852656365697074446174610000001c454950323933300400410a01484549503239333052656365697074446174610001001c454950313535390400410a014845495031353539526563656970744461746100020000410a0c20657468657265756d1c72656365697074444549503635385265636569707444617461000010012c7374617475735f636f64650801087538000120757365645f67617349050110553235360001286c6f67735f626c6f6f6d350a0114426c6f6f6d0001106c6f67739d0501205665633c4c6f673e0000450a0c20657468657265756d14626c6f636b14426c6f636b040454016505000c0118686561646572490a01184865616465720001307472616e73616374696f6e73510a01185665633c543e0001186f6d6d657273550a012c5665633c4865616465723e0000490a0c20657468657265756d186865616465721848656164657200003c012c706172656e745f686173683001104832353600012c6f6d6d6572735f686173683001104832353600012c62656e6566696369617279650301104831363000012873746174655f726f6f74300110483235360001447472616e73616374696f6e735f726f6f743001104832353600013472656365697074735f726f6f74300110483235360001286c6f67735f626c6f6f6d350a0114426c6f6f6d000128646966666963756c747949050110553235360001186e756d62657249050110553235360001246761735f6c696d697449050110553235360001206761735f75736564490501105532353600012474696d657374616d702c010c75363400012865787472615f6461746134011442797465730001206d69785f68617368300110483235360001146e6f6e63654d0a010c48363400004d0a0c38657468657265756d5f747970657310686173680c483634000004000101011c5b75383b20385d0000510a000002650500550a000002490a00590a0000023d0a005d0a0000022d0a00610a0c3c70616c6c65745f657468657265756d1870616c6c6574144572726f7204045400010840496e76616c69645369676e6174757265000004545369676e617475726520697320696e76616c69642e305072654c6f67457869737473000104d85072652d6c6f672069732070726573656e742c207468657265666f7265207472616e73616374206973206e6f7420616c6c6f7765642e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e650a0c6870616c6c65745f65766d5f636f6465725f7375627374726174651870616c6c6574144572726f72040454000108204f75744f66476173000000244f75744f6646756e6400010014850144697370617463684572726f72206973206f70617175652c20627574207765206e65656420746f20736f6d65686f77206578747261637420636f7272656374206572726f7220696e2063617365206f66204f75744f66476173206661696c7572659101536f207765206861766520746869732070616c6c65742c20776869636820646566696e6573204f75744f66476173206572726f722c20616e64206b6e65777320697473206f776e20696420746f20636865636b2069662044697370617463684572726f725c6973207468726f776e2062656361757365206f662069740061015468657365206572726f72732073686f756c646e277420656e6420696e2065787472696e73696320726573756c74732c2061732074686579206f6e6c79207573656420696e2065766d20657865637574696f6e2070617468690a083c75705f646174615f737472756374734053706f6e736f7273686970537461746504244163636f756e744964014d04010c2044697361626c65640000002c556e636f6e6669726d656404004d0401244163636f756e74496400010024436f6e6669726d656404004d0401244163636f756e744964000200006d0a086c70616c6c65745f65766d5f636f6e74726163745f68656c706572733c53706f6e736f72696e674d6f64655400010c2044697361626c65640000002c416c6c6f776c69737465640001002047656e65726f757300020000710a0c4c626f756e6465645f636f6c6c656374696f6e7344626f756e6465645f62747265655f6d61703c426f756e64656442547265654d61700c044b01100456014905045300000400750a013842547265654d61703c4b2c20563e0000750a042042547265654d617008044b01100456014905000400790a000000790a0000027d0a007d0a0000040810490500810a000004086503650300850a0c6c70616c6c65745f65766d5f636f6e74726163745f68656c706572731870616c6c6574144572726f7204045400010c304e6f5065726d697373696f6e000004c054686973206d6574686f64206973206f6e6c792065786563757461626c6520627920636f6e7472616374206f776e6572404e6f50656e64696e6753706f6e736f72000104804e6f2070656e64696e672073706f6e736f7220666f7220636f6e74726163742e80546f6f4d616e794d6574686f64734861766553706f6e736f7265644c696d697400020419014e756d626572206f66206d6574686f647320746861742073706f6e736f726564206c696d697420697320646566696e656420666f722065786365656473206d6178696d756d2e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e890a0c5070616c6c65745f65766d5f6d6967726174696f6e1870616c6c6574144572726f7204045400010c3c4163636f756e744e6f74456d7074790000048843616e206f6e6c79206d69677261746520746f20656d70747920616464726573732e544163636f756e7449734e6f744d6967726174696e6700010409014d6967726174696f6e206f662074686973206163636f756e74206973206e6f742079657420737461727465642c206f7220616c72656164792066696e69736865642e204261644576656e74000204704661696c656420746f206465636f6465206576656e74206279746573048054686520604572726f726020656e756d206f6620746869732070616c6c65742e8d0a0c4870616c6c65745f6d61696e74656e616e63651870616c6c6574144572726f72040454000100048054686520604572726f726020656e756d206f6620746869732070616c6c65742e910a0c3870616c6c65745f7574696c6974791870616c6c6574144572726f7204045400010430546f6f4d616e7943616c6c730000045c546f6f206d616e792063616c6c7320626174636865642e048054686520604572726f726020656e756d206f6620746869732070616c6c65742e950a0c4470616c6c65745f746573745f7574696c731870616c6c6574144572726f72040454000108485465737450616c6c657444697361626c65640000003c54726967676572526f6c6c6261636b000100048054686520604572726f726020656e756d206f6620746869732070616c6c65742e990a0c4466705f73656c665f636f6e7461696e65644c756e636865636b65645f65787472696e73696348556e636865636b656445787472696e736963101c4164647265737301dd011043616c6c015d01245369676e6174757265019d0a14457874726101b50a000400e90a01250173705f72756e74696d653a3a67656e657269633a3a556e636865636b656445787472696e7369633c416464726573732c2043616c6c2c205369676e61747572652c2045787472610a3e00009d0a082873705f72756e74696d65384d756c74695369676e617475726500010c1c456432353531390400a10a0148656432353531393a3a5369676e61747572650000001c537232353531390400a90a0148737232353531393a3a5369676e61747572650001001445636473610400ad0a014065636473613a3a5369676e617475726500020000a10a0c1c73705f636f72651c65643235353139245369676e617475726500000400a50a01205b75383b2036345d0000a50a000003400000000800a90a0c1c73705f636f72651c73723235353139245369676e617475726500000400a50a01205b75383b2036345d0000ad0a0c1c73705f636f7265146563647361245369676e617475726500000400b10a01205b75383b2036355d0000b10a000003410000000800b50a00000428b90abd0ac10ac50acd0ad10ad50ad90add0ae50a00b90a10306672616d655f73797374656d28657874656e73696f6e7348636865636b5f737065635f76657273696f6e40436865636b5370656356657273696f6e04045400000000bd0a10306672616d655f73797374656d28657874656e73696f6e7340636865636b5f74785f76657273696f6e38436865636b547856657273696f6e04045400000000c10a10306672616d655f73797374656d28657874656e73696f6e7334636865636b5f67656e6573697330436865636b47656e6573697304045400000000c50a10306672616d655f73797374656d28657874656e73696f6e733c636865636b5f6d6f7274616c69747938436865636b4d6f7274616c69747904045400000400c90a010c4572610000c90a102873705f72756e74696d651c67656e657269630c6572610c4572610001010420496d6d6f7274616c0000001c4d6f7274616c31040008000001001c4d6f7274616c32040008000002001c4d6f7274616c33040008000003001c4d6f7274616c34040008000004001c4d6f7274616c35040008000005001c4d6f7274616c36040008000006001c4d6f7274616c37040008000007001c4d6f7274616c38040008000008001c4d6f7274616c3904000800000900204d6f7274616c313004000800000a00204d6f7274616c313104000800000b00204d6f7274616c313204000800000c00204d6f7274616c313304000800000d00204d6f7274616c313404000800000e00204d6f7274616c313504000800000f00204d6f7274616c313604000800001000204d6f7274616c313704000800001100204d6f7274616c313804000800001200204d6f7274616c313904000800001300204d6f7274616c323004000800001400204d6f7274616c323104000800001500204d6f7274616c323204000800001600204d6f7274616c323304000800001700204d6f7274616c323404000800001800204d6f7274616c323504000800001900204d6f7274616c323604000800001a00204d6f7274616c323704000800001b00204d6f7274616c323804000800001c00204d6f7274616c323904000800001d00204d6f7274616c333004000800001e00204d6f7274616c333104000800001f00204d6f7274616c333204000800002000204d6f7274616c333304000800002100204d6f7274616c333404000800002200204d6f7274616c333504000800002300204d6f7274616c333604000800002400204d6f7274616c333704000800002500204d6f7274616c333804000800002600204d6f7274616c333904000800002700204d6f7274616c343004000800002800204d6f7274616c343104000800002900204d6f7274616c343204000800002a00204d6f7274616c343304000800002b00204d6f7274616c343404000800002c00204d6f7274616c343504000800002d00204d6f7274616c343604000800002e00204d6f7274616c343704000800002f00204d6f7274616c343804000800003000204d6f7274616c343904000800003100204d6f7274616c353004000800003200204d6f7274616c353104000800003300204d6f7274616c353204000800003400204d6f7274616c353304000800003500204d6f7274616c353404000800003600204d6f7274616c353504000800003700204d6f7274616c353604000800003800204d6f7274616c353704000800003900204d6f7274616c353804000800003a00204d6f7274616c353904000800003b00204d6f7274616c363004000800003c00204d6f7274616c363104000800003d00204d6f7274616c363204000800003e00204d6f7274616c363304000800003f00204d6f7274616c363404000800004000204d6f7274616c363504000800004100204d6f7274616c363604000800004200204d6f7274616c363704000800004300204d6f7274616c363804000800004400204d6f7274616c363904000800004500204d6f7274616c373004000800004600204d6f7274616c373104000800004700204d6f7274616c373204000800004800204d6f7274616c373304000800004900204d6f7274616c373404000800004a00204d6f7274616c373504000800004b00204d6f7274616c373604000800004c00204d6f7274616c373704000800004d00204d6f7274616c373804000800004e00204d6f7274616c373904000800004f00204d6f7274616c383004000800005000204d6f7274616c383104000800005100204d6f7274616c383204000800005200204d6f7274616c383304000800005300204d6f7274616c383404000800005400204d6f7274616c383504000800005500204d6f7274616c383604000800005600204d6f7274616c383704000800005700204d6f7274616c383804000800005800204d6f7274616c383904000800005900204d6f7274616c393004000800005a00204d6f7274616c393104000800005b00204d6f7274616c393204000800005c00204d6f7274616c393304000800005d00204d6f7274616c393404000800005e00204d6f7274616c393504000800005f00204d6f7274616c393604000800006000204d6f7274616c393704000800006100204d6f7274616c393804000800006200204d6f7274616c393904000800006300244d6f7274616c31303004000800006400244d6f7274616c31303104000800006500244d6f7274616c31303204000800006600244d6f7274616c31303304000800006700244d6f7274616c31303404000800006800244d6f7274616c31303504000800006900244d6f7274616c31303604000800006a00244d6f7274616c31303704000800006b00244d6f7274616c31303804000800006c00244d6f7274616c31303904000800006d00244d6f7274616c31313004000800006e00244d6f7274616c31313104000800006f00244d6f7274616c31313204000800007000244d6f7274616c31313304000800007100244d6f7274616c31313404000800007200244d6f7274616c31313504000800007300244d6f7274616c31313604000800007400244d6f7274616c31313704000800007500244d6f7274616c31313804000800007600244d6f7274616c31313904000800007700244d6f7274616c31323004000800007800244d6f7274616c31323104000800007900244d6f7274616c31323204000800007a00244d6f7274616c31323304000800007b00244d6f7274616c31323404000800007c00244d6f7274616c31323504000800007d00244d6f7274616c31323604000800007e00244d6f7274616c31323704000800007f00244d6f7274616c31323804000800008000244d6f7274616c31323904000800008100244d6f7274616c31333004000800008200244d6f7274616c31333104000800008300244d6f7274616c31333204000800008400244d6f7274616c31333304000800008500244d6f7274616c31333404000800008600244d6f7274616c31333504000800008700244d6f7274616c31333604000800008800244d6f7274616c31333704000800008900244d6f7274616c31333804000800008a00244d6f7274616c31333904000800008b00244d6f7274616c31343004000800008c00244d6f7274616c31343104000800008d00244d6f7274616c31343204000800008e00244d6f7274616c31343304000800008f00244d6f7274616c31343404000800009000244d6f7274616c31343504000800009100244d6f7274616c31343604000800009200244d6f7274616c31343704000800009300244d6f7274616c31343804000800009400244d6f7274616c31343904000800009500244d6f7274616c31353004000800009600244d6f7274616c31353104000800009700244d6f7274616c31353204000800009800244d6f7274616c31353304000800009900244d6f7274616c31353404000800009a00244d6f7274616c31353504000800009b00244d6f7274616c31353604000800009c00244d6f7274616c31353704000800009d00244d6f7274616c31353804000800009e00244d6f7274616c31353904000800009f00244d6f7274616c3136300400080000a000244d6f7274616c3136310400080000a100244d6f7274616c3136320400080000a200244d6f7274616c3136330400080000a300244d6f7274616c3136340400080000a400244d6f7274616c3136350400080000a500244d6f7274616c3136360400080000a600244d6f7274616c3136370400080000a700244d6f7274616c3136380400080000a800244d6f7274616c3136390400080000a900244d6f7274616c3137300400080000aa00244d6f7274616c3137310400080000ab00244d6f7274616c3137320400080000ac00244d6f7274616c3137330400080000ad00244d6f7274616c3137340400080000ae00244d6f7274616c3137350400080000af00244d6f7274616c3137360400080000b000244d6f7274616c3137370400080000b100244d6f7274616c3137380400080000b200244d6f7274616c3137390400080000b300244d6f7274616c3138300400080000b400244d6f7274616c3138310400080000b500244d6f7274616c3138320400080000b600244d6f7274616c3138330400080000b700244d6f7274616c3138340400080000b800244d6f7274616c3138350400080000b900244d6f7274616c3138360400080000ba00244d6f7274616c3138370400080000bb00244d6f7274616c3138380400080000bc00244d6f7274616c3138390400080000bd00244d6f7274616c3139300400080000be00244d6f7274616c3139310400080000bf00244d6f7274616c3139320400080000c000244d6f7274616c3139330400080000c100244d6f7274616c3139340400080000c200244d6f7274616c3139350400080000c300244d6f7274616c3139360400080000c400244d6f7274616c3139370400080000c500244d6f7274616c3139380400080000c600244d6f7274616c3139390400080000c700244d6f7274616c3230300400080000c800244d6f7274616c3230310400080000c900244d6f7274616c3230320400080000ca00244d6f7274616c3230330400080000cb00244d6f7274616c3230340400080000cc00244d6f7274616c3230350400080000cd00244d6f7274616c3230360400080000ce00244d6f7274616c3230370400080000cf00244d6f7274616c3230380400080000d000244d6f7274616c3230390400080000d100244d6f7274616c3231300400080000d200244d6f7274616c3231310400080000d300244d6f7274616c3231320400080000d400244d6f7274616c3231330400080000d500244d6f7274616c3231340400080000d600244d6f7274616c3231350400080000d700244d6f7274616c3231360400080000d800244d6f7274616c3231370400080000d900244d6f7274616c3231380400080000da00244d6f7274616c3231390400080000db00244d6f7274616c3232300400080000dc00244d6f7274616c3232310400080000dd00244d6f7274616c3232320400080000de00244d6f7274616c3232330400080000df00244d6f7274616c3232340400080000e000244d6f7274616c3232350400080000e100244d6f7274616c3232360400080000e200244d6f7274616c3232370400080000e300244d6f7274616c3232380400080000e400244d6f7274616c3232390400080000e500244d6f7274616c3233300400080000e600244d6f7274616c3233310400080000e700244d6f7274616c3233320400080000e800244d6f7274616c3233330400080000e900244d6f7274616c3233340400080000ea00244d6f7274616c3233350400080000eb00244d6f7274616c3233360400080000ec00244d6f7274616c3233370400080000ed00244d6f7274616c3233380400080000ee00244d6f7274616c3233390400080000ef00244d6f7274616c3234300400080000f000244d6f7274616c3234310400080000f100244d6f7274616c3234320400080000f200244d6f7274616c3234330400080000f300244d6f7274616c3234340400080000f400244d6f7274616c3234350400080000f500244d6f7274616c3234360400080000f600244d6f7274616c3234370400080000f700244d6f7274616c3234380400080000f800244d6f7274616c3234390400080000f900244d6f7274616c3235300400080000fa00244d6f7274616c3235310400080000fb00244d6f7274616c3235320400080000fc00244d6f7274616c3235330400080000fd00244d6f7274616c3235340400080000fe00244d6f7274616c3235350400080000ff0000cd0a10306672616d655f73797374656d28657874656e73696f6e732c636865636b5f6e6f6e636528436865636b4e6f6e636504045400000400e00120543a3a4e6f6e63650000d10a10306672616d655f73797374656d28657874656e73696f6e7330636865636b5f7765696768742c436865636b57656967687404045400000000d50a10306f70616c5f72756e74696d653872756e74696d655f636f6d6d6f6e2c6d61696e74656e616e636540436865636b4d61696e74656e616e636500000000d90a10306f70616c5f72756e74696d653872756e74696d655f636f6d6d6f6e206964656e746974795044697361626c654964656e7469747943616c6c7300000000dd0a088c70616c6c65745f74656d706c6174655f7472616e73616374696f6e5f7061796d656e74604368617267655472616e73616374696f6e5061796d656e7404045401e10a000400bc013042616c616e63654f663c543e0000e10a08306f70616c5f72756e74696d651c52756e74696d6500000000e50a083c70616c6c65745f657468657265756d6046616b655472616e73616374696f6e46696e616c697a657204045401e10a000000e90a102873705f72756e74696d651c67656e657269634c756e636865636b65645f65787472696e73696348556e636865636b656445787472696e736963101c4164647265737301dd011043616c6c015d01245369676e6174757265019d0a14457874726101b50a00040034000000d41853797374656d011853797374656d401c4163636f756e7401010402000c4101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008004e8205468652066756c6c206163636f756e7420696e666f726d6174696f6e20666f72206120706172746963756c6172206163636f756e742049442e3845787472696e736963436f756e74000010040004b820546f74616c2065787472696e7369637320636f756e7420666f72207468652063757272656e7420626c6f636b2e2c426c6f636b576569676874010020180000000000000488205468652063757272656e742077656967687420666f722074686520626c6f636b2e40416c6c45787472696e736963734c656e000010040004410120546f74616c206c656e6774682028696e2062797465732920666f7220616c6c2065787472696e736963732070757420746f6765746865722c20666f72207468652063757272656e7420626c6f636b2e24426c6f636b486173680101040510308000000000000000000000000000000000000000000000000000000000000000000498204d6170206f6620626c6f636b206e756d6265727320746f20626c6f636b206861736865732e3445787472696e736963446174610101040510340400043d012045787472696e73696373206461746120666f72207468652063757272656e7420626c6f636b20286d61707320616e2065787472696e736963277320696e64657820746f206974732064617461292e184e756d6265720100101000000000040901205468652063757272656e7420626c6f636b206e756d626572206265696e672070726f6365737365642e205365742062792060657865637574655f626c6f636b602e28506172656e744861736801003080000000000000000000000000000000000000000000000000000000000000000004702048617368206f66207468652070726576696f757320626c6f636b2e18446967657374010038040004f020446967657374206f66207468652063757272656e7420626c6f636b2c20616c736f2070617274206f662074686520626c6f636b206865616465722e184576656e747301004804001ca0204576656e7473206465706f736974656420666f72207468652063757272656e7420626c6f636b2e001d01204e4f54453a20546865206974656d20697320756e626f756e6420616e642073686f756c64207468657265666f7265206e657665722062652072656164206f6e20636861696e2ed020497420636f756c64206f746865727769736520696e666c6174652074686520506f562073697a65206f66206120626c6f636b2e002d01204576656e747320686176652061206c6172676520696e2d6d656d6f72792073697a652e20426f7820746865206576656e747320746f206e6f7420676f206f75742d6f662d6d656d6f7279fc206a75737420696e206361736520736f6d656f6e65207374696c6c207265616473207468656d2066726f6d2077697468696e207468652072756e74696d652e284576656e74436f756e74010010100000000004b820546865206e756d626572206f66206576656e747320696e2074686520604576656e74733c543e60206c6973742e2c4576656e74546f70696373010104023025060400282501204d617070696e67206265747765656e206120746f7069632028726570726573656e74656420627920543a3a486173682920616e64206120766563746f72206f6620696e646578657394206f66206576656e747320696e2074686520603c4576656e74733c543e3e60206c6973742e00510120416c6c20746f70696320766563746f727320686176652064657465726d696e69737469632073746f72616765206c6f636174696f6e7320646570656e64696e67206f6e2074686520746f7069632e2054686973450120616c6c6f7773206c696768742d636c69656e747320746f206c6576657261676520746865206368616e67657320747269652073746f7261676520747261636b696e67206d656368616e69736d20616e64e420696e2063617365206f66206368616e67657320666574636820746865206c697374206f66206576656e7473206f6620696e7465726573742e005901205468652076616c756520686173207468652074797065206028426c6f636b4e756d626572466f723c543e2c204576656e74496e646578296020626563617573652069662077652075736564206f6e6c79206a7573744d012074686520604576656e74496e64657860207468656e20696e20636173652069662074686520746f70696320686173207468652073616d6520636f6e74656e7473206f6e20746865206e65787420626c6f636b0101206e6f206e6f74696669636174696f6e2077696c6c20626520747269676765726564207468757320746865206576656e74206d69676874206265206c6f73742e484c61737452756e74696d65557067726164650000290604000455012053746f726573207468652060737065635f76657273696f6e6020616e642060737065635f6e616d6560206f66207768656e20746865206c6173742072756e74696d6520757067726164652068617070656e65642e545570677261646564546f553332526566436f756e74010035010400044d012054727565206966207765206861766520757067726164656420736f207468617420607479706520526566436f756e74602069732060753332602e2046616c7365202864656661756c7429206966206e6f742e605570677261646564546f547269706c65526566436f756e74010035010400085d012054727565206966207765206861766520757067726164656420736f2074686174204163636f756e74496e666f20636f6e7461696e73207468726565207479706573206f662060526566436f756e74602e2046616c736548202864656661756c7429206966206e6f742e38457865637574696f6e506861736500002106040004882054686520657865637574696f6e207068617365206f662074686520626c6f636b2e01610101541830426c6f636b576569676874732d066d01025b1f5d00070088526a7402004001c2a0a91d000107d00918a44b0200d000010700e6bd4f570200f000010000c2a0a91d000107d0abacbe680200200101070088526a7402004001010700a2941a1d02005000c2a0a91d0000000004d020426c6f636b20262065787472696e7369637320776569676874733a20626173652076616c75657320616e64206c696d6974732e2c426c6f636b4c656e6774683d063000003c00000050000000500004a820546865206d6178696d756d206c656e677468206f66206120626c6f636b2028696e206279746573292e38426c6f636b48617368436f756e74101060090000045501204d6178696d756d206e756d626572206f6620626c6f636b206e756d62657220746f20626c6f636b2068617368206d617070696e677320746f206b65657020286f6c64657374207072756e6564206669727374292e20446257656967687445064040787d010000000000e1f505000000000409012054686520776569676874206f662072756e74696d65206461746162617365206f7065726174696f6e73207468652072756e74696d652063616e20696e766f6b652e1c56657273696f6e49064103106f70616c106f70616c01000000cfbd9800000000003c4fdc4d29738b36d503000000144f3c7616f5c8a102000000df6acb689907609b0400000037e397fc7c91f5e40200000040fe3ad401f8959a06000000d2bc9897eed08f1503000000f78b278be53f454c02000000582211f65bb14b8905000000ab3c0572291feb8b01000000dd718d5cc53262d401000000ea93e3f16f3d696202000000bc9d89904f5b923f0100000037c8bb1350a9a2a80400000032d67ae360cae94401000000e65b00e46cedd0aa0200000003000000010484204765742074686520636861696e27732063757272656e742076657273696f6e2e28535335385072656669784901082a0014a8205468652064657369676e61746564205353353820707265666978206f66207468697320636861696e2e0039012054686973207265706c6163657320746865202273733538466f726d6174222070726f7065727479206465636c6172656420696e2074686520636861696e20737065632e20526561736f6e20697331012074686174207468652072756e74696d652073686f756c64206b6e6f772061626f7574207468652070726566697820696e206f7264657220746f206d616b6520757365206f662069742061737020616e206964656e746966696572206f662074686520636861696e2e01590600485374617465547269654d6967726174696f6e01485374617465547269654d6967726174696f6e0c404d6967726174696f6e50726f6365737301007d013800000000000000000000000000001050204d6967726174696f6e2070726f67726573732e005d0120546869732073746f7265732074686520736e617073686f74206f6620746865206c617374206d69677261746564206b6579732e2049742063616e2062652073657420696e746f206d6f74696f6e20616e64206d6f7665d420666f727761726420627920616e79206f6620746865206d65616e732070726f766964656420627920746869732070616c6c65742e284175746f4c696d6974730100750104000cd420546865206c696d69747320746861742061726520696d706f736564206f6e206175746f6d61746963206d6967726174696f6e732e00d42049662073657420746f204e6f6e652c207468656e206e6f206175746f6d61746963206d6967726174696f6e2068617070656e732e605369676e65644d6967726174696f6e4d61784c696d6974730000790104000ce020546865206d6178696d756d206c696d697473207468617420746865207369676e6564206d6967726174696f6e20636f756c64207573652e00b4204966206e6f74207365742c206e6f207369676e6564207375626d697373696f6e20697320616c6c6f7765642e017101017804244d61784b65794c656e10100002000054b4204d6178696d616c206e756d626572206f6620627974657320746861742061206b65792063616e20686176652e00b0204652414d4520697473656c6620646f6573206e6f74206c696d697420746865206b6579206c656e6774682e01012054686520636f6e63726574652076616c7565206d757374207468657265666f726520646570656e64206f6e20796f75722073746f726167652075736167652e59012041205b606672616d655f737570706f72743a3a73746f726167653a3a53746f726167654e4d6170605d20666f72206578616d706c652063616e206861766520616e20617262697472617279206e756d626572206f664501206b65797320776869636820617265207468656e2068617368656420616e6420636f6e636174656e617465642c20726573756c74696e6720696e206172626974726172696c79206c6f6e67206b6579732e0041012055736520746865202a7374617465206d6967726174696f6e205250432a20746f20726574726965766520746865206c656e677468206f6620746865206c6f6e67657374206b657920696e20796f757201012073746f726167653a203c68747470733a2f2f6769746875622e636f6d2f706172697479746563682f7375627374726174652f6973737565732f31313634323e00290120546865206d6967726174696f6e2077696c6c2068616c7420776974682061206048616c74656460206576656e7420696620746869732076616c756520697320746f6f20736d616c6c2e49012053696e6365207468657265206973206e6f207265616c2070656e616c74792066726f6d206f7665722d657374696d6174696e672c206974206973206164766973656420746f207573652061206c61726765802076616c75652e205468652064656661756c742069732035313220627974652e008020536f6d65206b6579206c656e6774687320666f72207265666572656e63653ad0202d205b606672616d655f737570706f72743a3a73746f726167653a3a53746f7261676556616c7565605d3a2033322062797465c8202d205b606672616d655f737570706f72743a3a73746f726167653a3a53746f726167654d6170605d3a2036342062797465e0202d205b606672616d655f737570706f72743a3a73746f726167653a3a53746f72616765446f75626c654d6170605d3a2039362062797465004820466f72206d6f726520696e666f207365653501203c68747470733a2f2f7777772e736861776e74616272697a692e636f6d2f7375627374726174652f7175657279696e672d7375627374726174652d73746f726167652d7669612d7270632f3e0180013c50617261636861696e53797374656d013c50617261636861696e53797374656d6044556e696e636c756465645365676d656e7401005d060400184901204c617465737420696e636c7564656420626c6f636b2064657363656e64616e7473207468652072756e74696d652061636365707465642e20496e206f7468657220776f7264732c20746865736520617265610120616e636573746f7273206f66207468652063757272656e746c7920657865637574696e6720626c6f636b2077686963682068617665206e6f74206265656e20696e636c7564656420696e20746865206f627365727665644c2072656c61792d636861696e2073746174652e00750120546865207365676d656e74206c656e677468206973206c696d69746564206279207468652063617061636974792072657475726e65642066726f6d20746865205b60436f6e73656e737573486f6f6b605d20636f6e666967757265643c20696e207468652070616c6c65742e6c41676772656761746564556e696e636c756465645365676d656e740000810604000c69012053746f72616765206669656c642074686174206b6565707320747261636b206f662062616e64776964746820757365642062792074686520756e696e636c75646564207365676d656e7420616c6f6e672077697468207468655901206c617465737420746865206c61746573742048524d502077617465726d61726b2e205573656420666f72206c696d6974696e672074686520616363657074616e6365206f66206e657720626c6f636b73207769746890207265737065637420746f2072656c617920636861696e20636f6e73747261696e74732e5450656e64696e6756616c69646174696f6e436f6465010034040018590120496e2063617365206f662061207363686564756c656420757067726164652c20746869732073746f72616765206669656c6420636f6e7461696e73207468652076616c69646174696f6e20636f646520746f20626524206170706c6965642e003d0120417320736f6f6e206173207468652072656c617920636861696e2067697665732075732074686520676f2d6168656164207369676e616c2c2077652077696c6c206f7665727772697465207468657101205b603a636f6465605d5b73705f636f72653a3a73746f726167653a3a77656c6c5f6b6e6f776e5f6b6579733a3a434f44455d2077686963682077696c6c20726573756c7420746865206e65787420626c6f636b2070726f636573730901207769746820746865206e65772076616c69646174696f6e20636f64652e205468697320636f6e636c756465732074686520757067726164652070726f636573732e444e657756616c69646174696f6e436f64650000340400145d012056616c69646174696f6e20636f6465207468617420697320736574206279207468652070617261636861696e20616e6420697320746f20626520636f6d6d756e69636174656420746f20636f6c6c61746f7220616e647820636f6e73657175656e746c79207468652072656c61792d636861696e2e00650120546869732077696c6c20626520636c656172656420696e20606f6e5f696e697469616c697a6560206f662065616368206e657720626c6f636b206966206e6f206f746865722070616c6c657420616c7265616479207365742c207468652076616c75652e3856616c69646174696f6e446174610000910104000cd020546865205b6050657273697374656456616c69646174696f6e44617461605d2073657420666f72207468697320626c6f636b2e2d0120546869732076616c756520697320657870656374656420746f20626520736574206f6e6c79206f6e63652070657220626c6f636b20616e642069742773206e657665722073746f7265643420696e2074686520747269652e5044696453657456616c69646174696f6e436f646501003501040004e02057657265207468652076616c69646174696f6e20646174612073657420746f206e6f74696679207468652072656c617920636861696e3f644c61737452656c6179436861696e426c6f636b4e756d6265720100101000000000041d01205468652072656c617920636861696e20626c6f636b206e756d626572206173736f636961746564207769746820746865206c6173742070617261636861696e20626c6f636b2e60557067726164655265737472696374696f6e5369676e616c0100850604001c750120416e206f7074696f6e20776869636820696e64696361746573206966207468652072656c61792d636861696e20726573747269637473207369676e616c6c696e6720612076616c69646174696f6e20636f646520757067726164652e610120496e206f7468657220776f7264732c20696620746869732069732060536f6d656020616e64205b604e657756616c69646174696f6e436f6465605d2069732060536f6d6560207468656e207468652070726f64756365646c2063616e6469646174652077696c6c20626520696e76616c69642e00710120546869732073746f72616765206974656d2069732061206d6972726f72206f662074686520636f72726573706f6e64696e672076616c756520666f72207468652063757272656e742070617261636861696e2066726f6d207468656d012072656c61792d636861696e2e20546869732076616c756520697320657068656d6572616c207768696368206d65616e7320697420646f65736e277420686974207468652073746f726167652e20546869732076616c756520697360207365742061667465722074686520696e686572656e742e3855706772616465476f416865616401007906040014dc204f7074696f6e616c207570677261646520676f2d6168656164207369676e616c2066726f6d207468652072656c61792d636861696e2e00710120546869732073746f72616765206974656d2069732061206d6972726f72206f662074686520636f72726573706f6e64696e672076616c756520666f72207468652063757272656e742070617261636861696e2066726f6d207468656d012072656c61792d636861696e2e20546869732076616c756520697320657068656d6572616c207768696368206d65616e7320697420646f65736e277420686974207468652073746f726167652e20546869732076616c756520697360207365742061667465722074686520696e686572656e742e3c52656c6179537461746550726f6f6600009901040018c4205468652073746174652070726f6f6620666f7220746865206c6173742072656c617920706172656e7420626c6f636b2e006d012054686973206669656c64206973206d65616e7420746f2062652075706461746564206561636820626c6f636b2077697468207468652076616c69646174696f6e206461746120696e686572656e742e205468657265666f72652c4d01206265666f72652070726f63657373696e67206f662074686520696e686572656e742c20652e672e20696e20606f6e5f696e697469616c697a656020746869732064617461206d6179206265207374616c652e00ac2054686973206461746120697320616c736f20616273656e742066726f6d207468652067656e657369732e5852656c6576616e744d6573736167696e67537461746500008d0604001c65012054686520736e617073686f74206f6620736f6d652073746174652072656c6174656420746f206d6573736167696e672072656c6576616e7420746f207468652063757272656e742070617261636861696e2061732070657248207468652072656c617920706172656e742e006d012054686973206669656c64206973206d65616e7420746f2062652075706461746564206561636820626c6f636b2077697468207468652076616c69646174696f6e206461746120696e686572656e742e205468657265666f72652c4d01206265666f72652070726f63657373696e67206f662074686520696e686572656e742c20652e672e20696e20606f6e5f696e697469616c697a656020746869732064617461206d6179206265207374616c652e00ac2054686973206461746120697320616c736f20616273656e742066726f6d207468652067656e657369732e44486f7374436f6e66696775726174696f6e0000a1060400182901205468652070617261636861696e20686f737420636f6e66696775726174696f6e207468617420776173206f627461696e65642066726f6d207468652072656c617920706172656e742e006d012054686973206669656c64206973206d65616e7420746f2062652075706461746564206561636820626c6f636b2077697468207468652076616c69646174696f6e206461746120696e686572656e742e205468657265666f72652c4d01206265666f72652070726f63657373696e67206f662074686520696e686572656e742c20652e672e20696e20606f6e5f696e697469616c697a656020746869732064617461206d6179206265207374616c652e00ac2054686973206461746120697320616c736f20616273656e742066726f6d207468652067656e657369732e384c617374446d714d7163486561640100a90680000000000000000000000000000000000000000000000000000000000000000010f420546865206c61737420646f776e77617264206d65737361676520717565756520636861696e20686561642077652068617665206f627365727665642e00650120546869732076616c7565206973206c6f61646564206265666f726520616e642073617665642061667465722070726f63657373696e6720696e626f756e6420646f776e77617264206d65737361676573206361727269656460206279207468652073797374656d20696e686572656e742e404c61737448726d704d716348656164730100ad06040010490120546865206d65737361676520717565756520636861696e2068656164732077652068617665206f62736572766564207065722065616368206368616e6e656c20696e636f6d696e67206368616e6e656c2e00650120546869732076616c7565206973206c6f61646564206265666f726520616e642073617665642061667465722070726f63657373696e6720696e626f756e6420646f776e77617264206d65737361676573206361727269656460206279207468652073797374656d20696e686572656e742e6450726f636573736564446f776e776172644d6573736167657301001010000000000cc8204e756d626572206f6620646f776e77617264206d657373616765732070726f63657373656420696e206120626c6f636b2e00ec20546869732077696c6c20626520636c656172656420696e20606f6e5f696e697469616c697a6560206f662065616368206e657720626c6f636b2e3448726d7057617465726d61726b01001010000000000ca02048524d502077617465726d61726b2074686174207761732073657420696e206120626c6f636b2e00ec20546869732077696c6c20626520636c656172656420696e20606f6e5f696e697469616c697a6560206f662065616368206e657720626c6f636b2e5048726d704f7574626f756e644d657373616765730100b90604000ca42048524d50206d65737361676573207468617420776572652073656e7420696e206120626c6f636b2e00ec20546869732077696c6c20626520636c656172656420696e20606f6e5f696e697469616c697a6560206f662065616368206e657720626c6f636b2e385570776172644d6573736167657301006d0104000cac20557077617264206d65737361676573207468617420776572652073656e7420696e206120626c6f636b2e00ec20546869732077696c6c20626520636c656172656420696e20606f6e5f696e697469616c697a6560206f662065616368206e657720626c6f636b2e5450656e64696e675570776172644d6573736167657301006d01040004310120557077617264206d65737361676573207468617420617265207374696c6c2070656e64696e6720616e64206e6f74207965742073656e6420746f207468652072656c617920636861696e2e84416e6e6f756e63656448726d704d6573736167657350657243616e646964617465010010100000000008650120546865206e756d626572206f662048524d50206d65737361676573207765206f6273657276656420696e20606f6e5f696e697469616c697a656020616e64207468757320757365642074686174206e756d62657220666f72f020616e6e6f756e63696e672074686520776569676874206f6620606f6e5f696e697469616c697a656020616e6420606f6e5f66696e616c697a65602e68526573657276656458636d705765696768744f766572726964650000240400085d01205468652077656967687420776520726573657276652061742074686520626567696e6e696e67206f662074686520626c6f636b20666f722070726f63657373696e672058434d50206d657373616765732e2054686973b8206f76657272696465732074686520616d6f756e742073657420696e2074686520436f6e6669672074726169742e645265736572766564446d705765696768744f766572726964650000240400085901205468652077656967687420776520726573657276652061742074686520626567696e6e696e67206f662074686520626c6f636b20666f722070726f63657373696e6720444d50206d657373616765732e2054686973b8206f76657272696465732074686520616d6f756e742073657420696e2074686520436f6e6669672074726169742e44417574686f72697a6564557067726164650000c106040004b820546865206e65787420617574686f72697a656420757067726164652c206966207468657265206973206f6e652e60437573746f6d56616c69646174696f6e486561644461746100003404000c2901204120637573746f6d2068656164206461746120746861742073686f756c642062652072657475726e656420617320726573756c74206f66206076616c69646174655f626c6f636b602e00110120536565206050616c6c65743a3a7365745f637573746f6d5f76616c69646174696f6e5f686561645f646174616020666f72206d6f726520696e666f726d6174696f6e2e01890101840001c506143450617261636861696e496e666f013450617261636861696e496e666f042c50617261636861696e49640100ad0110640000000001c1010000001528417574686f72736869700128417574686f72736869700418417574686f720000000400046420417574686f72206f662063757272656e7420626c6f636b2e000000001644436f6c6c61746f7253656c656374696f6e0144436f6c6c61746f7253656c656374696f6e1034496e76756c6e657261626c65730100c9060400048c2054686520696e76756c6e657261626c652c20666978656420636f6c6c61746f72732e404c6963656e73654465706f7369744f66010104020018400000000000000000000000000000000004ac205468652028636f6d6d756e6974792920636f6c6c6174696f6e206c6963656e736520686f6c646572732e2843616e646964617465730100c906040004bc205468652028636f6d6d756e6974792c206c696d697465642920636f6c6c6174696f6e2063616e646964617465732e444c617374417574686f726564426c6f636b01010405001010000000000484204c61737420626c6f636b20617574686f72656420627920636f6c6c61746f722e01c501018c0001cd06171c53657373696f6e011c53657373696f6e1c2856616c696461746f72730100e5010400047c205468652063757272656e7420736574206f662076616c696461746f72732e3043757272656e74496e646578010010100000000004782043757272656e7420696e646578206f66207468652073657373696f6e2e345175657565644368616e67656401003501040008390120547275652069662074686520756e6465726c79696e672065636f6e6f6d6963206964656e746974696573206f7220776569676874696e6720626568696e64207468652076616c696461746f7273a420686173206368616e67656420696e20746865207175657565642076616c696461746f72207365742e285175657565644b6579730100d1060400083d012054686520717565756564206b65797320666f7220746865206e6578742073657373696f6e2e205768656e20746865206e6578742073657373696f6e20626567696e732c207468657365206b657973e02077696c6c206265207573656420746f2064657465726d696e65207468652076616c696461746f7227732073657373696f6e206b6579732e4844697361626c656456616c696461746f7273010031050400148020496e6469636573206f662064697361626c65642076616c696461746f72732e003d01205468652076656320697320616c77617973206b65707420736f7274656420736f20746861742077652063616e2066696e642077686574686572206120676976656e2076616c696461746f722069733d012064697361626c6564207573696e672062696e617279207365617263682e204974206765747320636c6561726564207768656e20606f6e5f73657373696f6e5f656e64696e67602072657475726e73642061206e657720736574206f66206964656e7469746965732e204e6578744b6579730001040500cd010400049c20546865206e6578742073657373696f6e206b65797320666f7220612076616c696461746f722e204b65794f776e657200010405d90600040004090120546865206f776e6572206f662061206b65792e20546865206b65792069732074686520604b657954797065496460202b2074686520656e636f646564206b65792e01c90101900001e106181041757261011041757261082c417574686f7269746965730100e5060400046c205468652063757272656e7420617574686f72697479207365742e2c43757272656e74536c6f740100ed062000000000000000000c80205468652063757272656e7420736c6f74206f66207468697320626c6f636b2e009420546869732077696c6c2062652073657420696e20606f6e5f696e697469616c697a65602e00000000191c41757261457874011c41757261457874082c417574686f7269746965730100e506040014942053657276657320617320636163686520666f722074686520617574686f7269746965732e0071012054686520617574686f72697469657320696e204175526120617265206f7665727772697474656e20696e20606f6e5f696e697469616c697a6560207768656e2077652073776974636820746f2061206e65772073657373696f6e2c5d0120627574207765207265717569726520746865206f6c6420617574686f72697469657320746f2076657269667920746865207365616c207768656e2076616c69646174696e67206120506f562e20546869732077696c6c0d0120616c77617973206265207570646174656420746f20746865206c6174657374204175526120617574686f72697469657320696e20606f6e5f66696e616c697a65602e20536c6f74496e666f0000f10604000cd82043757272656e7420736c6f742070616972656420776974682061206e756d626572206f6620617574686f72656420626c6f636b732e00982055706461746564206f6e206561636820626c6f636b20696e697469616c697a6174696f6e2e000000001a2042616c616e636573012042616c616e6365731c34546f74616c49737375616e6365010018400000000000000000000000000000000004982054686520746f74616c20756e6974732069737375656420696e207468652073797374656d2e40496e61637469766549737375616e636501001840000000000000000000000000000000000409012054686520746f74616c20756e697473206f66206f75747374616e64696e672064656163746976617465642062616c616e636520696e207468652073797374656d2e1c4163636f756e74010104020014010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080600901205468652042616c616e6365732070616c6c6574206578616d706c65206f662073746f72696e67207468652062616c616e6365206f6620616e206163636f756e742e00282023204578616d706c650034206060606e6f636f6d70696c65b02020696d706c2070616c6c65745f62616c616e6365733a3a436f6e66696720666f722052756e74696d65207b19022020202074797065204163636f756e7453746f7265203d2053746f726167654d61705368696d3c53656c663a3a4163636f756e743c52756e74696d653e2c206672616d655f73797374656d3a3a50726f76696465723c52756e74696d653e2c204163636f756e7449642c2053656c663a3a4163636f756e74446174613c42616c616e63653e3e0c20207d102060606000150120596f752063616e20616c736f2073746f7265207468652062616c616e6365206f6620616e206163636f756e7420696e20746865206053797374656d602070616c6c65742e00282023204578616d706c650034206060606e6f636f6d70696c65b02020696d706c2070616c6c65745f62616c616e6365733a3a436f6e66696720666f722052756e74696d65207b7420202074797065204163636f756e7453746f7265203d2053797374656d0c20207d102060606000510120427574207468697320636f6d657320776974682074726164656f6666732c2073746f72696e67206163636f756e742062616c616e63657320696e207468652073797374656d2070616c6c65742073746f7265736d0120606672616d655f73797374656d60206461746120616c6f6e677369646520746865206163636f756e74206461746120636f6e747261727920746f2073746f72696e67206163636f756e742062616c616e63657320696e207468652901206042616c616e636573602070616c6c65742c20776869636820757365732061206053746f726167654d61706020746f2073746f72652062616c616e6365732064617461206f6e6c792e4101204e4f54453a2054686973206973206f6e6c79207573656420696e207468652063617365207468617420746869732070616c6c6574206973207573656420746f2073746f72652062616c616e6365732e144c6f636b730101040200f506040008b820416e79206c6971756964697479206c6f636b73206f6e20736f6d65206163636f756e742062616c616e6365732e2501204e4f54453a2053686f756c64206f6e6c79206265206163636573736564207768656e2073657474696e672c206368616e67696e6720616e642066726565696e672061206c6f636b2e20526573657276657301010402000507040004a4204e616d6564207265736572766573206f6e20736f6d65206163636f756e742062616c616e6365732e14486f6c6473010104020011070400046c20486f6c6473206f6e206163636f756e742062616c616e6365732e1c467265657a6573010104020025070400048820467265657a65206c6f636b73206f6e206163636f756e742062616c616e6365732e01d901019414484578697374656e7469616c4465706f73697418400000000000000000000000000000000020410120546865206d696e696d756d20616d6f756e7420726571756972656420746f206b65657020616e206163636f756e74206f70656e2e204d5553542042452047524541544552205448414e205a45524f2100590120496620796f75202a7265616c6c792a206e65656420697420746f206265207a65726f2c20796f752063616e20656e61626c652074686520666561747572652060696e7365637572655f7a65726f5f65646020666f72610120746869732070616c6c65742e20486f77657665722c20796f7520646f20736f20617420796f7572206f776e207269736b3a20746869732077696c6c206f70656e2075702061206d616a6f7220446f5320766563746f722e590120496e206361736520796f752068617665206d756c7469706c6520736f7572636573206f662070726f7669646572207265666572656e6365732c20796f75206d617920616c736f2067657420756e65787065637465648c206265686176696f757220696620796f7520736574207468697320746f207a65726f2e00f020426f74746f6d206c696e653a20446f20796f757273656c662061206661766f757220616e64206d616b65206974206174206c65617374206f6e6521204d61784c6f636b7310103200000008f420546865206d6178696d756d206e756d626572206f66206c6f636b7320746861742073686f756c64206578697374206f6e20616e206163636f756e742edc204e6f74207374726963746c7920656e666f726365642c20627574207573656420666f722077656967687420657374696d6174696f6e2e2c4d61785265736572766573101032000000040d0120546865206d6178696d756d206e756d626572206f66206e616d656420726573657276657320746861742063616e206578697374206f6e20616e206163636f756e742e204d6178486f6c647310100a00000004190120546865206d6178696d756d206e756d626572206f6620686f6c647320746861742063616e206578697374206f6e20616e206163636f756e7420617420616e792074696d652e284d6178467265657a657310100a00000004610120546865206d6178696d756d206e756d626572206f6620696e646976696475616c20667265657a65206c6f636b7320746861742063616e206578697374206f6e20616e206163636f756e7420617420616e792074696d652e0131071e2454696d657374616d70012454696d657374616d70080c4e6f7701002c20000000000000000004902043757272656e742074696d6520666f72207468652063757272656e7420626c6f636b2e2444696455706461746501003501040004b420446964207468652074696d657374616d7020676574207570646174656420696e207468697320626c6f636b3f01e9010004344d696e696d756d506572696f642c207017000000000000104d0120546865206d696e696d756d20706572696f64206265747765656e20626c6f636b732e204265776172652074686174207468697320697320646966666572656e7420746f20746865202a65787065637465642a5d0120706572696f6420746861742074686520626c6f636b2070726f64756374696f6e206170706172617475732070726f76696465732e20596f75722063686f73656e20636f6e73656e7375732073797374656d2077696c6c5d012067656e6572616c6c7920776f726b2077697468207468697320746f2064657465726d696e6520612073656e7369626c6520626c6f636b2074696d652e20652e672e20466f7220417572612c2069742077696c6c206265a020646f75626c65207468697320706572696f64206f6e2064656661756c742073657474696e67732e0020485472616e73616374696f6e5061796d656e7401485472616e73616374696f6e5061796d656e7408444e6578744665654d756c7469706c6965720100350740000064a7b3b6e00d0000000000000000003853746f7261676556657273696f6e0100390704000000019c04604f7065726174696f6e616c4665654d756c7469706c696572080405545901204120666565206d756c6974706c69657220666f7220604f7065726174696f6e616c602065787472696e7369637320746f20636f6d7075746520227669727475616c207469702220746f20626f6f73742074686569722c20607072696f7269747960004d0120546869732076616c7565206973206d756c7469706c656420627920746865206066696e616c5f6665656020746f206f627461696e206120227669727475616c20746970222074686174206973206c61746572f420616464656420746f20612074697020636f6d706f6e656e7420696e20726567756c617220607072696f72697479602063616c63756c6174696f6e732e4d01204974206d65616e732074686174206120604e6f726d616c60207472616e73616374696f6e2063616e2066726f6e742d72756e20612073696d696c61726c792d73697a656420604f7065726174696f6e616c6041012065787472696e736963202877697468206e6f20746970292c20627920696e636c7564696e672061207469702076616c75652067726561746572207468616e20746865207669727475616c207469702e003c20606060727573742c69676e6f726540202f2f20466f7220604e6f726d616c608c206c6574207072696f72697479203d207072696f726974795f63616c6328746970293b0054202f2f20466f7220604f7065726174696f6e616c601101206c6574207669727475616c5f746970203d2028696e636c7573696f6e5f666565202b2074697029202a204f7065726174696f6e616c4665654d756c7469706c6965723bc4206c6574207072696f72697479203d207072696f726974795f63616c6328746970202b207669727475616c5f746970293b1020606060005101204e6f746520746861742073696e636520776520757365206066696e616c5f6665656020746865206d756c7469706c696572206170706c69657320616c736f20746f2074686520726567756c61722060746970605d012073656e74207769746820746865207472616e73616374696f6e2e20536f2c206e6f74206f6e6c7920646f657320746865207472616e73616374696f6e206765742061207072696f726974792062756d702062617365646101206f6e207468652060696e636c7573696f6e5f666565602c2062757420776520616c736f20616d706c6966792074686520696d70616374206f662074697073206170706c69656420746f20604f7065726174696f6e616c6038207472616e73616374696f6e732e002120547265617375727901205472656173757279103450726f706f73616c436f756e74010010100000000004a4204e756d626572206f662070726f706f73616c7320746861742068617665206265656e206d6164652e2450726f706f73616c7300010405103d070400047c2050726f706f73616c7320746861742068617665206265656e206d6164652e2c4465616374697661746564010018400000000000000000000000000000000004f02054686520616d6f756e7420776869636820686173206265656e207265706f7274656420617320696e61637469766520746f2043757272656e63792e24417070726f76616c7301004107040004f82050726f706f73616c20696e646963657320746861742068617665206265656e20617070726f76656420627574206e6f742079657420617761726465642e01ed0101a01c3050726f706f73616c426f6e6445071050c30000085501204672616374696f6e206f6620612070726f706f73616c27732076616c756520746861742073686f756c6420626520626f6e64656420696e206f7264657220746f20706c616365207468652070726f706f73616c2e110120416e2061636365707465642070726f706f73616c2067657473207468657365206261636b2e20412072656a65637465642070726f706f73616c20646f6573206e6f742e4c50726f706f73616c426f6e644d696e696d756d1840000064a7b3b6e00d0000000000000000044901204d696e696d756d20616d6f756e74206f662066756e647320746861742073686f756c6420626520706c6163656420696e2061206465706f73697420666f72206d616b696e6720612070726f706f73616c2e4c50726f706f73616c426f6e644d6178696d756d250544010000a0dec5adc9353600000000000000044901204d6178696d756d20616d6f756e74206f662066756e647320746861742073686f756c6420626520706c6163656420696e2061206465706f73697420666f72206d616b696e6720612070726f706f73616c2e2c5370656e64506572696f64101019000000048820506572696f64206265747765656e2073756363657373697665207370656e64732e104275726e450710000000000411012050657263656e74616765206f662073706172652066756e64732028696620616e7929207468617420617265206275726e7420706572207370656e6420706572696f642e2050616c6c6574496449072070792f74727372790419012054686520747265617375727927732070616c6c65742069642c207573656420666f72206465726976696e672069747320736f7665726569676e206163636f756e742049442e304d6178417070726f76616c731010640000000c150120546865206d6178696d756d206e756d626572206f6620617070726f76616c7320746861742063616e207761697420696e20746865207370656e64696e672071756575652e004d01204e4f54453a205468697320706172616d6574657220697320616c736f20757365642077697468696e2074686520426f756e746965732050616c6c657420657874656e73696f6e20696620656e61626c65642e014d0722105375646f01105375646f040c4b6579000000040004842054686520604163636f756e74496460206f6620746865207375646f206b65792e01f10101a400015107231c56657374696e67011c56657374696e67044056657374696e675363686564756c65730101040200550704000c842056657374696e67207363686564756c6573206f6620616e206163636f756e742e00e02056657374696e675363686564756c65733a206d6170204163636f756e744964203d3e205665633c56657374696e675363686564756c653e01f50101b404444d696e5665737465645472616e7366657218400000e8890423c78a000000000000000004e820546865206d696e696d756d20616d6f756e74207472616e7366657272656420746f2063616c6c20607665737465645f7472616e73666572602e015907251c58546f6b656e730001fd0101c0083053656c664c6f636174696f6ed414010100bd2004542053656c6620636861696e206c6f636174696f6e2e344261736558636d57656967687424180284d717a10f104420426173652058434d207765696768742e00f8205468652061637475616c6c792077656967687420666f7220616e2058434d206d6573736167652069732060543a3a4261736558636d576569676874202b6c20543a3a576569676865723a3a77656967687428266d736729602e015d072618546f6b656e730118546f6b656e731034546f74616c49737375616e6365010104050d0118400000000000000000000000000000000004902054686520746f74616c2069737375616e6365206f66206120746f6b656e20747970652e144c6f636b73010108020561076507040008d820416e79206c6971756964697479206c6f636b73206f66206120746f6b656e207479706520756e64657220616e206163636f756e742e2501204e4f54453a2053686f756c64206f6e6c79206265206163636573736564207768656e2073657474696e672c206368616e67696e6720616e642066726565696e672061206c6f636b2e204163636f756e7473010108020561077107c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018b8205468652062616c616e6365206f66206120746f6b656e207479706520756e64657220616e206163636f756e742e00fc204e4f54453a2049662074686520746f74616c2069732065766572207a65726f2c206465637265617365206163636f756e7420726566206163636f756e742e001901204e4f54453a2054686973206973206f6e6c79207573656420696e20746865206361736520746861742074686973206d6f64756c65206973207573656420746f2073746f7265282062616c616e6365732e205265736572766573010108020561077507040004a4204e616d6564207265736572766573206f6e20736f6d65206163636f756e742062616c616e6365732e014d0201090108204d61784c6f636b73101032000000002c4d61785265736572766573101032000000040d0120546865206d6178696d756d206e756d626572206f66206e616d656420726573657276657320746861742063616e206578697374206f6e20616e206163636f756e742e01810727204964656e7469747901204964656e7469747910284964656e746974794f660001040500f90204000c210120496e666f726d6174696f6e20746861742069732070657274696e656e7420746f206964656e746966792074686520656e7469747920626568696e6420616e206163636f756e742e00c02054574f582d4e4f54453a204f4b20e2809520604163636f756e7449646020697320612073656375726520686173682e1c53757065724f660001040200e1020400086101205468652073757065722d6964656e74697479206f6620616e20616c7465726e6174697665202273756222206964656e7469747920746f676574686572207769746820697473206e616d652c2077697468696e2074686174510120636f6e746578742e20496620746865206163636f756e74206973206e6f7420736f6d65206f74686572206163636f756e742773207375622d6964656e746974792c207468656e206a75737420604e6f6e65602e18537562734f660101040500850744000000000000000000000000000000000014b820416c7465726e6174697665202273756222206964656e746974696573206f662074686973206163636f756e742e001d0120546865206669727374206974656d20697320746865206465706f7369742c20746865207365636f6e64206973206120766563746f72206f6620746865206163636f756e74732e00c02054574f582d4e4f54453a204f4b20e2809520604163636f756e7449646020697320612073656375726520686173682e285265676973747261727301008d070400104d012054686520736574206f6620726567697374726172732e204e6f7420657870656374656420746f206765742076657279206269672061732063616e206f6e6c79206265206164646564207468726f7567682061a8207370656369616c206f726967696e20286c696b656c79206120636f756e63696c206d6f74696f6e292e0029012054686520696e64657820696e746f20746869732063616e206265206361737420746f2060526567697374726172496e6465786020746f2067657420612076616c69642076616c75652e015102011501183042617369634465706f73697418400000e8890423c78a000000000000000004d42054686520616d6f756e742068656c64206f6e206465706f73697420666f7220612072656769737465726564206964656e74697479304669656c644465706f7369741840008062175ed158000000000000000000042d012054686520616d6f756e742068656c64206f6e206465706f73697420706572206164646974696f6e616c206669656c6420666f7220612072656769737465726564206964656e746974792e445375624163636f756e744465706f73697418400000c84e676dc11b00000000000000000c65012054686520616d6f756e742068656c64206f6e206465706f73697420666f7220612072656769737465726564207375626163636f756e742e20546869732073686f756c64206163636f756e7420666f7220746865206661637465012074686174206f6e652073746f72616765206974656d27732076616c75652077696c6c20696e637265617365206279207468652073697a65206f6620616e206163636f756e742049442c20616e642074686572652077696c6c350120626520616e6f746865722074726965206974656d2077686f73652076616c7565206973207468652073697a65206f6620616e206163636f756e7420494420706c75732033322062797465732e384d61785375624163636f756e7473101064000000040d0120546865206d6178696d756d206e756d626572206f66207375622d6163636f756e747320616c6c6f77656420706572206964656e746966696564206163636f756e742e4c4d61784164646974696f6e616c4669656c6473101064000000086501204d6178696d756d206e756d626572206f66206164646974696f6e616c206669656c64732074686174206d61792062652073746f72656420696e20616e2049442e204e656564656420746f20626f756e642074686520492f4fe020726571756972656420746f2061636365737320616e206964656e746974792c206275742063616e2062652070726574747920686967682e344d617852656769737472617273101014000000085101204d61786d696d756d206e756d626572206f66207265676973747261727320616c6c6f77656420696e207468652073797374656d2e204e656564656420746f20626f756e642074686520636f6d706c65786974797c206f662c20652e672e2c207570646174696e67206a756467656d656e74732e019d072820507265696d6167650120507265696d6167650824537461747573466f720001040630a1070400049020546865207265717565737420737461747573206f66206120676976656e20686173682e2c507265696d616765466f7200010406ad07b1070400000119030119010001b507292444656d6f6372616379012444656d6f6372616379303c5075626c696350726f70436f756e74010010100000000004f420546865206e756d626572206f6620287075626c6963292070726f706f73616c7320746861742068617665206265656e206d61646520736f206661722e2c5075626c696350726f70730100b907040004050120546865207075626c69632070726f706f73616c732e20556e736f727465642e20546865207365636f6e64206974656d206973207468652070726f706f73616c2e244465706f7369744f660001040510c50704000c842054686f73652077686f2068617665206c6f636b65642061206465706f7369742e00d82054574f582d4e4f54453a20536166652c20617320696e6372656173696e6720696e7465676572206b6579732061726520736166652e3c5265666572656e64756d436f756e74010010100000000004310120546865206e6578742066726565207265666572656e64756d20696e6465782c20616b6120746865206e756d626572206f66207265666572656e6461207374617274656420736f206661722e344c6f77657374556e62616b6564010010100000000008250120546865206c6f77657374207265666572656e64756d20696e64657820726570726573656e74696e6720616e20756e62616b6564207265666572656e64756d2e20457175616c20746fdc20605265666572656e64756d436f756e74602069662074686572652069736e2774206120756e62616b6564207265666572656e64756d2e405265666572656e64756d496e666f4f660001040510cd0704000cb420496e666f726d6174696f6e20636f6e6365726e696e6720616e7920676976656e207265666572656e64756d2e0009012054574f582d4e4f54453a205341464520617320696e646578657320617265206e6f7420756e64657220616e2061747461636b6572e280997320636f6e74726f6c2e20566f74696e674f660101040500d907d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105d0120416c6c20766f74657320666f72206120706172746963756c617220766f7465722e2057652073746f7265207468652062616c616e636520666f7220746865206e756d626572206f6620766f74657320746861742077655d012068617665207265636f726465642e20546865207365636f6e64206974656d2069732074686520746f74616c20616d6f756e74206f662064656c65676174696f6e732c20746861742077696c6c2062652061646465642e00e82054574f582d4e4f54453a205341464520617320604163636f756e7449646073206172652063727970746f2068617368657320616e797761792e544c6173745461626c656457617345787465726e616c010035010400085901205472756520696620746865206c617374207265666572656e64756d207461626c656420776173207375626d69747465642065787465726e616c6c792e2046616c7365206966206974207761732061207075626c6963282070726f706f73616c2e304e65787445787465726e616c0000f107040010590120546865207265666572656e64756d20746f206265207461626c6564207768656e6576657220697420776f756c642062652076616c696420746f207461626c6520616e2065787465726e616c2070726f706f73616c2e550120546869732068617070656e73207768656e2061207265666572656e64756d206e6565647320746f206265207461626c656420616e64206f6e65206f662074776f20636f6e646974696f6e7320617265206d65743aa4202d20604c6173745461626c656457617345787465726e616c60206973206066616c7365603b206f7268202d20605075626c696350726f70736020697320656d7074792e24426c61636b6c6973740001040630f50704000851012041207265636f7264206f662077686f207665746f656420776861742e204d6170732070726f706f73616c206861736820746f206120706f737369626c65206578697374656e7420626c6f636b206e756d626572e82028756e74696c207768656e206974206d6179206e6f742062652072657375626d69747465642920616e642077686f207665746f65642069742e3443616e63656c6c6174696f6e73010104063035010400042901205265636f7264206f6620616c6c2070726f706f73616c7320746861742068617665206265656e207375626a65637420746f20656d657267656e63792063616e63656c6c6174696f6e2e284d657461646174614f66000104022d0130040018ec2047656e6572616c20696e666f726d6174696f6e20636f6e6365726e696e6720616e792070726f706f73616c206f72207265666572656e64756d2e6901205468652060507265696d61676548617368602072656665727320746f2074686520707265696d616765206f66207468652060507265696d61676573602070726f76696465722077686963682063616e2062652061204a534f4e882064756d70206f7220495046532068617368206f662061204a534f4e2066696c652e00750120436f6e73696465722061206761726261676520636f6c6c656374696f6e20666f722061206d65746164617461206f662066696e6973686564207265666572656e64756d7320746f2060756e7265717565737460202872656d6f76652944206c6172676520707265696d616765732e011d03011d01303c456e6163746d656e74506572696f6410101900000014e82054686520706572696f64206265747765656e20612070726f706f73616c206265696e6720617070726f76656420616e6420656e61637465642e0031012049742073686f756c642067656e6572616c6c792062652061206c6974746c65206d6f7265207468616e2074686520756e7374616b6520706572696f6420746f20656e737572652074686174510120766f74696e67207374616b657273206861766520616e206f70706f7274756e69747920746f2072656d6f7665207468656d73656c7665732066726f6d207468652073797374656d20696e207468652063617365b4207768657265207468657920617265206f6e20746865206c6f73696e672073696465206f66206120766f74652e304c61756e6368506572696f6410102c01000004e420486f77206f6674656e2028696e20626c6f636b7329206e6577207075626c6963207265666572656e646120617265206c61756e636865642e30566f74696e67506572696f6410102c01000004b820486f77206f6674656e2028696e20626c6f636b732920746f20636865636b20666f72206e657720766f7465732e44566f74654c6f636b696e67506572696f64101019000000109020546865206d696e696d756d20706572696f64206f6620766f7465206c6f636b696e672e0065012049742073686f756c64206265206e6f2073686f72746572207468616e20656e6163746d656e7420706572696f6420746f20656e73757265207468617420696e207468652063617365206f6620616e20617070726f76616c2c49012074686f7365207375636365737366756c20766f7465727320617265206c6f636b656420696e746f2074686520636f6e73657175656e636573207468617420746865697220766f74657320656e7461696c2e384d696e696d756d4465706f73697418400000000000000000000000000000000004350120546865206d696e696d756d20616d6f756e7420746f20626520757365642061732061206465706f73697420666f722061207075626c6963207265666572656e64756d2070726f706f73616c2e38496e7374616e74416c6c6f776564350104000c550120496e64696361746f7220666f72207768657468657220616e20656d657267656e6379206f726967696e206973206576656e20616c6c6f77656420746f2068617070656e2e20536f6d6520636861696e73206d617961012077616e7420746f207365742074686973207065726d616e656e746c7920746f206066616c7365602c206f7468657273206d61792077616e7420746f20636f6e646974696f6e206974206f6e207468696e67732073756368a020617320616e207570677261646520686176696e672068617070656e656420726563656e746c792e5446617374547261636b566f74696e67506572696f6410103200000004ec204d696e696d756d20766f74696e6720706572696f6420616c6c6f77656420666f72206120666173742d747261636b207265666572656e64756d2e34436f6f6c6f6666506572696f6410102c01000004610120506572696f6420696e20626c6f636b7320776865726520616e2065787465726e616c2070726f706f73616c206d6179206e6f742062652072652d7375626d6974746564206166746572206265696e67207665746f65642e204d6178566f74657310106400000010b020546865206d6178696d756d206e756d626572206f6620766f74657320666f7220616e206163636f756e742e00d420416c736f207573656420746f20636f6d70757465207765696768742c20616e206f7665726c79206269672076616c75652063616e1501206c65616420746f2065787472696e7369632077697468207665727920626967207765696768743a20736565206064656c65676174656020666f7220696e7374616e63652e304d617850726f706f73616c73101064000000040d0120546865206d6178696d756d206e756d626572206f66207075626c69632070726f706f73616c7320746861742063616e20657869737420617420616e792074696d652e2c4d61784465706f73697473101064000000041d0120546865206d6178696d756d206e756d626572206f66206465706f736974732061207075626c69632070726f706f73616c206d6179206861766520617420616e792074696d652e384d6178426c61636b6c697374656410106400000004d820546865206d6178696d756d206e756d626572206f66206974656d732077686963682063616e20626520626c61636b6c69737465642e01f9072a1c436f756e63696c011c436f756e63696c182450726f706f73616c730100fd07040004902054686520686173686573206f6620746865206163746976652070726f706f73616c732e2850726f706f73616c4f6600010406305d01040004cc2041637475616c2070726f706f73616c20666f72206120676976656e20686173682c20696620697427732063757272656e742e18566f74696e6700010406300108040004b420566f746573206f6e206120676976656e2070726f706f73616c2c206966206974206973206f6e676f696e672e3450726f706f73616c436f756e74010010100000000004482050726f706f73616c7320736f206661722e1c4d656d626572730100e5010400043901205468652063757272656e74206d656d62657273206f662074686520636f6c6c6563746976652e20546869732069732073746f72656420736f7274656420286a7573742062792076616c7565292e145072696d65000000040004650120546865207072696d65206d656d62657220746861742068656c70732064657465726d696e65207468652064656661756c7420766f7465206265686176696f7220696e2063617365206f6620616273656e746174696f6e732e012d0301310104444d617850726f706f73616c57656967687424280700a0db215d0200000104250120546865206d6178696d756d20776569676874206f6620612064697370617463682063616c6c20746861742063616e2062652070726f706f73656420616e642065786563757465642e0105082b48546563686e6963616c436f6d6d69747465650148546563686e6963616c436f6d6d6974746565182450726f706f73616c7301000908040004902054686520686173686573206f6620746865206163746976652070726f706f73616c732e2850726f706f73616c4f6600010406305d01040004cc2041637475616c2070726f706f73616c20666f72206120676976656e20686173682c20696620697427732063757272656e742e18566f74696e6700010406300108040004b420566f746573206f6e206120676976656e2070726f706f73616c2c206966206974206973206f6e676f696e672e3450726f706f73616c436f756e74010010100000000004482050726f706f73616c7320736f206661722e1c4d656d626572730100e5010400043901205468652063757272656e74206d656d62657273206f662074686520636f6c6c6563746976652e20546869732069732073746f72656420736f7274656420286a7573742062792076616c7565292e145072696d65000000040004650120546865207072696d65206d656d62657220746861742068656c70732064657465726d696e65207468652064656661756c7420766f7465206265686176696f7220696e2063617365206f6620616273656e746174696f6e732e01310301390104444d617850726f706f73616c57656967687424280700a0db215d0200000104250120546865206d6178696d756d20776569676874206f6620612064697370617463682063616c6c20746861742063616e2062652070726f706f73656420616e642065786563757465642e010d082c44436f756e63696c4d656d626572736869700144436f756e63696c4d656d62657273686970081c4d656d6265727301001108040004c8205468652063757272656e74206d656d626572736869702c2073746f72656420617320616e206f726465726564205665632e145072696d65000000040004a4205468652063757272656e74207072696d65206d656d6265722c206966206f6e65206578697374732e013503013d01000115082d70546563686e6963616c436f6d6d69747465654d656d626572736869700170546563686e6963616c436f6d6d69747465654d656d62657273686970081c4d656d6265727301001908040004c8205468652063757272656e74206d656d626572736869702c2073746f72656420617320616e206f726465726564205665632e145072696d65000000040004a4205468652063757272656e74207072696d65206d656d6265722c206966206f6e65206578697374732e01390301410100011d082e5046656c6c6f7773686970436f6c6c656374697665015046656c6c6f7773686970436f6c6c656374697665182c4d656d626572436f756e7401010405490110100000000008690120546865206e756d626572206f66206d656d6265727320696e2074686520636f6c6c6563746976652077686f2068617665206174206c65617374207468652072616e6b206163636f7264696e6720746f2074686520696e64657830206f6620746865207665632e1c4d656d62657273000104050021080400049c205468652063757272656e74206d656d62657273206f662074686520636f6c6c6563746976652e244964546f496e646578000108050525081004000461012054686520696e646578206f6620656163682072616e6b732773206d656d62657220696e746f207468652067726f7570206f66206d656d626572732077686f2068617665206174206c6561737420746861742072616e6b2e24496e646578546f496400010805052908000400085d0120546865206d656d6265727320696e2074686520636f6c6c65637469766520627920696e6465782e20416c6c20696e646963657320696e207468652072616e67652060302e2e4d656d626572436f756e74602077696c6c65012072657475726e2060536f6d65602c20686f77657665722061206d656d626572277320696e646578206973206e6f742067756172616e7465656420746f2072656d61696e20756e6368616e676564206f7665722074696d652e18566f74696e6700010802052d084d01040004b420566f746573206f6e206120676976656e2070726f706f73616c2c206966206974206973206f6e676f696e672e34566f74696e67436c65616e757000010402103108040000013d03014501000135082f4c46656c6c6f77736869705265666572656e6461014c46656c6c6f77736869705265666572656e6461143c5265666572656e64756d436f756e74010010100000000004310120546865206e6578742066726565207265666572656e64756d20696e6465782c20616b6120746865206e756d626572206f66207265666572656e6461207374617274656420736f206661722e445265666572656e64756d496e666f466f7200010402103908040004b420496e666f726d6174696f6e20636f6e6365726e696e6720616e7920676976656e207265666572656e64756d2e28547261636b517565756501010405490159080400105d012054686520736f72746564206c697374206f66207265666572656e646120726561647920746f206265206465636964656420627574206e6f7420796574206265696e6720646563696465642c206f7264657265642062797c20636f6e76696374696f6e2d776569676874656420617070726f76616c732e00410120546869732073686f756c6420626520656d70747920696620604465636964696e67436f756e7460206973206c657373207468616e2060547261636b496e666f3a3a6d61785f6465636964696e67602e344465636964696e67436f756e7401010405490110100000000004c420546865206e756d626572206f66207265666572656e6461206265696e6720646563696465642063757272656e746c792e284d657461646174614f66000104021030040018050120546865206d6574616461746120697320612067656e6572616c20696e666f726d6174696f6e20636f6e6365726e696e6720746865207265666572656e64756d2e6901205468652060507265696d61676548617368602072656665727320746f2074686520707265696d616765206f66207468652060507265696d61676573602070726f76696465722077686963682063616e2062652061204a534f4e882064756d70206f7220495046532068617368206f662061204a534f4e2066696c652e00750120436f6e73696465722061206761726261676520636f6c6c656374696f6e20666f722061206d65746164617461206f662066696e6973686564207265666572656e64756d7320746f2060756e7265717565737460202872656d6f76652944206c6172676520707265696d616765732e01410301550114445375626d697373696f6e4465706f7369741840e803000000000000000000000000000004350120546865206d696e696d756d20616d6f756e7420746f20626520757365642061732061206465706f73697420666f722061207075626c6963207265666572656e64756d2070726f706f73616c2e244d617851756575656410106400000004e4204d6178696d756d2073697a65206f6620746865207265666572656e64756d20717565756520666f7220612073696e676c6520747261636b2e44556e6465636964696e6754696d656f757410102c01000008550120546865206e756d626572206f6620626c6f636b73206166746572207375626d697373696f6e20746861742061207265666572656e64756d206d75737420626567696e206265696e6720646563696465642062792ee4204f6e63652074686973207061737365732c207468656e20616e796f6e65206d61792063616e63656c20746865207265666572656e64756d2e34416c61726d496e74657276616c1010010000000c5d01205175616e74697a6174696f6e206c6576656c20666f7220746865207265666572656e64756d2077616b657570207363686564756c65722e204120686967686572206e756d6265722077696c6c20726573756c7420696e5d012066657765722073746f726167652072656164732f777269746573206e656564656420666f7220736d616c6c657220766f746572732c2062757420616c736f20726573756c7420696e2064656c61797320746f207468655501206175746f6d61746963207265666572656e64756d20737461747573206368616e6765732e204578706c6963697420736572766963696e6720696e737472756374696f6e732061726520756e61666665637465642e18547261636b735d085501040a004c64656d6f63726163795f70726f706f73616c730a0000000000e8890423c78a0000000000000000190000002c01000032000000050000000000ca9a3b0065cd1d00ca9a3b0000ca9a3b000000000065cd1d04e020496e666f726d6174696f6e20636f6e6365726e696e672074686520646966666572656e74207265666572656e64756d20747261636b732e01750830245363686564756c657201245363686564756c65720c3c496e636f6d706c65746553696e6365000010040000184167656e6461010104051079080400044d01204974656d7320746f2062652065786563757465642c20696e64657865642062792074686520626c6f636b206e756d626572207468617420746865792073686f756c64206265206578656375746564206f6e2e184c6f6f6b757000010405047903040010f8204c6f6f6b75702066726f6d2061206e616d6520746f2074686520626c6f636b206e756d62657220616e6420696e646578206f6620746865207461736b2e00590120466f72207633202d3e207634207468652070726576696f75736c7920756e626f756e646564206964656e7469746965732061726520426c616b65322d3235362068617368656420746f20666f726d2074686520763430206964656e7469746965732e01710301b90508344d6178696d756d57656967687424280700b864d9450200c00004290120546865206d6178696d756d207765696768742074686174206d6179206265207363686564756c65642070657220626c6f636b20666f7220616e7920646973706174636861626c65732e504d61785363686564756c6564506572426c6f636b101032000000141d0120546865206d6178696d756d206e756d626572206f66207363686564756c65642063616c6c7320696e2074686520717565756520666f7220612073696e676c6520626c6f636b2e0018204e4f54453a5101202b20446570656e64656e742070616c6c657473272062656e63686d61726b73206d696768742072657175697265206120686967686572206c696d697420666f72207468652073657474696e672e205365742061c420686967686572206c696d697420756e646572206072756e74696d652d62656e63686d61726b736020666561747572652e018908311c4f726967696e730000000000632458636d705175657565012458636d7051756575652844496e626f756e6458636d7053746174757301008d080400049420537461747573206f662074686520696e626f756e642058434d50206368616e6e656c732e4c496e626f756e6458636d704d657373616765730101080205a50834040004190120496e626f756e64206167677265676174652058434d50206d657373616765732e2049742063616e206f6e6c79206265206f6e6520706572205061726149642f626c6f636b2e484f7574626f756e6458636d705374617475730100a9080400185d0120546865206e6f6e2d656d7074792058434d50206368616e6e656c7320696e206f72646572206f66206265636f6d696e67206e6f6e2d656d7074792c20616e642074686520696e646578206f6620746865206669727374510120616e64206c617374206f7574626f756e64206d6573736167652e204966207468652074776f20696e64696365732061726520657175616c2c207468656e20697420696e6469636174657320616e20656d707479590120717565756520616e64207468657265206d7573742062652061206e6f6e2d604f6b6020604f7574626f756e64537461747573602e20576520617373756d65207175657565732067726f77206e6f20677265617465725901207468616e203635353335206974656d732e20517565756520696e646963657320666f72206e6f726d616c206d6573736167657320626567696e206174206f6e653b207a65726f20697320726573657276656420696e11012063617365206f6620746865206e65656420746f2073656e64206120686967682d7072696f72697479207369676e616c206d657373616765207468697320626c6f636b2e09012054686520626f6f6c20697320747275652069662074686572652069732061207369676e616c206d6573736167652077616974696e6720746f2062652073656e742e504f7574626f756e6458636d704d657373616765730101080205b50834040004bc20546865206d65737361676573206f7574626f756e6420696e206120676976656e2058434d50206368616e6e656c2e385369676e616c4d6573736167657301010402ad0134040004a020416e79207369676e616c206d657373616765732077616974696e6720746f2062652073656e742e2c5175657565436f6e6669670100b90874020000000500000001000000821a06000008000700c817a804020004000415012054686520636f6e66696775726174696f6e20776869636820636f6e74726f6c73207468652064796e616d696373206f6620746865206f7574626f756e642071756575652e284f766572776569676874000104052cbd08040010050120546865206d657373616765732074686174206578636565646564206d617820696e646976696475616c206d65737361676520776569676874206275646765742e003901205468657365206d657373616765207374617920696e20746869732073746f72616765206d617020756e74696c207468657920617265206d616e75616c6c79206469737061746368656420766961582060736572766963655f6f766572776569676874602e50436f756e746572466f724f766572776569676874010010100000000004ac436f756e74657220666f72207468652072656c6174656420636f756e7465642073746f72616765206d61703c4f766572776569676874436f756e7401002c20000000000000000008690120546865206e756d626572206f66206f766572776569676874206d657373616765732065766572207265636f7264656420696e20604f766572776569676874602e20416c736f20646f75626c657320617320746865206e6578748420617661696c61626c652066726565206f76657277656967687420696e6465782e38517565756553757370656e6465640100350104000441012057686574686572206f72206e6f74207468652058434d502071756575652069732073757370656e6465642066726f6d20657865637574696e6720696e636f6d696e672058434d73206f72206e6f742e017d0301bd050001c108322c506f6c6b61646f7458636d012c506f6c6b61646f7458636d30305175657279436f756e74657201002c200000000000000000048820546865206c617465737420617661696c61626c6520717565727920696e6465782e1c51756572696573000104022cc5080400045420546865206f6e676f696e6720717565726965732e28417373657454726170730101040630101000000000106820546865206578697374696e672061737365742074726170732e007501204b65792069732074686520626c616b6532203235362068617368206f6620286f726967696e2c2076657273696f6e656420604d756c7469417373657473602920706169722e2056616c756520697320746865206e756d626572206f661d012074696d65732074686973207061697220686173206265656e20747261707065642028757375616c6c79206a75737420312069662069742065786973747320617420616c6c292e385361666558636d56657273696f6e00001004000861012044656661756c742076657273696f6e20746f20656e636f64652058434d207768656e206c61746573742076657273696f6e206f662064657374696e6174696f6e20697320756e6b6e6f776e2e20496620604e6f6e65602c3d01207468656e207468652064657374696e6174696f6e732077686f73652058434d2076657273696f6e20697320756e6b6e6f776e2061726520636f6e7369646572656420756e726561636861626c652e40537570706f7274656456657273696f6e0001080502d90810040004f020546865204c61746573742076657273696f6e732074686174207765206b6e6f7720766172696f7573206c6f636174696f6e7320737570706f72742e4056657273696f6e4e6f746966696572730001080502d9082c040004050120416c6c206c6f636174696f6e7320746861742077652068617665207265717565737465642076657273696f6e206e6f74696669636174696f6e732066726f6d2e5056657273696f6e4e6f74696679546172676574730001080502d908dd0804000871012054686520746172676574206c6f636174696f6e73207468617420617265207375627363726962656420746f206f75722076657273696f6e206368616e6765732c2061732077656c6c20617320746865206d6f737420726563656e7494206f66206f75722076657273696f6e7320776520696e666f726d6564207468656d206f662e5456657273696f6e446973636f7665727951756575650100e10804000c65012044657374696e6174696f6e732077686f7365206c61746573742058434d2076657273696f6e20776520776f756c64206c696b6520746f206b6e6f772e204475706c696361746573206e6f7420616c6c6f7765642c20616e6471012074686520607533326020636f756e74657220697320746865206e756d626572206f662074696d6573207468617420612073656e6420746f207468652064657374696e6174696f6e20686173206265656e20617474656d707465642c8c20776869636820697320757365642061732061207072696f726974697a6174696f6e2e4043757272656e744d6967726174696f6e0000ed080400049c205468652063757272656e74206d6967726174696f6e27732073746167652c20696620616e792e5452656d6f74654c6f636b656446756e6769626c657300010c050202f508fd08040004f02046756e6769626c6520617373657473207768696368207765206b6e6f7720617265206c6f636b6564206f6e20612072656d6f746520636861696e2e3c4c6f636b656446756e6769626c657300010402000d09040004e02046756e6769626c6520617373657473207768696368207765206b6e6f7720617265206c6f636b6564206f6e207468697320636861696e2e5458636d457865637574696f6e53757370656e64656401003501040004b420476c6f62616c2073757370656e73696f6e207374617465206f66207468652058434d206578656375746f722e01810301c10500011909332843756d756c757358636d0001250401c90500011d093420446d7051756575650120446d7051756575651434436f6e66696775726174696f6e01002109280700e40b540202000400044c2054686520636f6e66696775726174696f6e2e2450616765496e646578010025094000000000000000000000000000000000044020546865207061676520696e6465782e1450616765730101040210290904000444205468652071756575652070616765732e284f766572776569676874000104022c2d090400046420546865206f766572776569676874206d657373616765732e50436f756e746572466f724f766572776569676874010010100000000004ac436f756e74657220666f72207468652072656c6174656420636f756e7465642073746f72616765206d617001290401cd05000131093524496e666c6174696f6e0124496e666c6174696f6e14645374617274696e6759656172546f74616c49737375616e636501001840000000000000000000000000000000000474207374617274696e67207965617220746f74616c2069737375616e636538426c6f636b496e666c6174696f6e01001840000000000000000000000000000000000401012043757272656e7420696e666c6174696f6e20666f722060496e666c6174696f6e426c6f636b496e74657276616c60206e756d626572206f6620626c6f636b73484e657874496e666c6174696f6e426c6f636b010010100000000004e4204e65787420746172676574202872656c61792920626c6f636b207768656e20696e666c6174696f6e2077696c6c206265206170706c696564584e657874526563616c63756c6174696f6e426c6f636b010010100000000004e4204e65787420746172676574202872656c61792920626c6f636b207768656e20696e666c6174696f6e20697320726563616c63756c61746564285374617274426c6f636b0100101000000000049c2052656c617920626c6f636b207768656e20696e666c6174696f6e206861732073746172746564012d04000458496e666c6174696f6e426c6f636b496e74657276616c101064000000043501204e756d626572206f6620626c6f636b7320746861742070617373206265747765656e2074726561737572792062616c616e636520757064617465732064756520746f20696e666c6174696f6e003c18556e697175650118556e697175652430436861696e56657273696f6e01002c2000000000000000000450205573656420666f72206d6967726174696f6e73404372656174654974656d4261736b657400010402350910040008cc2028436f6c6c656374696f6e2069642028636f6e74726f6c6c65643f32292c2077686f206372656174656420287265616c2929410120544f444f3a204f666620636861696e20776f726b65722073686f756c642072656d6f76652066726f6d2074686973206d6170207768656e20636f6c6c656374696f6e20676574732072656d6f766564444e66745472616e736665724261736b65740001080202390910040004d820436f6c6c656374696f6e2069642028636f6e74726f6c6c65643f32292c20746f6b656e2069642028636f6e74726f6c6c65643f32295846756e6769626c655472616e736665724261736b65740001080205350910040004c420436f6c6c656374696f6e2069642028636f6e74726f6c6c65643f32292c206f776e696e67207573657220287265616c2960526546756e6769626c655472616e736665724261736b657400010c0202053d0910040004d820436f6c6c656374696f6e2069642028636f6e74726f6c6c65643f32292c20746f6b656e2069642028636f6e74726f6c6c65643f32294c546f6b656e50726f70657274794261736b657400010802023909100400045901204c6173742073706f6e736f72696e67206f6620746f6b656e2070726f70657274792073657474696e67202f2f20746f646f3a646f63207265706872617365207468697320616e642074686520666f6c6c6f77696e67404e6674417070726f76654261736b65740001080202390910040004c0204c6173742073706f6e736f72696e67206f66204e465420617070726f76616c20696e206120636f6c6c656374696f6e5446756e6769626c65417070726f76654261736b65740001080205350910040004f0204c6173742073706f6e736f72696e67206f662066756e6769626c6520746f6b656e7320617070726f76616c20696e206120636f6c6c656374696f6e5c526566756e6769626c65417070726f76654261736b657400010c0202053d0910040004c0204c6173742073706f6e736f72696e67206f662052465420617070726f76616c20696e206120636f6c6c656374696f6e0131040034386e657374696e675f62756467657410100500000004fc2041206d6178696d756d206e756d626572206f66206c6576656c73206f6620646570746820696e2074686520746f6b656e206e657374696e6720747265652e686d61785f636f6c6c656374696f6e5f6e616d655f6c656e6774681010400000000494204d6178696d616c206c656e677468206f66206120636f6c6c656374696f6e206e616d652e846d61785f636f6c6c656374696f6e5f6465736372697074696f6e5f6c656e67746810100001000004b0204d6178696d616c206c656e677468206f66206120636f6c6c656374696f6e206465736372697074696f6e2e5c6d61785f746f6b656e5f7072656669785f6c656e6774681010100000000488204d6178696d616c206c656e677468206f66206120746f6b656e207072656669782e5c636f6c6c656374696f6e5f61646d696e735f6c696d6974101005000000047c204d6178696d756d2061646d696e732070657220636f6c6c656374696f6e2e5c6d61785f70726f70657274795f6b65795f6c656e6774681010000100000488204d6178696d616c206c656e677468206f6620612070726f7065727479206b65792e646d61785f70726f70657274795f76616c75655f6c656e6774681010008000000490204d6178696d616c206c656e677468206f6620612070726f70657274792076616c75652e5c6d61785f70726f706572746965735f7065725f6974656d10104000000004982041206d6178696d756d206e756d626572206f6620746f6b656e2070726f706572746965732e786d61785f636f6c6c656374696f6e5f70726f706572746965735f73697a65101000a0000004b0204d6178696d756d2073697a6520666f7220616c6c20636f6c6c656374696f6e2070726f706572746965732e646d61785f746f6b656e5f70726f706572746965735f73697a651010008000000498204d6178696d756d2073697a65206f6620616c6c20746f6b656e2070726f706572746965732e746e66745f64656661756c745f636f6c6c656374696f6e5f6c696d6974735d04840140420f000100080000010001ffffffff0105000000010500000001000101010104782044656661756c74204e465420636f6c6c656374696f6e206c696d69742e747266745f64656661756c745f636f6c6c656374696f6e5f6c696d6974735d04840140420f000100080000010001ffffffff0105000000010500000001000101010104782044656661756c742052465420636f6c6c656374696f6e206c696d69742e7066745f64656661756c745f636f6c6c656374696f6e5f6c696d6974735d04840140420f000100080000010001ffffffff0105000000010500000001000101010104742044656661756c7420465420636f6c6c656374696f6e206c696d69742e0141093d34436f6e66696775726174696f6e0134436f6e66696775726174696f6e1878576569676874546f466565436f656666696369656e744f7665727269646501002c20449004f701540801004c4d696e47617350726963654f7665727269646501002c20788dfa33b4010000008c41707050726f6d6f6d6f74696f6e436f6e66696775726174696f6e4f7665727269646501001505100000000000a4436f6c6c61746f7253656c656374696f6e44657369726564436f6c6c61746f72734f76657272696465010010100a0000000090436f6c6c61746f7253656c656374696f6e4c6963656e7365426f6e644f766572726964650100184000000040eaed7446d09c2c9f0c0000000098436f6c6c61746f7253656c656374696f6e4b69636b5468726573686f6c644f76657272696465010010102c01000000010d0501d105207444656661756c74576569676874546f466565436f656666696369656e742c20449004f701540801004844656661756c744d696e47617350726963652c20788dfa33b401000000584d617858636d416c6c6f7765644c6f636174696f6e73101010000000005441707050726f6d6f74696f6e4461696c79526174651d051020a10700003844617952656c6179426c6f636b73101040380000009044656661756c74436f6c6c61746f7253656c656374696f6e4d6178436f6c6c61746f727310100a000000008c44656661756c74436f6c6c61746f7253656c656374696f6e4c6963656e7365426f6e64184000000040eaed7446d09c2c9f0c000000009444656661756c74436f6c6c61746f7253656c656374696f6e4b69636b5468726573686f6c6410102c010000000145093f204368617267696e6700000000004018436f6d6d6f6e0118436f6d6d6f6e245843726561746564436f6c6c656374696f6e436f756e740100890410000000000469012053746f72616765206f662074686520636f756e74206f66206372656174656420636f6c6c656374696f6e732e20457373656e7469616c6c7920636f6e7461696e7320746865206c61737420636f6c6c656374696f6e2049442e6044657374726f796564436f6c6c656374696f6e436f756e7401008904100000000004b42053746f72616765206f662074686520636f756e74206f662064656c6574656420636f6c6c656374696f6e732e38436f6c6c656374696f6e427949640001040289044909040004702053746f72616765206f6620636f6c6c656374696f6e20696e666f2e50436f6c6c656374696f6e50726f7065727469657301010402890451092400000000000000000004882053746f72616765206f6620636f6c6c656374696f6e2070726f706572746965732e74436f6c6c656374696f6e50726f70657274795065726d697373696f6e730101040289046909040004dc2053746f72616765206f6620746f6b656e2070726f7065727479207065726d697373696f6e73206f66206120636f6c6c656374696f6e2e2c41646d696e416d6f756e7401010402890410100000000004b02053746f72616765206f662074686520616d6f756e74206f6620636f6c6c656374696f6e2061646d696e732e1c497341646d696e01010802027d0935010400046c204c697374206f6620636f6c6c656374696f6e2061646d696e732e24416c6c6f776c69737401010802027d0935010400047820416c6c6f776c697374656420636f6c6c656374696f6e2075736572732e4444756d6d7953746f7261676556616c7565000081090400040501204e6f74207573656420627920636f64652c20657869737473206f6e6c7920746f2070726f7669646520736f6d6520747970657320746f206d657461646174612e0001d5050c5c436f6c6c656374696f6e4372656174696f6e507269636518400000c84e676dc11b000000000000000004882053657420707269636520746f20637265617465206120636f6c6c656374696f6e2e3c436f6e7472616374416464726573736503506c4e9fe1ae37a41e93cee429e8e1881abdcbb54f041901204164647265737320756e6465722077686963682074686520436f6c6c656374696f6e48656c70657220636f6e747261637420776f756c6420626520617661696c61626c652e5c636f6c6c656374696f6e5f61646d696e735f6c696d6974101005000000047c204d6178696d756d2061646d696e732070657220636f6c6c656374696f6e2e01c509422046756e6769626c65012046756e6769626c650c2c546f74616c537570706c7901010405890418400000000000000000000000000000000004d420546f74616c20616d6f756e74206f662066756e6769626c6520746f6b656e7320696e73696465206120636f6c6c656374696f6e2e1c42616c616e636501010805027d0918400000000000000000000000000000000004e820416d6f756e74206f6620746f6b656e73206f776e656420627920616e206163636f756e7420696e73696465206120636f6c6c656374696f6e2e24416c6c6f77616e636501010c050002c9091840000000000000000000000000000000000405012053746f7261676520666f72206173736574732064656c65676174656420746f2061206c696d6974656420657874656e7420746f206f746865722075736572732e00000001cd094328526566756e6769626c650128526566756e6769626c652430546f6b656e734d696e74656401010405890410100000000004bc20546f74616c20616d6f756e74206f66206d696e74656420746f6b656e7320696e206120636f6c6c656374696f6e2e2c546f6b656e734275726e7401010405890410100000000004a020416d6f756e74206f6620746f6b656e73206275726e7420696e206120636f6c6c656374696f6e2e3c546f6b656e50726f7065727469657300010805053909d109040004cc20416d6f756e74206f6620706965636573206120726566756e6769626c6520746f6b656e2069732073706c697420696e746f2e2c546f74616c537570706c7901010805053909184000000000000000000000000000000000048420546f74616c20616d6f756e74206f662070696563657320666f7220746f6b656e144f776e656401010c050205d5093501040004ac205573656420746f20656e756d657261746520746f6b656e73206f776e6564206279206163636f756e742e384163636f756e7442616c616e636501010805027d0910100000000004450120416d6f756e74206f6620746f6b656e7320286e6f742070696563657329207061727469616c6c79206f776e656420627920616e206163636f756e742077697468696e206120636f6c6c656374696f6e2e1c42616c616e636501010c050502d90918400000000000000000000000000000000004a420416d6f756e74206f6620746f6b656e20706965636573206f776e6564206279206163636f756e742e24416c6c6f77616e636501011005050002dd0918400000000000000000000000000000000004e50120416c6c6f77616e636520736574206279206120746f6b656e206f776e657220666f7220616e6f74686572207573657220746f20706572666f726d206f6e65206f66206365727461696e207472616e73616374696f6e73206f6e2061206e756d626572206f6620706965636573206f66206120746f6b656e2e4c436f6c6c656374696f6e416c6c6f77616e636501010c050202c90935010400048d01205370656e6465722073657420627920612077616c6c6574206f776e6572207468617420636f756c6420706572666f726d206365727461696e207472616e73616374696f6e73206f6e20616c6c20746f6b656e7320696e207468652077616c6c65742e00000001e109442c4e6f6e66756e6769626c65012c4e6f6e66756e6769626c652830546f6b656e734d696e74656401010405890410100000000004bc20546f74616c20616d6f756e74206f66206d696e74656420746f6b656e7320696e206120636f6c6c656374696f6e2e2c546f6b656e734275726e7401010405890410100000000004a020416d6f756e74206f66206275726e7420746f6b656e7320696e206120636f6c6c656374696f6e2e24546f6b656e4461746100010805053909e509040004c020546f6b656e20646174612c207573656420746f207061727469616c6c79206465736372696265206120746f6b656e2e3c546f6b656e50726f7065727469657300010805053909d109040004f0204d6170206f66206b65792d76616c75652070616972732c2064657363726962696e6720746865206d65746164617461206f66206120746f6b656e2e48546f6b656e41757850726f7065727469657300011005050505e909f109040024d020437573746f6d2064617461206f66206120746f6b656e20746861742069732073657269616c697a656420746f2062797465732cb0207072696d6172696c7920726573657276656420666f72206f6e2d636861696e206f7065726174696f6e732cac206e6f726d616c6c79206f627363757265642066726f6d207468652065787465726e616c2075736572732e00c420417578696c696172792070726f706572746965732061726520736c696768746c7920646966666572656e742066726f6dd420757375616c205b60546f6b656e50726f70657274696573605d2064756520746f20616e20756e6c696d69746564206e756d626572d820616e642073657061726174656c792073746f72656420616e64207772697474656e2d746f206b65792d76616c75652070616972732e00482043757272656e746c7920756e757365642e144f776e656401010c050205d5093501040004ac205573656420746f20656e756d657261746520746f6b656e73206f776e6564206279206163636f756e742e34546f6b656e4368696c6472656e01010c050505f509350104000490205573656420746f20656e756d657261746520746f6b656e2773206368696c6472656e2e384163636f756e7442616c616e636501010805027d0910100000000004d820416d6f756e74206f6620746f6b656e73206f776e656420627920616e206163636f756e7420696e206120636f6c6c656374696f6e2e24416c6c6f77616e6365000108050539094d040400048d0120416c6c6f77616e636520736574206279206120746f6b656e206f776e657220666f7220616e6f74686572207573657220746f20706572666f726d206f6e65206f66206365727461696e207472616e73616374696f6e73206f6e206120746f6b656e2e4c436f6c6c656374696f6e416c6c6f77616e636501010c050202c90935010400049101204f70657261746f722073657420627920612077616c6c6574206f776e6572207468617420636f756c6420706572666f726d206365727461696e207472616e73616374696f6e73206f6e20616c6c20746f6b656e7320696e207468652077616c6c65742e00000001f90945245374727563747572650001290501d9050001fd09463041707050726f6d6f74696f6e013041707050726f6d6f74696f6e182c546f74616c5374616b6564010018400000000000000000000000000000000004802053746f7265732074686520746f74616c207374616b656420616d6f756e742e1441646d696e00000004000485012053746f72657320746865206061646d696e60206163636f756e742e20536f6d652065787472696e736963732063616e206f6e6c7920626520657865637574656420696620746865792077657265207369676e6564206279206061646d696e602e185374616b65640101080205010a050a5000000000000000000000000000000000000000001809012053746f7265732074686520616d6f756e74206f6620746f6b656e73207374616b6564206279206163636f756e7420696e2074686520626c6f636b6e756d6265722e0074202a202a2a4b6579312a2a202d205374616b6572206163636f756e742ee4202a202a2a4b6579322a2a202d2052656c617920626c6f636b206e756d626572207768656e20746865207374616b6520776173206d6164652ed4202a202a2a2842616c616e63652c20426c6f636b4e756d626572292a2a202d2042616c616e6365206f6620746865207374616b652e490120546865206e756d626572206f66207468652072656c617920626c6f636b20696e207768696368207765206d75737420706572666f726d2074686520696e74657265737420726563616c63756c6174696f6e405374616b65735065724163636f756e74010104020008040010c42053746f726573206e756d626572206f66207374616b65207265636f72647320666f7220616e20604163636f756e74602e0070202a202a2a4b65792a2a202d205374616b6572206163636f756e742e80202a202a2a56616c75652a2a202d20416d6f756e74206f66207374616b65732e3850656e64696e67556e7374616b650101040510090a040010a82050656e64696e6720756e7374616b65207265636f72647320666f7220616e20604163636f756e74602e0070202a202a2a4b65792a2a202d205374616b6572206163636f756e742e80202a202a2a56616c75652a2a202d20416d6f756e74206f66207374616b65732e6050726576696f757343616c63756c617465645265636f72640000010a0400082d012053746f7265732061206b657920666f72207265636f726420666f722077686963682074686520726576656e756520726563616c63756c6174696f6e2077617320706572666f726d65642eb90120496620604e6f6e65602c207468656e20726563616c63756c6174696f6e20686173206e6f7420796574206265656e20706572666f726d6564206f722063616c63756c6174696f6e732068617665206265656e20636f6d706c6574656420666f7220616c6c207374616b6572732e012d0501dd05182050616c6c657449644907206170707374616b65041901205468652061707027732070616c6c65742069642c207573656420666f72206465726976696e672069747320736f7665726569676e206163636f756e7420616464726573732e40467265657a654964656e7469666965720501406170707374616b656170707374616b65049420467265657a65206964656e7469666965722075736564206279207468652070616c6c657454526563616c63756c6174696f6e496e74657276616c101040380000044420496e2072656c617920626c6f636b732e3c50656e64696e67496e74657276616c1010e0c40000045420496e2070617261636861696e20626c6f636b732e38496e74657276616c496e636f6d651d051020a107000429012052617465206f662072657475726e20666f7220696e74657276616c20696e20626c6f636b7320646566696e656420696e2060526563616c63756c6174696f6e496e74657276616c602e1c4e6f6d696e616c1840000064a7b3b6e00d0000000000000000047420446563696d616c7320666f7220746865206043757272656e6379602e01110a4934466f726569676e4173736574730134466f726569676e41737365747314484e657874466f726569676e4173736574496401001010000000000c8c204e65787420617661696c61626c6520466f726569676e20417373657449642049442e008c204e657874466f726569676e417373657449643a20466f726569676e4173736574496454466f726569676e41737365744c6f636174696f6e730001040510d404000c84205468652073746f726167657320666f72204d756c74694c6f636174696f6e732e000d0120466f726569676e41737365744c6f636174696f6e733a206d617020466f726569676e41737365744964203d3e204f7074696f6e3c4d756c74694c6f636174696f6e3e544c6f636174696f6e546f43757272656e637949647300010405d41004000c78205468652073746f726167657320666f722043757272656e63794964732e000d01204c6f636174696f6e546f43757272656e63794964733a206d6170204d756c74694c6f636174696f6e203d3e204f7074696f6e3c466f726569676e417373657449643e3841737365744d6574616461746173000104050d01390504000c84205468652073746f726167657320666f722041737365744d65746164617461732e00d82041737365744d65746164617461733a206d6170204173736574496473203d3e204f7074696f6e3c41737365744d657461646174613e30417373657442696e64696e6700010405108904040008dc205468652073746f726167657320666f722061737365747320746f2066756e6769626c6520636f6c6c656374696f6e2062696e64696e670001350501e1050001150a500c45564d010c45564d10304163636f756e74436f64657301010402650334040000504163636f756e74436f6465734d65746164617461000104026503190a0400003c4163636f756e7453746f726167657301010802021d0a30800000000000000000000000000000000000000000000000000000000000000000002c43757272656e744c6f677301009d05040008a0205772697474656e206f6e206c6f672c207265736574206166746572207472616e73616374696f6e942053686f756c6420626520656d707479206265747765656e207472616e73616374696f6e7301450501e5050001210a6420457468657265756d0120457468657265756d181c50656e64696e670100250a040004d02043757272656e74206275696c64696e6720626c6f636b2773207472616e73616374696f6e7320616e642072656365697074732e3043757272656e74426c6f636b0000450a04000470205468652063757272656e7420457468657265756d20626c6f636b2e3c43757272656e7452656365697074730000590a0400047c205468652063757272656e7420457468657265756d2072656365697074732e6843757272656e745472616e73616374696f6e537461747573657300005d0a04000488205468652063757272656e74207472616e73616374696f6e2073746174757365732e24426c6f636b48617368010104054905308000000000000000000000000000000000000000000000000000000000000000000034496e6a65637465644e6f6e63650100490580000000000000000000000000000000000000000000000000000000000000000004190120496e6a6563746564207472616e73616374696f6e732073686f756c64206861766520756e69717565206e6f6e63652c20686572652077652073746f72652063757272656e7401610501e9050001610a654445766d436f6465725375627374726174650000000001650a964845766d436f6e747261637448656c70657273014845766d436f6e747261637448656c7065727324144f776e6572010104036503650350000000000000000000000000000000000000000010682053746f7265206f776e657220666f7220636f6e74726163742e0078202a202a2a4b65792a2a202d20636f6e747261637420616464726573732e88202a202a2a56616c75652a2a202d206f776e657220666f7220636f6e74726163742e3853656c6653706f6e736f72696e6701010403650335010400049c20446570726563617465643a20746869732073746f7261676520697320646570726563617465642853706f6e736f72696e67010104056503690a040010982053746f726520666f7220636f6e74726163742073706f6e736f72736869702073746174652e0078202a202a2a4b65792a2a202d20636f6e747261637420616464726573732e84202a202a2a56616c75652a2a202d2073706f6e736f72736869702073746174652e3853706f6e736f72696e674d6f64650001040365036d0a04001c6c2053746f726520666f722073706f6e736f72696e67206d6f64652e00282023232320557361676591012050726566657220746f2064656c65746520636f6c6c656374696f6e2066726f6d2073746f72616765206966206d6f64652063686167656420746f205b6044697361626c6564605d2853706f6e736f72696e674d6f6465543a3a44697361626c6564292e0078202a202a2a4b65792a2a202d20636f6e747261637420616464726573732ed0202a202a2a56616c75652a2a202d205b6073706f6e736f72696e67206d6f6465605d2853706f6e736f72696e674d6f646554292e4c53706f6e736f72696e67526174654c696d69740101040365031010201c000010b42053746f7261676520666f722073706f6e736f72696e672072617465206c696d697420696e20626c6f636b732e0078202a202a2a4b65792a2a202d20636f6e747261637420616464726573732ea8202a202a2a56616c75652a2a202d20616d6f756e74206f662073706f6e736f72656420626c6f636b732e4853706f6e736f72696e674665654c696d6974010104036503710a040014882053746f7261676520666f72206c6173742073706f6e736f72656420626c6f636b2e007c202a202a2a4b6579312a2a202d20636f6e747261637420616464726573732e94202a202a2a4b6579322a2a202d2073706f6e736f726564207573657220616464726573732eac202a202a2a56616c75652a2a202d206c6173742073706f6e736f72656420626c6f636b206e756d6265722e3453706f6e736f724261736b65740001080303810a1004000040416c6c6f776c697374456e61626c6564010104036503350104001c69012053746f7265676520666f7220636f6e7472616374732077697468205b60416c6c6f776c6973746564605d2853706f6e736f72696e674d6f6465543a3a416c6c6f776c6973746564292073706f6e736f72696e67206d6f64652e002820232323205573616765bd012050726566657220746f2064656c65746520636f6c6c656374696f6e2066726f6d2073746f72616765206966206d6f64652063686167656420746f206e6f6e2060416c6c6f776c6973746564602c207468616e20736574202a2a56616c75652a2a20746f202a2a66616c73652a2a2e0078202a202a2a4b65792a2a202d20636f6e747261637420616464726573732e4501202a202a2a56616c75652a2a202d20697320636f6e747261637420696e205b60416c6c6f776c6973746564605d2853706f6e736f72696e674d6f6465543a3a416c6c6f776c697374656429206d6f64652e24416c6c6f776c6973740101080303810a3501040020c02053746f7261676520666f72207573657273207468617420616c6c6f77656420666f722073706f6e736f72736869702e00282023232320557361676539012050726566657220746f2064656c657465207265636f72642066726f6d2073746f726167652069662075736572206e6f206d6f726520616c6c6f77656420666f722073706f6e736f72736869702e007c202a202a2a4b6579312a2a202d20636f6e747261637420616464726573732ec0202a202a2a4b6579322a2a202d2075736572207468617420616c6c6f77656420666f722073706f6e736f72736869702ea4202a202a2a56616c75652a2a202d20616c6c6f77616e636520666f722073706f6e736f72736869702e018905010d06043c436f6e747261637441646472657373650350842899ecf380553e8a4de75bf534cdf6fbf6404904d820416464726573732c20756e646572207768696368206d6167696320636f6e74726163742077696c6c20626520617661696c61626c6501850a975445766d5472616e73616374696f6e5061796d656e740000000000983045766d4d6967726174696f6e013045766d4d6967726174696f6e04404d6967726174696f6e50656e64696e6701010405650335010400000191050111060001890a992c4d61696e74656e616e6365012c4d61696e74656e616e6365041c456e61626c65640100350104000001a50501150600018d0a9a3c42616c616e6365734164617074657200000000009b1c5574696c6974790001a905011906044c626174636865645f63616c6c735f6c696d69741010aa2a000004a820546865206c696d6974206f6e20746865206e756d626572206f6620626174636865642063616c6c732e01910a9c24546573745574696c730124546573745574696c73081c456e61626c656401003501040000245465737456616c756501001010000000000001b105011d060001950aff990a042840436865636b5370656356657273696f6eb90a1038436865636b547856657273696f6ebd0a1030436865636b47656e65736973c10a3038436865636b4d6f7274616c697479c50a3028436865636b4e6f6e6365cd0aac2c436865636b576569676874d10aac40436865636b4d61696e74656e616e6365d50aac5044697361626c654964656e7469747943616c6c73d90aac604368617267655472616e73616374696f6e5061796d656e74dd0aac6046616b655472616e73616374696f6e46696e616c697a6572e50aace10a","id":"1"}
\ No newline at end of file
js-packages/scripts/src/proposefasttrack.tsdiffbeforeafterboth--- a/js-packages/scripts/src/proposefasttrack.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import {ApiPromise, WsProvider} from '@polkadot/api';
-import {blake2AsHex} from '@polkadot/util-crypto';
-
-async function main() {
- const networkUrl = process.argv[2];
-
- const wsProvider = new WsProvider(networkUrl);
- const api = await ApiPromise.create({provider: wsProvider});
-
- const externalDemocracyProposal = (await api.query.democracy.nextExternal() as any).unwrap()[0];
-
- let proposalHash;
- if(externalDemocracyProposal.isInline) {
- proposalHash = blake2AsHex(externalDemocracyProposal.asInline, 256);
- } else if(externalDemocracyProposal.isLegacy) {
- proposalHash = externalDemocracyProposal.asLegacy.toJSON().hash;
- } else {
- proposalHash = externalDemocracyProposal.asLookup.toJSON().hash;
- }
-
- const voringPeriod = 7200;
- const delay = 10;
-
- const democracyFastTrack = api.tx.democracy.fastTrack(proposalHash, voringPeriod, delay);
-
- const techCommThreshold = ((await api.query.technicalCommittee.members()).toJSON() as any[]).length;
- const techCommProposal = api.tx.technicalCommittee.propose(
- techCommThreshold,
- democracyFastTrack.method.toHex(),
- democracyFastTrack.encodedLength,
- );
-
- const encodedCall = techCommProposal.method.toHex();
-
- console.log('-----------------');
- console.log('Fast Track Proposal: ', `https://polkadot.js.org/apps/?rpc=${networkUrl}#/extrinsics/decode/${encodedCall}`);
- console.log('-----------------');
-
- await api.disconnect();
-}
-
-await main();
js-packages/scripts/src/proposeupgrade.tsdiffbeforeafterboth--- a/js-packages/scripts/src/proposeupgrade.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import {ApiPromise, WsProvider} from '@polkadot/api';
-import {blake2AsHex} from '@polkadot/util-crypto';
-import {readFileSync} from 'fs';
-
-async function main() {
- const networkUrl = process.argv[2];
- const wasmFile = process.argv[3];
-
- const wsProvider = new WsProvider(networkUrl);
- const api = await ApiPromise.create({provider: wsProvider});
-
- const wasmFileBytes = readFileSync(wasmFile);
- const wasmFileHash = blake2AsHex(wasmFileBytes, 256);
-
- const authorizeUpgrade = api.tx.parachainSystem.authorizeUpgrade(wasmFileHash, true);
- const enableMaintenance = api.tx.maintenance.enable();
-
- const councilMembers = (await api.query.council.members()).toJSON() as any[];
- const councilProposalThreshold = Math.floor(councilMembers.length / 2) + 1;
-
- const democracyProposalContent = api.tx.utility.batchAll([
- authorizeUpgrade.method.toHex(),
- enableMaintenance.method.toHex(),
- ]).method.toHex();
-
- const democracyProposalHash = blake2AsHex(democracyProposalContent, 256);
- const democracyProposalPreimage = api.tx.preimage.notePreimage(democracyProposalContent).method.toHex();
-
- const democracyProposal = api.tx.democracy.externalProposeDefault({
- Legacy: democracyProposalHash,
- });
-
- const councilProposal = api.tx.council.propose(
- councilProposalThreshold,
- democracyProposal,
- democracyProposal.method.encodedLength,
- ).method.toHex();
-
- const proposeUpgradeBatch = api.tx.utility.batchAll([
- democracyProposalPreimage,
- councilProposal,
- ]);
-
- const encodedCall = proposeUpgradeBatch.method.toHex();
-
- console.log('-----------------');
- console.log('Upgrade Proposal: ', `https://polkadot.js.org/apps/?rpc=${networkUrl}#/extrinsics/decode/${encodedCall}`);
- console.log('-----------------');
-
- await api.disconnect();
-}
-
-await main();
js-packages/scripts/src/transfer.nload.tsdiffbeforeafterboth--- a/js-packages/scripts/src/transfer.nload.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-/* eslint-disable @typescript-eslint/no-floating-promises */
-import os from 'os';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds} from '@unique/tests/src/util/index.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-import * as notReallyCluster from 'cluster'; // https://github.com/nodejs/node/issues/42271#issuecomment-1063415346
-const cluster = notReallyCluster as unknown as notReallyCluster.Cluster;
-
-async function findUnusedAddress(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, seedAddition = ''): Promise<IKeyringPair> {
- let bal = 0n;
- let unused;
- do {
- const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;
- unused = await privateKey(`//${randomSeed}`);
- bal = await helper.balance.getSubstrate(unused.address);
- } while(bal !== 0n);
- return unused;
-}
-
-function findUnusedAddresses(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, amount: number): Promise<IKeyringPair[]> {
- return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(helper, privateKey, '_' + Date.now())));
-}
-
-// Innacurate transfer fee
-const FEE = 10n ** 8n;
-
-let counters: { [key: string]: number } = {};
-function increaseCounter(name: string, amount: number) {
- if(!counters[name]) {
- counters[name] = 0;
- }
- counters[name] += amount;
-}
-function flushCounterToMaster() {
- if(Object.keys(counters).length === 0) {
- return;
- }
- process.send!(counters);
- counters = {};
-}
-
-async function distributeBalance(source: IKeyringPair, helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, totalAmount: bigint, stages: number) {
- const accounts = [source];
- // we don't need source in output array
- const failedAccounts = [0];
-
- const finalUserAmount = 2 ** stages - 1;
- accounts.push(...await findUnusedAddresses(helper, privateKey, finalUserAmount));
- // findUnusedAddresses produces at least 1 request per user
- increaseCounter('requests', finalUserAmount);
-
- for(let stage = 0; stage < stages; stage++) {
- const usersWithBalance = 2 ** stage;
- const amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage);
- // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`);
- const txs: Promise<boolean | void>[] = [];
- for(let i = 0; i < usersWithBalance; i++) {
- const newUser = accounts[i + usersWithBalance];
- // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`);
- const tx = helper.balance.transferToSubstrate(accounts[i], newUser.address, amount);
- txs.push(tx.catch(() => {
- failedAccounts.push(i + usersWithBalance);
- increaseCounter('txFailed', 1);
- }));
- increaseCounter('tx', 1);
- }
- await Promise.all(txs);
- }
-
- for(const account of failedAccounts.reverse()) {
- accounts.splice(account, 1);
- }
- return accounts;
-}
-
-if(cluster.isMaster) {
- let testDone = false;
- usingPlaygrounds(async (helper) => {
- const prevCounters: { [key: string]: number } = {};
- while(!testDone) {
- for(const name in counters) {
- if(!(name in prevCounters)) {
- prevCounters[name] = 0;
- }
- if(counters[name] === prevCounters[name]) {
- continue;
- }
- console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`);
- prevCounters[name] = counters[name];
- }
- await helper.wait.newBlocks(1);
- }
- });
- const waiting: Promise<void>[] = [];
- console.log(`Starting ${os.cpus().length} workers`);
- usingPlaygrounds(async (helper, privateKey) => {
- const alice = await privateKey('//Alice');
- for(const id in os.cpus()) {
- const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`;
- const workerAccount = await privateKey(WORKER_NAME);
- await helper.balance.transferToSubstrate(alice, workerAccount.address, 400n * 10n ** 23n);
-
- const worker = cluster.fork({
- WORKER_NAME,
- STAGES: id + 2,
- });
- worker.on('message', msg => {
- for(const key in msg) {
- increaseCounter(key, msg[key]);
- }
- });
- waiting.push(new Promise(res => worker.on('exit', res)));
- }
- await Promise.all(waiting);
- testDone = true;
- });
-} else {
- increaseCounter('startedWorkers', 1);
- usingPlaygrounds(async (helper, privateKey) => {
- await distributeBalance(await privateKey(process.env.WORKER_NAME as string), helper, privateKey, 400n * 10n ** 22n, 10);
- });
- const interval = setInterval(() => {
- flushCounterToMaster();
- }, 100);
- interval.unref();
-}
js-packages/scripts/transfer.nload.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/scripts/transfer.nload.ts
@@ -0,0 +1,142 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+/* eslint-disable @typescript-eslint/no-floating-promises */
+import os from 'os';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds} from '@unique/tests/util/index.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+import * as notReallyCluster from 'cluster'; // https://github.com/nodejs/node/issues/42271#issuecomment-1063415346
+const cluster = notReallyCluster as unknown as notReallyCluster.Cluster;
+
+async function findUnusedAddress(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, seedAddition = ''): Promise<IKeyringPair> {
+ let bal = 0n;
+ let unused;
+ do {
+ const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;
+ unused = await privateKey(`//${randomSeed}`);
+ bal = await helper.balance.getSubstrate(unused.address);
+ } while(bal !== 0n);
+ return unused;
+}
+
+function findUnusedAddresses(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, amount: number): Promise<IKeyringPair[]> {
+ return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(helper, privateKey, '_' + Date.now())));
+}
+
+// Innacurate transfer fee
+const FEE = 10n ** 8n;
+
+let counters: { [key: string]: number } = {};
+function increaseCounter(name: string, amount: number) {
+ if(!counters[name]) {
+ counters[name] = 0;
+ }
+ counters[name] += amount;
+}
+function flushCounterToMaster() {
+ if(Object.keys(counters).length === 0) {
+ return;
+ }
+ process.send!(counters);
+ counters = {};
+}
+
+async function distributeBalance(source: IKeyringPair, helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, totalAmount: bigint, stages: number) {
+ const accounts = [source];
+ // we don't need source in output array
+ const failedAccounts = [0];
+
+ const finalUserAmount = 2 ** stages - 1;
+ accounts.push(...await findUnusedAddresses(helper, privateKey, finalUserAmount));
+ // findUnusedAddresses produces at least 1 request per user
+ increaseCounter('requests', finalUserAmount);
+
+ for(let stage = 0; stage < stages; stage++) {
+ const usersWithBalance = 2 ** stage;
+ const amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage);
+ // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`);
+ const txs: Promise<boolean | void>[] = [];
+ for(let i = 0; i < usersWithBalance; i++) {
+ const newUser = accounts[i + usersWithBalance];
+ // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`);
+ const tx = helper.balance.transferToSubstrate(accounts[i], newUser.address, amount);
+ txs.push(tx.catch(() => {
+ failedAccounts.push(i + usersWithBalance);
+ increaseCounter('txFailed', 1);
+ }));
+ increaseCounter('tx', 1);
+ }
+ await Promise.all(txs);
+ }
+
+ for(const account of failedAccounts.reverse()) {
+ accounts.splice(account, 1);
+ }
+ return accounts;
+}
+
+if(cluster.isMaster) {
+ let testDone = false;
+ usingPlaygrounds(async (helper) => {
+ const prevCounters: { [key: string]: number } = {};
+ while(!testDone) {
+ for(const name in counters) {
+ if(!(name in prevCounters)) {
+ prevCounters[name] = 0;
+ }
+ if(counters[name] === prevCounters[name]) {
+ continue;
+ }
+ console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`);
+ prevCounters[name] = counters[name];
+ }
+ await helper.wait.newBlocks(1);
+ }
+ });
+ const waiting: Promise<void>[] = [];
+ console.log(`Starting ${os.cpus().length} workers`);
+ usingPlaygrounds(async (helper, privateKey) => {
+ const alice = await privateKey('//Alice');
+ for(const id in os.cpus()) {
+ const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`;
+ const workerAccount = await privateKey(WORKER_NAME);
+ await helper.balance.transferToSubstrate(alice, workerAccount.address, 400n * 10n ** 23n);
+
+ const worker = cluster.fork({
+ WORKER_NAME,
+ STAGES: id + 2,
+ });
+ worker.on('message', msg => {
+ for(const key in msg) {
+ increaseCounter(key, msg[key]);
+ }
+ });
+ waiting.push(new Promise(res => worker.on('exit', res)));
+ }
+ await Promise.all(waiting);
+ testDone = true;
+ });
+} else {
+ increaseCounter('startedWorkers', 1);
+ usingPlaygrounds(async (helper, privateKey) => {
+ await distributeBalance(await privateKey(process.env.WORKER_NAME as string), helper, privateKey, 400n * 10n ** 22n, 10);
+ });
+ const interval = setInterval(() => {
+ flushCounterToMaster();
+ }, 100);
+ interval.unref();
+}
js-packages/scripts/tsconfig.jsondiffbeforeafterboth--- a/js-packages/scripts/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../tsconfig.packages.json",
- "compilerOptions": {
- "rootDir": "./src",
- "outDir": "dist",
- "resolveJsonModule": true
- },
- "references": [
- { "path": "../types/tsconfig.json" },
- { "path": "../playgrounds/tsconfig.json" },
- { "path": "../tests/tsconfig.json" }
- ]
-}
\ No newline at end of file
js-packages/tests/addCollectionAdmin.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/addCollectionAdmin.test.ts
@@ -0,0 +1,120 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itSub('Add collection admin.', async ({helper}) => {
+ const [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+
+ const collection = await helper.collection.getData(collectionId);
+ expect(collection!.normalizedOwner!).to.be.equal(helper.address.normalizeSubstrate(alice.address));
+
+ await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});
+
+ const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId);
+ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
+ });
+});
+
+describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itSub("Not owner can't add collection admin.", async ({helper}) => {
+ const [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+
+ const collection = await helper.collection.getData(collectionId);
+ expect(collection?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address));
+
+ await expect(helper.collection.addAdmin(bob, collectionId, {Substrate: charlie.address})).to.be.rejectedWith(/common\.NoPermission/);
+ await expect(helper.collection.addAdmin(bob, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.NoPermission/);
+
+ const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId);
+ expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: charlie.address});
+ expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: bob.address});
+ });
+
+ itSub("Admin can't add collection admin.", async ({helper}) => {
+ const [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ const adminListAfterAddAdmin = await collection.getAdmins();
+ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
+
+ await expect(collection.addAdmin(bob, {Substrate: charlie.address})).to.be.rejectedWith(/common\.NoPermission/);
+
+ const adminListAfterAddNewAdmin = await collection.getAdmins();
+ expect(adminListAfterAddNewAdmin).to.be.deep.contains({Substrate: bob.address});
+ expect(adminListAfterAddNewAdmin).to.be.not.deep.contains({Substrate: charlie.address});
+ });
+
+ itSub("Can't add collection admin of not existing collection.", async ({helper}) => {
+ const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+
+ await expect(helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/);
+
+ // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+ await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+ });
+
+ itSub("Can't add an admin to a destroyed collection.", async ({helper}) => {
+ const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+
+ await collection.burn(alice);
+ await expect(collection.addAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/);
+
+ // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+ await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+ });
+
+ itSub('Add an admin to a collection that has reached the maximum number of admins limit', async ({helper}) => {
+ const [alice, ...accounts] = await helper.arrange.createAccounts([10n, 0n, 0n, 0n, 0n, 0n, 0n, 0n], donor);
+ const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
+
+ const chainAdminLimit = (helper.getApi().consts.common.collectionAdminsLimit as any).toNumber();
+ expect(chainAdminLimit).to.be.equal(5);
+
+ for(let i = 0; i < chainAdminLimit; i++) {
+ await collection.addAdmin(alice, {Substrate: accounts[i].address});
+ const adminListAfterAddAdmin = await collection.getAdmins();
+ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: accounts[i].address});
+ }
+
+ await expect(collection.addAdmin(alice, {Substrate: accounts[chainAdminLimit].address})).to.be.rejectedWith(/common\.CollectionAdminCountExceeded/);
+ });
+});
js-packages/tests/adminTransferAndBurn.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/adminTransferAndBurn.test.ts
@@ -0,0 +1,61 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from './util/index.js';
+
+describe('Integration Test: ownerCanTransfer allows admins to use only transferFrom/burnFrom:', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('admin transfers other user\'s token', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
+ await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+ const limits = await helper.collection.getEffectiveLimits(collectionId);
+ expect(limits.ownerCanTransfer).to.be.true;
+
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+ await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})).to.be.rejected;
+
+ await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address});
+ const newTokenOwner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(newTokenOwner).to.be.deep.equal({Substrate: charlie.address});
+ });
+
+ itSub('admin burns other user\'s token', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
+
+ await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+ const limits = await helper.collection.getEffectiveLimits(collectionId);
+ expect(limits.ownerCanTransfer).to.be.true;
+
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+
+ await expect(helper.nft.burnToken(alice, collectionId, tokenId)).to.be.rejected;
+
+ await helper.nft.burnToken(bob, collectionId, tokenId);
+ const token = await helper.nft.getToken(collectionId, tokenId);
+ expect(token).to.be.null;
+ });
+});
js-packages/tests/allowLists.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/allowLists.test.ts
@@ -0,0 +1,361 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from './util/index.js';
+import type {ICollectionPermissions} from '@unique/playgrounds/types.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test ext. Allow list tests', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);
+ });
+ });
+
+ describe('Positive', () => {
+ itSub('Owner can add address to allow list', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ // allow list does not need to be enabled to add someone in advance
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+ const allowList = await helper.nft.getAllowList(collectionId);
+ expect(allowList).to.deep.contain({Substrate: bob.address});
+ });
+
+ itSub('Admin can add address to allow list', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});
+
+ // allow list does not need to be enabled to add someone in advance
+ await helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address});
+ const allowList = await helper.nft.getAllowList(collectionId);
+ expect(allowList).to.deep.contain({Substrate: charlie.address});
+ });
+
+ itSub('If address is already added to allow list, nothing happens', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+ const allowList = await helper.nft.getAllowList(collectionId);
+ expect(allowList).to.deep.contain({Substrate: bob.address});
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('Nobody can add address to allow list of non-existing collection', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Nobody can add address to allow list of destroyed collection', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.collection.burn(alice, collectionId);
+ await expect(helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Non-privileged user cannot add address to allow list', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.NoPermission/);
+ });
+ });
+});
+
+describe('Integration Test ext. Remove from Allow List', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);
+ });
+ });
+
+ describe('Positive', () => {
+ itSub('Owner can remove address from allow list', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+
+ await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+
+ const allowList = await helper.nft.getAllowList(collectionId);
+
+ expect(allowList).to.not.deep.contain({Substrate: bob.address});
+ });
+
+ itSub('Admin can remove address from allow list', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addAdmin(alice, collectionId, {Substrate: charlie.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+ await helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: bob.address});
+
+ const allowList = await helper.nft.getAllowList(collectionId);
+ expect(allowList).to.not.deep.contain({Substrate: bob.address});
+ });
+
+ itSub('If address is already removed from allow list, nothing happens', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+ await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+ const allowListBefore = await helper.nft.getAllowList(collectionId);
+ expect(allowListBefore).to.not.deep.contain({Substrate: bob.address});
+
+ await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+
+ const allowListAfter = await helper.nft.getAllowList(collectionId);
+ expect(allowListAfter).to.not.deep.contain({Substrate: bob.address});
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('Non-privileged user cannot remove address from allow list', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+ await expect(helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.NoPermission/);
+
+ const allowList = await helper.nft.getAllowList(collectionId);
+ expect(allowList).to.deep.contain({Substrate: charlie.address});
+ });
+
+ itSub('Nobody can remove address from allow list of non-existing collection', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ await expect(helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Nobody can remove address from allow list of deleted collection', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+ await helper.collection.burn(alice, collectionId);
+
+ await expect(helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+ });
+});
+
+describe('Integration Test ext. Transfer if included in Allow List', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);
+ });
+ });
+
+ describe('Positive', () => {
+ itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transfer.', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+ await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+ const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner).to.be.deep.equal({Substrate: charlie.address});
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transferFrom.', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+ await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+
+ await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});
+ const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner).to.be.deep.equal({Substrate: charlie.address});
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+
+ await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+ const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner).to.be.deep.equal({Substrate: charlie.address});
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transferFrom', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+ await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+
+ await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});
+ const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner).to.be.deep.equal({Substrate: charlie.address});
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+
+ await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+ await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+ await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});
+
+ await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+
+ await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+
+ await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+ await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});
+
+ await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
+ });
+
+ itSub('If Public Access mode is set to AllowList, tokens can\'t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await expect(helper.nft.burnToken(bob, collectionId, tokenId))
+ .to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('If Public Access mode is set to AllowList, token transfers can\'t be Approved by a non-allowlisted address (see Approve method)', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+ await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+ await expect(helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
+ });
+ });
+});
+
+describe('Integration Test ext. Mint if included in Allow List', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ const permissionSet: ICollectionPermissions[] = [
+ {access: 'Normal', mintMode: false},
+ {access: 'Normal', mintMode: true},
+ {access: 'AllowList', mintMode: false},
+ {access: 'AllowList', mintMode: true},
+ ];
+
+ const testPermissionSuite = (permissions: ICollectionPermissions) => {
+ const allowlistedMintingShouldFail = !permissions.mintMode!;
+
+ const appropriateRejectionMessage = permissions.mintMode! ? /common\.AddressNotInAllowlist/ : /common\.PublicMintingNotAllowed/;
+
+ const allowlistedMintingTest = () => itSub(
+ `With the condtions above, tokens can${allowlistedMintingShouldFail ? '\'t' : ''} be created by allow-listed addresses`,
+ async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setPermissions(alice, permissions);
+ await collection.addToAllowList(alice, {Substrate: bob.address});
+
+ if(allowlistedMintingShouldFail)
+ await expect(collection.mintToken(bob, {Substrate: bob.address})).to.be.rejectedWith(appropriateRejectionMessage);
+ else
+ await expect(collection.mintToken(bob, {Substrate: bob.address})).to.not.be.rejected;
+ },
+ );
+
+
+ describe(`Public Access Mode = ${permissions.access}, Mint Mode = ${permissions.mintMode}`, () => {
+ describe('Positive', () => {
+ itSub('With the condtions above, tokens can be created by owner', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setPermissions(alice, permissions);
+ await expect(collection.mintToken(alice, {Substrate: alice.address})).to.not.be.rejected;
+ });
+
+ itSub('With the condtions above, tokens can be created by admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setPermissions(alice, permissions);
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await expect(collection.mintToken(bob, {Substrate: bob.address})).to.not.be.rejected;
+ });
+
+ if(!allowlistedMintingShouldFail) allowlistedMintingTest();
+ });
+
+ describe('Negative', () => {
+ itSub('With the condtions above, tokens can\'t be created by non-priviliged non-allow-listed address', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setPermissions(alice, permissions);
+ await expect(collection.mintToken(bob, {Substrate: bob.address}))
+ .to.be.rejectedWith(appropriateRejectionMessage);
+ });
+
+ if(allowlistedMintingShouldFail) allowlistedMintingTest();
+ });
+ });
+ };
+
+ for(const permissions of permissionSet) {
+ testPermissionSuite(permissions);
+ }
+});
js-packages/tests/apiConsts.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/apiConsts.test.ts
@@ -0,0 +1,116 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {ApiPromise} from '@polkadot/api';
+import {usingPlaygrounds, itSub, expect, COLLECTION_HELPER, CONTRACT_HELPER} from './util/index.js';
+
+
+const MAX_COLLECTION_DESCRIPTION_LENGTH = 256n;
+const MAX_COLLECTION_NAME_LENGTH = 64n;
+const COLLECTION_ADMINS_LIMIT = 5n;
+const MAX_COLLECTION_PROPERTIES_SIZE = 40960n;
+const MAX_TOKEN_PREFIX_LENGTH = 16n;
+const MAX_PROPERTY_KEY_LENGTH = 256n;
+const MAX_PROPERTY_VALUE_LENGTH = 32768n;
+const MAX_PROPERTIES_PER_ITEM = 64n;
+const MAX_TOKEN_PROPERTIES_SIZE = 32768n;
+const NESTING_BUDGET = 5n;
+
+const DEFAULT_COLLETCTION_LIMIT = {
+ accountTokenOwnershipLimit: '1,000,000',
+ sponsoredDataSize: '2,048',
+ sponsoredDataRateLimit: 'SponsoringDisabled',
+ tokenLimit: '4,294,967,295',
+ sponsorTransferTimeout: '5',
+ sponsorApproveTimeout: '5',
+ ownerCanTransfer: false,
+ ownerCanDestroy: true,
+ transfersEnabled: true,
+};
+
+describe('integration test: API UNIQUE consts', () => {
+ let api: ApiPromise;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper) => {
+ api = await helper.getApi();
+ });
+ });
+
+ itSub('DEFAULT_NFT_COLLECTION_LIMITS', () => {
+ expect(api.consts.unique.nftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
+ });
+
+ itSub('DEFAULT_RFT_COLLECTION_LIMITS', () => {
+ expect(api.consts.unique.rftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
+ });
+
+ itSub('DEFAULT_FT_COLLECTION_LIMITS', () => {
+ expect(api.consts.unique.ftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
+ });
+
+ itSub('MAX_COLLECTION_NAME_LENGTH', () => {
+ checkConst(api.consts.unique.maxCollectionNameLength, MAX_COLLECTION_NAME_LENGTH);
+ });
+
+ itSub('MAX_COLLECTION_DESCRIPTION_LENGTH', () => {
+ checkConst(api.consts.unique.maxCollectionDescriptionLength, MAX_COLLECTION_DESCRIPTION_LENGTH);
+ });
+
+ itSub('MAX_COLLECTION_PROPERTIES_SIZE', () => {
+ checkConst(api.consts.unique.maxCollectionPropertiesSize, MAX_COLLECTION_PROPERTIES_SIZE);
+ });
+
+ itSub('MAX_TOKEN_PREFIX_LENGTH', () => {
+ checkConst(api.consts.unique.maxTokenPrefixLength, MAX_TOKEN_PREFIX_LENGTH);
+ });
+
+ itSub('MAX_PROPERTY_KEY_LENGTH', () => {
+ checkConst(api.consts.unique.maxPropertyKeyLength, MAX_PROPERTY_KEY_LENGTH);
+ });
+
+ itSub('MAX_PROPERTY_VALUE_LENGTH', () => {
+ checkConst(api.consts.unique.maxPropertyValueLength, MAX_PROPERTY_VALUE_LENGTH);
+ });
+
+ itSub('MAX_PROPERTIES_PER_ITEM', () => {
+ checkConst(api.consts.unique.maxPropertiesPerItem, MAX_PROPERTIES_PER_ITEM);
+ });
+
+ itSub('NESTING_BUDGET', () => {
+ checkConst(api.consts.unique.nestingBudget, NESTING_BUDGET);
+ });
+
+ itSub('MAX_TOKEN_PROPERTIES_SIZE', () => {
+ checkConst(api.consts.unique.maxTokenPropertiesSize, MAX_TOKEN_PROPERTIES_SIZE);
+ });
+
+ itSub('COLLECTION_ADMINS_LIMIT', () => {
+ checkConst(api.consts.unique.collectionAdminsLimit, COLLECTION_ADMINS_LIMIT);
+ });
+
+ itSub('HELPERS_CONTRACT_ADDRESS', () => {
+ expect(api.consts.evmContractHelpers.contractAddress.toString().toLowerCase()).to.be.equal(CONTRACT_HELPER.toLowerCase());
+ });
+
+ itSub('EVM_COLLECTION_HELPERS_ADDRESS', () => {
+ expect(api.consts.common.contractAddress.toString().toLowerCase()).to.be.equal(COLLECTION_HELPER.toLowerCase());
+ });
+});
+
+function checkConst<T>(constValue: any, expectedValue: T) {
+ expect(constValue.toBigInt()).equal(expectedValue);
+}
\ No newline at end of file
js-packages/tests/approve.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/approve.test.ts
@@ -0,0 +1,658 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from './util/index.js';
+import {CrossAccountId} from '@unique/playgrounds/unique.js';
+
+
+
+[
+ {method: 'approveToken', account: (account: IKeyringPair) => CrossAccountId.fromKeyring(account).toICrossAccountId()},
+ {method: 'approveTokenFromEth', account: (account: IKeyringPair) => CrossAccountId.fromKeyring(account).toEthereum().toICrossAccountId()},
+].map(testCase => {
+ describe(`Integration Test ${testCase.method}(spender, collection_id, item_id, amount):`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('[nft] Execute the extrinsic and check approvedList', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
+ await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
+ });
+
+ itSub('[fungible] Execute the extrinsic and check approvedList', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
+ expect(amount).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('[refungible] Execute the extrinsic and check approvedList', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
+ await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
+ expect(amount).to.be.equal(1n);
+ });
+
+ itSub('[nft] Remove approval by using 0 amount', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const collectionId = collection.collectionId;
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
+ await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
+ await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
+ });
+
+ itSub('[fungible] Remove approval by using 0 amount', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
+ expect(amountBefore).to.be.equal(1n);
+
+ await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+ const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
+ expect(amountAfter).to.be.equal(0n);
+ });
+
+ itSub.ifWithPallets('[refungible] Remove approval by using 0 amount', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
+ await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
+ expect(amountBefore).to.be.equal(1n);
+
+ await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+ const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
+ expect(amountAfter).to.be.equal(0n);
+ });
+
+ itSub('can`t be called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
+ const result = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});
+ await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+ });
+
+ describe(`[${testCase.method}] Normal user can approve other users to transfer:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('NFT', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
+ await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.true;
+ });
+
+ itSub('Fungible up to an approved amount', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, testCase.account(bob));
+ expect(amount).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});
+ await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);
+ const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, testCase.account(bob));
+ expect(amount).to.be.equal(100n);
+ });
+ });
+
+ describe(`[${testCase.method}] Approved users can transferFrom up to approved amount:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('NFT', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
+ await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});
+ const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('Fungible up to an approved amount', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+ await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
+ const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+ expect(after - before).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});
+ await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+ await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
+ const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+ expect(after - before).to.be.equal(1n);
+ });
+ });
+
+ describe(`[${testCase.method}] Approved users cannot use transferFrom to repeat transfers if approved amount was already transferred:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('NFT', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
+ await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});
+ const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner).to.be.deep.equal({Substrate: alice.address});
+ const transferTokenFromTx = () => helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});
+ await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+
+ itSub('Fungible up to an approved amount', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+ await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
+ const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+ expect(after - before).to.be.equal(1n);
+
+ const transferTokenFromTx = () => helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
+ await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+
+ itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});
+ await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);
+ const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+ await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);
+ const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+ expect(after - before).to.be.equal(100n);
+ const transferTokenFromTx = () => helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);
+ await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+ });
+
+ describe(`[${testCase.method}] Approved amount decreases by the transferred amount:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+ let dave: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('If a user B is approved to transfer 10 Fungible tokens from user A, they can transfer 2 tokens to user C, which will result in decreasing approval from 10 to 8. Then user B can transfer 8 tokens to user D.', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 10n);
+
+ const charlieBefore = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
+ await helper.ft.transferTokenFrom(bob, collectionId, tokenId, testCase.account(alice), {Substrate: charlie.address}, 2n);
+ const charlieAfter = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
+ expect(charlieAfter - charlieBefore).to.be.equal(2n);
+
+ const daveBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+ await helper.ft.transferTokenFrom(bob, collectionId, tokenId, testCase.account(alice), {Substrate: dave.address}, 8n);
+ const daveAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+ expect(daveAfter - daveBefore).to.be.equal(8n);
+ });
+ });
+
+ describe(`[${testCase.method}] User may clear the approvals to approving for 0 amount:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('NFT', async ({helper}) => {
+ const owner = testCase.account(alice);
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: owner});
+
+ await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
+
+ await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
+
+ const transferTokenFromTx = helper.nft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: bob.address});
+ await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+
+ itSub('Fungible', async ({helper}) => {
+ const owner = testCase.account(alice);
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, owner);
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
+ expect(amountBefore).to.be.equal(1n);
+
+ await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+ const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
+ expect(amountAfter).to.be.equal(0n);
+
+ const transferTokenFromTx = helper.ft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: charlie.address}, 1n);
+ await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+
+ itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {
+ const owner = testCase.account(alice);
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner, pieces: 100n});
+ await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
+ const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
+ expect(amountBefore).to.be.equal(1n);
+
+ await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+ const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
+ expect(amountAfter).to.be.equal(0n);
+
+ const transferTokenFromTx = helper.rft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: charlie.address}, 1n);
+ await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+ });
+
+ describe(`[${testCase.method}] User cannot approve for the amount greater than they own:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('1 for NFT', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
+ const result = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 2n);
+ await expect(result).to.be.rejectedWith('nonfungible.NonfungibleItemsHaveNoAmount');
+ expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;
+ });
+
+ itSub('Fungible', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ const result = (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 11n);
+ await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+
+ itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
+ const result = (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 101n);
+ await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+ });
+
+ describe(`[${testCase.method}] Integration Test approve(spender, collection_id, item_id, amount) with collection admin permissions:`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('cannot be called by collection admin on non-owned item', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
+ await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+ const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+ });
+
+ describe(`[${testCase.method}] Negative Integration Test approve(spender, collection_id, item_id, amount):`, () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+ const NONEXISTENT_COLLECTION = (2 ** 32) - 1;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('[nft] Approve for a collection that does not exist', async ({helper}) => {
+ const approveTx = (helper.nft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});
+ await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
+ });
+
+ itSub('[fungible] Approve for a collection that does not exist', async ({helper}) => {
+ const approveTx = (helper.ft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});
+ await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
+ });
+
+ itSub.ifWithPallets('[refungible] Approve for a collection that does not exist', [Pallets.ReFungible], async ({helper}) => {
+ const approveTx = (helper.rft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});
+ await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
+ });
+
+ itSub('[nft] Approve for a collection that was destroyed', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.nft.burn(alice, collectionId);
+ const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});
+ await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
+ });
+
+ itSub('[fungible] Approve for a collection that was destroyed', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.ft.burn(alice, collectionId);
+ const approveTx = (helper.ft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});
+ await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
+ });
+
+ itSub.ifWithPallets('[refungible] Approve for a collection that was destroyed', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.rft.burn(alice, collectionId);
+ const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});
+ await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
+ });
+
+ itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});
+ await expect(approveTx).to.be.rejectedWith('common.TokenNotFound');
+ });
+
+ itSub.ifWithPallets('[refungible] Approve transfer of a token that does not exist', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned'); // TODO: why the error is not common.TokenNotFound
+ });
+
+ itSub('[nft] Approve using the address that does not own the approved token', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
+ const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+
+ itSub('[fungible] Approve using the address that does not own the approved token', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+ const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+
+ itSub.ifWithPallets('[refungible] Approve using the address that does not own the approved token', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
+ const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+
+ itSub.ifWithPallets('should fail if approved more ReFungibles than owned', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+ await helper.rft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 100n);
+ await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 100n);
+
+ const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 101n);
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+
+ itSub('should fail if approved more Fungibles than owned', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.ft.mintTokens(alice, collectionId, 10n, alice.address);
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+
+ await helper.ft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 10n);
+ await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 10n);
+ const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 11n);
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+
+ itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
+ await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});
+
+ const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});
+ await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
+ });
+ });
+});
+
+describe('Normal user can approve other users to be wallet operator:', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('[nft] Enable and disable approval', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+
+ const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+ expect(checkBeforeApproval).to.be.false;
+
+ await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);
+ const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+ expect(checkAfterApproval).to.be.true;
+
+ await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);
+ const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+ expect(checkAfterDisapproval).to.be.false;
+ });
+
+ itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+
+ const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+ expect(checkBeforeApproval).to.be.false;
+
+ await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);
+ const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+ expect(checkAfterApproval).to.be.true;
+
+ await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);
+ const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+ expect(checkAfterDisapproval).to.be.false;
+ });
+});
+
+describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+ let dave: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('NFT', async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});
+
+ await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});
+ const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner1).to.be.deep.equal({Substrate: dave.address});
+
+ await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+ await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});
+ const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);
+ expect(owner2).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('Fungible up to an approved amount', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+ await helper.ft.mintTokens(alice, collectionId, 10n, charlie.address);
+ const tokenId = await helper.ft.getLastTokenId(collectionId);
+
+ const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+ await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);
+ const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+ expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(1n);
+
+ await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});
+
+ const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+ await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);
+ const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+ expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+ const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});
+
+ const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});
+ await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);
+ const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});
+ expect(daveAfter - daveBefore).to.be.equal(1n);
+
+ await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+
+ const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+ await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);
+ const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+ expect(aliceAfter - aliceBefore).to.be.equal(1n);
+ });
+});
+
+describe('Repeated approvals add up', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+ let dave: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {});
+ await collection.mint(alice, 10n);
+ await collection.approveTokens(alice, {Substrate: bob.address}, 1n);
+ await collection.approveTokens(alice, {Substrate: charlie.address}, 1n);
+ // const allowances1 = await getAllowance(collectionId, 0, Alice.address, Bob.address);
+ // const allowances2 = await getAllowance(collectionId, 0, Alice.address, Charlie.address);
+ // expect(allowances1 + allowances2).to.be.eq(2n);
+ });
+
+ itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. ReFungible', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice, 10n);
+ await token.approve(alice, {Substrate: bob.address}, 1n);
+ await token.approve(alice, {Substrate: charlie.address}, 1n);
+ // const allowances1 = await getAllowance(collectionId, itemId, Alice.address, Bob.address);
+ // const allowances2 = await getAllowance(collectionId, itemId, Alice.address, Charlie.address);
+ // expect(allowances1 + allowances2).to.be.eq(2n);
+ });
+
+ // Canceled by changing approve logic
+ itSub.skip('Cannot approve for more than total user\'s amount (owned: 10, approval 1: 5 - should succeed, approval 2: 6 - should fail). Fungible', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {});
+ await collection.mint(alice, 10n, {Substrate: dave.address});
+ await collection.approveTokens(dave, {Substrate: bob.address}, 5n);
+ await expect(collection.approveTokens(dave, {Substrate: charlie.address}, 6n))
+ .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');
+ });
+
+ // Canceled by changing approve logic
+ itSub.skip('Cannot approve for more than total user\'s amount (owned: 100, approval 1: 50 - should succeed, approval 2: 51 - should fail). ReFungible', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice, 100n, {Substrate: dave.address});
+ await token.approve(dave, {Substrate: bob.address}, 50n);
+ await expect(token.approve(dave, {Substrate: charlie.address}, 51n))
+ .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');
+ });
+});
js-packages/tests/burnItem.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/burnItem.test.ts
@@ -0,0 +1,165 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from './util/index.js';
+
+
+describe('integration test: ext. burnItem():', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ itSub('Burn item in NFT collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ const token = await collection.mintToken(alice);
+
+ await token.burn(alice);
+ expect(await token.doesExist()).to.be.false;
+ });
+
+ itSub('Burn item in Fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {}, 10);
+ await collection.mint(alice, 10n);
+
+ await collection.burnTokens(alice, 1n);
+ expect(await collection.getBalance({Substrate: alice.address})).to.eq(9n);
+ });
+});
+
+describe('integration test: ext. burnItem() with admin permissions:', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Burn item in NFT collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ const token = await collection.mintToken(alice);
+
+ await token.burnFrom(bob, {Substrate: alice.address});
+ expect(await token.doesExist()).to.be.false;
+ });
+
+ itSub('Burn item in Fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {}, 0);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await collection.mint(alice, 10n);
+
+ await collection.burnTokensFrom(bob, {Substrate: alice.address}, 1n);
+ expect(await collection.getBalance({Substrate: alice.address})).to.eq(9n);
+ });
+});
+
+describe('Negative integration test: ext. burnItem():', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Burn a token that was never created', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ await expect(collection.burnToken(alice, 10)).to.be.rejectedWith('common.TokenNotFound');
+ });
+
+ itSub('Burn a token using the address that does not own it', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ const token = await collection.mintToken(alice);
+
+ await expect(token.burn(bob)).to.be.rejectedWith('common.NoPermission');
+ });
+
+ itSub('Transfer a burned token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ const token = await collection.mintToken(alice);
+ await token.burn(alice);
+
+ await expect(token.transfer(alice, {Substrate: bob.address})).to.be.rejectedWith('common.TokenNotFound');
+ });
+
+ itSub('Burn more than owned in Fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {}, 0);
+ await collection.mint(alice, 10n);
+
+ await expect(collection.burnTokens(alice, 11n)).to.be.rejectedWith('common.TokenValueTooLow');
+ expect(await collection.getBalance({Substrate: alice.address})).to.eq(10n);
+ });
+
+ itSub('Zero burn NFT', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Coll', description: 'Desc', tokenPrefix: 'T'});
+ const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});
+ const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});
+
+ // 1. Zero burn of own tokens allowed:
+ await helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenAlice.tokenId, 0]);
+ // 2. Zero burn of non-owned tokens not allowed:
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');
+ // 3. Zero burn of non-existing tokens not allowed:
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, 9999, 0])).to.be.rejectedWith('common.TokenNotFound');
+ expect(await tokenAlice.doesExist()).to.be.true;
+ expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});
+ expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});
+ // 4. Storage is not corrupted:
+ await tokenAlice.transfer(alice, {Substrate: bob.address});
+ await tokenBob.transfer(bob, {Substrate: alice.address});
+ expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});
+ expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});
+ });
+
+ itSub('zero burnFrom NFT', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Zero', description: 'Zero transfer', tokenPrefix: 'TF'});
+ const notApprovedNft = await collection.mintToken(alice, {Substrate: bob.address});
+ const approvedNft = await collection.mintToken(alice, {Substrate: bob.address});
+ await approvedNft.approve(bob, {Substrate: alice.address});
+
+ // 1. Zero burnFrom of non-existing tokens not allowed:
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, 9999, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+ // 2. Zero burnFrom of not approved tokens not allowed:
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, notApprovedNft.tokenId, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+ // 3. Zero burnFrom of approved tokens allowed:
+ await helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, approvedNft.tokenId, 0]);
+
+ // 4.1 approvedNft still approved:
+ expect(await approvedNft.isApproved({Substrate: alice.address})).to.be.true;
+ // 4.2 bob is still the owner:
+ expect(await approvedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+ expect(await notApprovedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+ // 4.3 Alice can burn approved nft:
+ await approvedNft.burnFrom(alice, {Substrate: bob.address});
+ expect(await approvedNft.doesExist()).to.be.false;
+ });
+});
js-packages/tests/change-collection-owner.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/change-collection-owner.test.ts
@@ -0,0 +1,170 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test changeCollectionOwner(collection_id, new_owner):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Changing owner changes owner address', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const beforeChanging = await helper.collection.getData(collection.collectionId);
+ expect(beforeChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address));
+
+ await collection.changeOwner(alice, bob.address);
+ const afterChanging = await helper.collection.getData(collection.collectionId);
+ expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
+ });
+});
+
+describe('Integration Test changeCollectionOwner(collection_id, new_owner) special checks for exOwner:', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('Changing the owner of the collection is not allowed for the former owner', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+
+ await collection.changeOwner(alice, bob.address);
+
+ const changeOwnerTx = () => collection.changeOwner(alice, alice.address);
+ await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
+
+ const afterChanging = await helper.collection.getData(collection.collectionId);
+ expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
+ });
+
+ itSub('New collectionOwner has access to sponsorship management operations in the collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.changeOwner(alice, bob.address);
+
+ const afterChanging = await helper.collection.getData(collection.collectionId);
+ expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
+
+ await collection.setSponsor(bob, charlie.address);
+ await collection.confirmSponsorship(charlie);
+ await collection.removeSponsor(bob);
+ const limits = {
+ accountTokenOwnershipLimit: 1,
+ tokenLimit: 1,
+ sponsorTransferTimeout: 1,
+ ownerCanDestroy: true,
+ ownerCanTransfer: true,
+ };
+
+ await collection.setLimits(bob, limits);
+ const gotLimits = await collection.getEffectiveLimits();
+ expect(gotLimits).to.be.deep.contains(limits);
+
+ await collection.setPermissions(bob, {access: 'AllowList', mintMode: true});
+
+ await collection.burn(bob);
+ const collectionData = await helper.collection.getData(collection.collectionId);
+ expect(collectionData).to.be.null;
+ });
+
+ itSub('New collectionOwner has access to changeCollectionOwner', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.changeOwner(alice, bob.address);
+ await collection.changeOwner(bob, charlie.address);
+ const collectionData = await collection.getData();
+ expect(collectionData?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(charlie.address));
+ });
+});
+
+describe('Negative Integration Test changeCollectionOwner(collection_id, new_owner):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('Not owner can\'t change owner.', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const changeOwnerTx = () => collection.changeOwner(bob, bob.address);
+ await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Collection admin can\'t change owner.', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ const changeOwnerTx = () => collection.changeOwner(bob, bob.address);
+ await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Can\'t change owner of a non-existing collection.', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ const changeOwnerTx = () => helper.collection.changeOwner(bob, collectionId, bob.address);
+ await expect(changeOwnerTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Former collectionOwner not allowed to sponsorship management operations in the collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.changeOwner(alice, bob.address);
+
+ const changeOwnerTx = () => collection.changeOwner(alice, alice.address);
+ await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
+
+ const afterChanging = await helper.collection.getData(collection.collectionId);
+ expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
+
+ const setSponsorTx = () => collection.setSponsor(alice, charlie.address);
+ const confirmSponsorshipTx = () => collection.confirmSponsorship(alice);
+ const removeSponsorTx = () => collection.removeSponsor(alice);
+ await expect(setSponsorTx()).to.be.rejectedWith(/common\.NoPermission/);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ await expect(removeSponsorTx()).to.be.rejectedWith(/common\.NoPermission/);
+
+ const limits = {
+ accountTokenOwnershipLimit: 1,
+ tokenLimit: 1,
+ sponsorTransferTimeout: 1,
+ ownerCanDestroy: true,
+ ownerCanTransfer: true,
+ };
+
+ const setLimitsTx = () => collection.setLimits(alice, limits);
+ await expect(setLimitsTx()).to.be.rejectedWith(/common\.NoPermission/);
+
+ const setPermissionTx = () => collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
+ await expect(setPermissionTx()).to.be.rejectedWith(/common\.NoPermission/);
+
+ const burnTx = () => collection.burn(alice);
+ await expect(burnTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+});
js-packages/tests/check-event/burnItemEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/burnItemEvent.test.ts
@@ -0,0 +1,44 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+
+describe('Burn Item event ', () => {
+ let alice: IKeyringPair;
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+ itSub('Check event from burnItem(): ', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ await token.burn(alice);
+ await helper.wait.newBlocks(1);
+
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.ItemDestroyed');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/check-event/createCollectionEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/createCollectionEvent.test.ts
@@ -0,0 +1,40 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Create collection event ', () => {
+ let alice: IKeyringPair;
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+ itSub('Check event from createCollection(): ', async ({helper}) => {
+ await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ await helper.wait.newBlocks(1);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.CollectionCreated');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/check-event/createItemEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/createItemEvent.test.ts
@@ -0,0 +1,41 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Create Item event ', () => {
+ let alice: IKeyringPair;
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+ itSub('Check event from createItem(): ', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ await collection.mintToken(alice, {Substrate: alice.address});
+ await helper.wait.newBlocks(1);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.ItemCreated');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/check-event/createMultipleItemsEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/createMultipleItemsEvent.test.ts
@@ -0,0 +1,46 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Create Multiple Items Event event ', () => {
+ let alice: IKeyringPair;
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+ itSub('Check event from createMultipleItems(): ', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ await collection.mintMultipleTokens(alice, [
+ {owner: {Substrate: alice.address}},
+ {owner: {Substrate: alice.address}},
+ ]);
+
+ await helper.wait.newBlocks(1);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.ItemCreated');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/check-event/destroyCollectionEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/destroyCollectionEvent.test.ts
@@ -0,0 +1,42 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Destroy collection event ', () => {
+ let alice: IKeyringPair;
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itSub('Check event from destroyCollection(): ', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ await collection.burn(alice);
+ await helper.wait.newBlocks(1);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.CollectionDestroyed');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/check-event/transferEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/transferEvent.test.ts
@@ -0,0 +1,45 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Transfer event ', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+ });
+ });
+
+ itSub('Check event from transfer(): ', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ await token.transfer(alice, {Substrate: bob.address});
+ await helper.wait.newBlocks(1);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.Transfer');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/check-event/transferFromEvent.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/check-event/transferFromEvent.test.ts
@@ -0,0 +1,44 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from '../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Transfer event ', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+ });
+ });
+
+ itSub('Check event from transfer(): ', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});
+ await helper.wait.newBlocks(1);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contains('common.Transfer');
+ expect(eventStrings).to.contains('treasury.Deposit');
+ expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+ });
+});
js-packages/tests/collator-selection/collatorSelection.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/collator-selection/collatorSelection.seqtest.ts
@@ -0,0 +1,423 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util/index.js';
+
+async function nodeAddress(name: string) {
+ // eslint-disable-next-line require-await
+ return await usingPlaygrounds(async (helper) => {
+ const envNodeStash = `RELAY_UNIQUE_NODE_${name.toUpperCase()}_STASH`;
+
+ const nodeStash = process.env[envNodeStash];
+ if(nodeStash) {
+ return helper.address.normalizeSubstrateToChainFormat(nodeStash);
+ } else {
+ throw Error(`"${envNodeStash}" env var is not set`);
+ }
+ });
+}
+
+async function getInitialInvulnerables() {
+ return await Promise.all([
+ nodeAddress('alpha'),
+ nodeAddress('beta'),
+ nodeAddress('gamma'),
+ nodeAddress('delta'),
+ ]);
+}
+
+async function resetInvulnerables() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const superuser = await privateKey('//Alice');
+ const initialInvulnerables = await getInitialInvulnerables();
+
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+ // Remove all invulnerables but the first one
+ const firstInvulnerable = invulnerables[0];
+
+ let nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(invulnerables.slice(1).map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++})));
+
+ // Add the initial invulnerables
+ await Promise.all(initialInvulnerables.map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [invulnerable], true, {nonce: nonce++})));
+
+ // Remove the first invulnerable if it's not an initial one
+ if(!initialInvulnerables.includes(firstInvulnerable)) {
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [firstInvulnerable]);
+ }
+ });
+}
+
+// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).
+describe('Integration Test: Collator Selection', () => {
+ let superuser: IKeyringPair;
+ let previousLicenseBond = 0n;
+ let licenseBond = 0n;
+
+ before(async function() {
+ if(!process.env.RUN_COLLATOR_TESTS) this.skip();
+
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);
+ superuser = await privateKey('//Alice');
+
+ previousLicenseBond = await helper.collatorSelection.getLicenseBond();
+ licenseBond = 10n * helper.balance.getOneTokenNominal();
+ await helper.getSudo().collatorSelection.setLicenseBond(superuser, licenseBond);
+ });
+ });
+
+ describe('Dynamic shuffling of collators', () => {
+ // These two are the default invulnerables, and should return to be invulnerables after this suite.
+ let alphaNode: string;
+ let betaNode: string;
+
+ let gammaNode: string;
+ let deltaNode: string;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper) => {
+ // todo:collator see again if blocks start to be finalized in dev mode
+ // Skip the collator block production in dev mode, since the blocks are sealed automatically.
+ if(await helper.arrange.isDevNode()) this.skip();
+
+ [alphaNode, betaNode, gammaNode, deltaNode] = await getInitialInvulnerables();
+
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(invulnerables.length, 'Invalid initial invulnerables number').to.be.equal(4);
+ expect(invulnerables, 'Invalid initial invulnerables').containSubset([alphaNode, betaNode, gammaNode, deltaNode]);
+ });
+ });
+
+ itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {
+ let nonce = await helper.chain.getNonce(superuser.address);
+
+ nonce = await helper.chain.getNonce(superuser.address);
+ await expect(Promise.all([
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alphaNode], true, {nonce: nonce++}),
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [betaNode], true, {nonce: nonce++}),
+ ])).to.be.fulfilled;
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
+
+ await helper.wait.newSessions(2);
+
+ const newValidators = await helper.callRpc('api.query.session.validators');
+ expect(newValidators).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
+
+ const lastBlockNumber = await helper.chain.getLatestBlockNumber();
+ await helper.wait.newBlocks(1);
+ const lastGammaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [gammaNode])).toNumber();
+ const lastDeltaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [deltaNode])).toNumber();
+ expect(lastGammaBlock >= lastBlockNumber || lastDeltaBlock >= lastBlockNumber).to.be.true;
+ });
+
+ after(async () => {
+ await resetInvulnerables();
+ });
+ });
+
+ describe('Getting and releasing licenses to collate', () => {
+ let crowd: IKeyringPair[];
+
+ before(async function() {
+ await usingPlaygrounds(async (helper) => {
+ crowd = await helper.arrange.createCrowd(20, 100n, superuser);
+
+ // set session keys for everyone
+ await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
+ });
+ });
+
+ describe('Positive', () => {
+ itSub('Can lease and release a license', async ({helper}) => {
+ const account = crowd.pop()!;
+
+ // make sure it does not have any reserved funds
+ expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(0n);
+
+ // getting a license reserves a license bond cost
+ await helper.collatorSelection.obtainLicense(account);
+ expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
+ expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(licenseBond);
+
+ // releasing a license un-reserves the license bond cost
+ await helper.collatorSelection.releaseLicense(account);
+ expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
+
+ const balance = await helper.balance.getSubstrateFull(account.address);
+ expect(balance.reserved).to.be.equal(0n);
+ expect(balance.free > 100n - licenseBond);
+ });
+
+ itSub('Can force revoke a license', async ({helper}) => {
+ const account = crowd.pop()!;
+
+ // getting a license reserves a license bond cost
+ const previousBalance = await helper.balance.getSubstrateFull(account.address);
+ await helper.collatorSelection.obtainLicense(account);
+ expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
+
+ // force-releasing a license un-reserves the license bond cost as well
+ await helper.getSudo().collatorSelection.forceReleaseLicense(superuser, account.address);
+ expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(previousBalance.reserved);
+
+ const balance = await helper.balance.getSubstrateFull(account.address);
+ expect(balance.reserved).to.be.equal(previousBalance.reserved);
+ expect(balance.free > previousBalance.free - licenseBond);
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('Cannot get a license without session keys set', async ({helper}) => {
+ const [account] = await helper.arrange.createAccounts([100n], superuser);
+ await expect(helper.collatorSelection.obtainLicense(account))
+ .to.be.rejectedWith(/collatorSelection.ValidatorNotRegistered/);
+ });
+
+ itSub('Cannot register a license twice', async ({helper}) => {
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await expect(helper.collatorSelection.obtainLicense(account))
+ .to.be.rejectedWith(/collatorSelection.AlreadyHoldingLicense/);
+ });
+
+ itSub('Cannot release a license twice', async ({helper}) => {
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await helper.collatorSelection.releaseLicense(account);
+ await expect(helper.collatorSelection.releaseLicense(account))
+ .to.be.rejectedWith(/collatorSelection.NoLicense/);
+ });
+
+ itSub('Cannot force revoke a license as non-sudo', async ({helper}) => {
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await expect(helper.collatorSelection.forceReleaseLicense(superuser, account.address))
+ .to.be.rejectedWith(/BadOrigin/);
+ });
+ });
+ });
+
+ describe('Onboarding, collating, and offboarding as collator candidates', () => {
+ let crowd: IKeyringPair[];
+
+ before(async function() {
+ await usingPlaygrounds(async (helper) => {
+ crowd = await helper.arrange.createCrowd(20, 100n, superuser);
+
+ // set session keys for everyone
+ await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
+ });
+ });
+
+ describe('Positive', () => {
+ itSub('Can onboard and offboard repeatedly', async ({helper}) => {
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await helper.collatorSelection.onboard(account);
+ expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
+
+ await helper.collatorSelection.offboard(account);
+ expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
+
+ await helper.collatorSelection.onboard(account);
+ expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
+
+ await helper.collatorSelection.offboard(account);
+ expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
+ });
+
+ itSub('Penalizes and forfeits license from faulty collators', async ({helper}) => {
+ // This one shouldn't even be able to produce blocks.
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await helper.collatorSelection.onboard(account);
+ expect(await helper.collatorSelection.getCandidates()).to.contain(account.address);
+
+ // Wait for 3 new sessions before checking that the collator will be kicked:
+ // one to get collator onboarded, and another two for the collator to fail
+ await helper.wait.newSessions(3);
+
+ expect(await helper.collatorSelection.getCandidates()).to.not.contain(account.address);
+ expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
+
+ // The account's reserved funds get slashed as a penalty
+ const balance = await helper.balance.getSubstrateFull(account.address);
+ expect(balance.reserved).to.be.equal(0n);
+ expect(balance.free < 100n - licenseBond);
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('Cannot onboard without a license', async ({helper}) => {
+ const account = crowd.pop()!;
+ await expect(helper.collatorSelection.onboard(account))
+ .to.be.rejectedWith(/collatorSelection.NoLicense/);
+ });
+
+ itSub('Cannot offboard without a license', async ({helper}) => {
+ const account = crowd.pop()!;
+ await expect(helper.collatorSelection.offboard(account))
+ .to.be.rejectedWith(/collatorSelection.NotCandidate/);
+ });
+
+ itSub('Cannot offboard while not onboarded', async ({helper}) => {
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await expect(helper.collatorSelection.offboard(account))
+ .to.be.rejectedWith(/collatorSelection.NotCandidate/);
+ });
+
+ itSub('Cannot onboard while already onboarded', async ({helper}) => {
+ const account = crowd.pop()!;
+ await helper.collatorSelection.obtainLicense(account);
+ await helper.collatorSelection.onboard(account);
+ await expect(helper.collatorSelection.onboard(account))
+ .to.be.rejectedWith(/collatorSelection.AlreadyCandidate/);
+ });
+ });
+ });
+
+ describe('Addition and removal of invulnerables', () => {
+ describe('Positive', () => {
+ itSub('Adds an invulnerable', async ({helper}) => {
+ const [account] = await helper.arrange.createAccounts([10n], superuser);
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+ await helper.session.setOwnKeysFromAddress(account);
+ await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);
+ });
+
+ itSub('Removes an invulnerable', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ const lastInvulnerable = invulnerables.pop()!;
+
+ await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ // invulnerables had its last element removed, so they should be equal
+ expect(newInvulnerables).to.have.all.members(invulnerables);
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('Does not duplicate an invulnerable', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ // adding an already invulnerable should not fail, but should not duplicate it either
+ await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))
+ .to.be.fulfilled;
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.have.all.members(invulnerables);
+ });
+
+ itSub('Cannot remove a non-existent invulnerable', async ({helper}) => {
+ const [account] = await helper.arrange.createAccounts([0n], superuser);
+ await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, account.address))
+ .to.be.rejectedWith(/collatorSelection.NotInvulnerable/);
+ });
+
+ itSub('Cannot allow invulnerables to be empty', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ const lastInvulnerable = invulnerables.pop()!;
+
+ let nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(invulnerables.map((i: any) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));
+
+ await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))
+ .to.be.rejectedWith(/collatorSelection.TooFewInvulnerables/);
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);
+
+ // restore the invulnerables to the previous state
+ nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(invulnerables.map((i: any) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));
+ });
+
+ itSub('Cannot have too many invulnerables', async ({helper}) => {
+ // todo:collator make sure that there is enough session time for a set of tests
+ // 28 non-functioning collators, teehee.
+
+ const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
+ const invulnerablesUntilLimit = (await helper.collatorSelection.getDesiredCollators()) - invulnerablesLength;
+ const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
+ const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
+
+ await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+ helper.session.setOwnKeysFromAddress(i)));
+ await helper.session.setOwnKeysFromAddress(lastInvulnerable);
+
+ let nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));
+
+ await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))
+ .to.be.rejectedWith(/collatorSelection.TooManyInvulnerables/);
+
+ // restore the invulnerables to the previous state
+ nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));
+ });
+
+ itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {
+ const [account] = await helper.arrange.createAccounts([10n], superuser);
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+ await helper.session.setOwnKeysFromAddress(account);
+ await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))
+ .to.be.rejectedWith(/BadOrigin/);
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.be.members(invulnerables);
+ });
+
+ itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))
+ .to.be.rejectedWith(/BadOrigin/);
+ expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
+ });
+
+ after(async function() {
+ await resetInvulnerables();
+ });
+ });
+ });
+
+ after(async function() {
+ if(!process.env.RUN_COLLATOR_TESTS) return;
+
+ await usingPlaygrounds(async (helper) => {
+ if(helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;
+
+ await helper.getSudo().collatorSelection.setLicenseBond(superuser, previousLicenseBond);
+
+ const candidates = await helper.collatorSelection.getCandidates();
+ let nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(candidates.map(candidate =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.forceReleaseLicense', [candidate], true, {nonce: nonce++})));
+ });
+ });
+});
js-packages/tests/collator-selection/identity.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/collator-selection/identity.seqtest.ts
@@ -0,0 +1,284 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+
+async function getIdentities(helper: UniqueHelper) {
+ const identities: [string, any][] = [];
+ for(const [key, value] of await helper.getApi().query.identity.identityOf.entries())
+ identities.push([(key as any).toHuman(), (value as any).unwrap()]);
+ return identities;
+}
+
+async function getIdentityAccounts(helper: UniqueHelper) {
+ return (await getIdentities(helper)).flatMap(([key, _value]) => key);
+}
+
+async function getSubIdentityAccounts(helper: UniqueHelper, address: string) {
+ return ((await helper.getApi().query.identity.subsOf(address)).toHuman() as any)[1];
+}
+
+async function getSubIdentityName(helper: UniqueHelper, address: string) {
+ return ((await helper.getApi().query.identity.superOf(address)).toHuman() as any);
+}
+
+describe('Integration Test: Identities Manipulation', () => {
+ let superuser: IKeyringPair;
+
+ before(async function() {
+ if(!process.env.RUN_COLLATOR_TESTS) this.skip();
+
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Identity]);
+ superuser = await privateKey('//Alice');
+ });
+ });
+
+ itSub('Normal calls do not work', async ({helper}) => {
+ // console.error = () => {};
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.identity.setIdentity', [{info: {display: {Raw: 'Meowser'}}}] as any))
+ .to.be.rejectedWith(/Transaction call is not expected/);
+ });
+
+ describe('Identities', () => {
+ itSub('Sets identities', async ({helper}) => {
+ const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
+
+ const crowdSize = 10;
+ const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+ const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+
+ expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + crowdSize);
+ });
+
+ itSub('Setting identities does not delete existing but does overwrite', async ({helper}) => {
+ const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
+ const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
+
+ // insert a single identity
+ let singleIdentity = identities.pop()!;
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [[singleIdentity]] as any);
+
+ const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
+
+ // change an identity and push it with a few new others
+ singleIdentity = [singleIdentity[0], {info: {display: {Raw: 'something special'}}}];
+ identities.push(singleIdentity);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+
+ // oldIdentitiesCount + 9 because one identity is overwritten, not inserted on top
+ expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + 9);
+ expect((await helper.callRpc('api.query.identity.identityOf', [singleIdentity[0]])).toHuman().info.display)
+ .to.be.deep.equal({Raw: 'something special'});
+ });
+
+ itSub('Removes identities', async ({helper}) => {
+ const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
+ const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+ const oldIdentities = await getIdentityAccounts(helper);
+
+ // delete a couple, check that they are no longer there
+ const scapegoats = [crowd.pop()!.address, crowd.pop()!.address];
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [scapegoats]);
+ const newIdentities = await getIdentityAccounts(helper);
+ expect(newIdentities.concat(scapegoats)).to.be.have.members(oldIdentities);
+ });
+ });
+
+ describe('Sub-identities', () => {
+ itSub('Sets subs', async ({helper}) => {
+ const crowdSize = 18;
+ const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+ const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
+
+ const subsPerSup = crowd.length / supers.length;
+ let subCount = 0;
+ const subs = [
+ crowd.slice(subCount, subCount += subsPerSup + 1),
+ crowd.slice(subCount, subCount += subsPerSup),
+ crowd.slice(subCount, subCount += subsPerSup - 1),
+ ];
+
+ const subsInfo = supers.map((acc, i) => [
+ acc.address, [
+ 1000000n + BigInt(i + 1),
+ subs[i].map((sub, j) => [
+ sub.address, {Raw: `accounter #${j}`},
+ ]),
+ ],
+ ]);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
+
+ for(let i = 0; i < supers.length; i++) {
+ // check deposit
+ expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
+
+ const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
+ // check sub-identities as account ids
+ expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
+
+ for(let j = 0; j < subsAccounts.length; j++) {
+ // check sub-identities' names
+ expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
+ }
+ }
+ });
+
+ itSub('Setting sub-identities does not delete other existing but does overwrite own', async ({helper}) => {
+ const crowdSize = 18;
+ const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+ const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
+
+ const subsPerSup = crowd.length / supers.length;
+ let subCount = 0;
+ const subs = [
+ crowd.slice(subCount, subCount += subsPerSup + 1),
+ crowd.slice(subCount, subCount += subsPerSup),
+ crowd.slice(subCount, subCount += subsPerSup - 1),
+ ];
+
+ const subsInfo1 = supers.map((acc, i) => [
+ acc.address, [
+ 1000000n + BigInt(i + 1),
+ subs[i].map((sub, j) => [
+ sub.address, {Raw: `accounter #${j}`},
+ ]),
+ ],
+ ]);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
+
+ // change some sub-identities...
+ subs[2].pop(); subs[2].pop(); subs[2].push(...await helper.arrange.createAccounts([0n], superuser));
+
+ // ...and set them
+ const subsInfo2 = [[
+ supers[2].address, [
+ 999999n,
+ subs[2].map((sub, j) => [
+ sub.address, {Raw: `discounter #${j}`},
+ ]),
+ ],
+ ]];
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
+
+ // make sure everything else is the same
+ for(let i = 0; i < supers.length - 1; i++) {
+ // check deposit
+ expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
+
+ const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
+ // check sub-identities as account ids
+ expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
+
+ for(let j = 0; j < subsAccounts; j++) {
+ // check sub-identities' names
+ expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
+ }
+ }
+
+ // check deposit
+ expect(((await helper.getApi().query.identity.subsOf(supers[2].address)).toJSON() as any)[0]).to.be.equal(999999);
+
+ const subsAccounts = await getSubIdentityAccounts(helper, supers[2].address);
+ // check sub-identities as account ids
+ expect(subsAccounts).to.include.members(subs[2].map(x => x.address));
+
+ for(let j = 0; j < subsAccounts.length; j++) {
+ // check sub-identities' names
+ expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `discounter #${j}`});
+ }
+ });
+
+ itSub('Removes sub-identities', async ({helper}) => {
+ const crowdSize = 3;
+ const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+ const sup = crowd.pop()!;
+
+ const subsInfo1 = [[
+ sup.address, [
+ 1000000n,
+ crowd.map((sub, j) => [
+ sub.address, {Raw: `accounter #${j}`},
+ ]),
+ ],
+ ]];
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
+
+ // empty sub-identities should delete the records
+ const subsInfo2 = [[
+ sup.address, [
+ 1000000n,
+ [],
+ ],
+ ]];
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
+
+ // check deposit
+ expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
+
+ for(let j = 0; j < crowd.length; j++) {
+ // check sub-identities' names
+ expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
+ }
+ });
+
+ itSub('Removing identities deletes associated sub-identities', async ({helper}) => {
+ const crowd = await helper.arrange.createCrowd(3, 0n, superuser);
+ const sup = crowd.pop()!;
+
+ // insert identity
+ const identities = [[sup.address, {info: {display: {Raw: 'mental'}}}]];
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+
+ // and its sub-identities
+ const subsInfo = [[
+ sup.address, [
+ 1000000n,
+ crowd.map((sub, j) => [
+ sub.address, {Raw: `accounter #${j}`},
+ ]),
+ ],
+ ]];
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
+
+ // delete top identity
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [[sup.address]]);
+
+ // check that sub-identities are deleted
+ expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
+
+ for(let j = 0; j < crowd.length; j++) {
+ // check sub-identities' names
+ expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
+ }
+ });
+ });
+
+ after(async function() {
+ if(!process.env.RUN_COLLATOR_TESTS) return;
+
+ await usingPlaygrounds(async helper => {
+ if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) return;
+
+ const identitiesToRemove: string[] = await getIdentityAccounts(helper);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [identitiesToRemove]);
+ });
+ });
+});
js-packages/tests/config.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/config.ts
@@ -0,0 +1,34 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import process from 'process';
+
+const config = {
+ relayUrl: process.env.RELAY_URL || 'ws://127.0.0.1:9844',
+ substrateUrl: process.env.RELAY_OPAL_URL || process.env.RELAY_QUARTZ_URL || process.env.RELAY_UNIQUE_URL || process.env.RELAY_SAPPHIRE_URL || 'ws://127.0.0.1:9944',
+ acalaUrl: process.env.RELAY_ACALA_URL || 'ws://127.0.0.1:9946',
+ karuraUrl: process.env.RELAY_KARURA_URL || 'ws://127.0.0.1:9946',
+ moonbeamUrl: process.env.RELAY_MOONBEAM_URL || 'ws://127.0.0.1:9947',
+ moonriverUrl: process.env.RELAY_MOONRIVER_URL || 'ws://127.0.0.1:9947',
+ astarUrl: process.env.RELAY_ASTAR_URL || 'ws://127.0.0.1:9949',
+ shidenUrl: process.env.RELAY_SHIDEN_URL || 'ws://127.0.0.1:9949',
+ westmintUrl: process.env.RELAY_WESTMINT_URL || 'ws://127.0.0.1:9948',
+ statemineUrl: process.env.RELAY_STATEMINE_URL || 'ws://127.0.0.1:9948',
+ statemintUrl: process.env.RELAY_STATEMINT_URL || 'ws://127.0.0.1:9948',
+ polkadexUrl: process.env.RELAY_POLKADEX_URL || 'ws://127.0.0.1:9950',
+};
+
+export default config;
js-packages/tests/confirmSponsorship.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/confirmSponsorship.test.ts
@@ -0,0 +1,253 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+async function setSponsorHelper(collection: any, signer: IKeyringPair, sponsorAddress: string) {
+ await collection.setSponsor(signer, sponsorAddress);
+ const raw = (await collection.getData())?.raw;
+ expect(raw.sponsorship.Unconfirmed).to.be.equal(sponsorAddress);
+}
+
+async function confirmSponsorHelper(collection: any, signer: IKeyringPair) {
+ await collection.confirmSponsorship(signer);
+ const raw = (await collection.getData())?.raw;
+ expect(raw.sponsorship.Confirmed).to.be.equal(signer.address);
+}
+
+describe('integration test: ext. confirmSponsorship():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+ let zeroBalance: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie, zeroBalance] = await helper.arrange.createAccounts([100n, 100n, 100n, 0n], donor);
+ });
+ });
+
+ itSub('Confirm collection sponsorship', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await setSponsorHelper(collection, alice, bob.address);
+ await confirmSponsorHelper(collection, bob);
+ });
+
+ itSub('Add sponsor to a collection after the same sponsor was already added and confirmed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await setSponsorHelper(collection, alice, bob.address);
+ await confirmSponsorHelper(collection, bob);
+ await setSponsorHelper(collection, alice, bob.address);
+ });
+ itSub('Add new sponsor to a collection after another sponsor was already added and confirmed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await setSponsorHelper(collection, alice, bob.address);
+ await confirmSponsorHelper(collection, bob);
+ await setSponsorHelper(collection, alice, charlie.address);
+ });
+
+ itSub('NFT: Transfer fees are paid by the sponsor after confirmation', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ const token = await collection.mintToken(alice, {Substrate: zeroBalance.address});
+ await token.transfer(zeroBalance, {Substrate: alice.address});
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+ expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
+ });
+
+ itSub('Fungible: Transfer fees are paid by the sponsor after confirmation', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ await collection.mint(alice, 100n, {Substrate: zeroBalance.address});
+ await collection.transfer(zeroBalance, {Substrate: alice.address}, 1n);
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+ expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
+ });
+
+ itSub.ifWithPallets('ReFungible: Transfer fees are paid by the sponsor after confirmation', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ const token = await collection.mintToken(alice, 100n, {Substrate: zeroBalance.address});
+ await token.transfer(zeroBalance, {Substrate: alice.address}, 1n);
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+ expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
+ });
+
+ itSub('CreateItem fees are paid by the sponsor after confirmation', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ await collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
+ await collection.addToAllowList(alice, {Substrate: zeroBalance.address});
+
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ await collection.mintToken(zeroBalance, {Substrate: zeroBalance.address});
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
+ });
+
+ itSub('NFT: Sponsoring of transfers is rate limited', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
+ sponsorTransferTimeout: 1000,
+ }});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ await token.transfer(alice, {Substrate: zeroBalance.address});
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ const transferTx = () => token.transfer(zeroBalance, {Substrate: alice.address});
+ await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees');
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
+ });
+
+ itSub('Fungible: Sponsoring is rate limited', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
+ sponsorTransferTimeout: 1000,
+ }});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+
+ await collection.mint(alice, 100n, {Substrate: zeroBalance.address});
+ await collection.transfer(zeroBalance, {Substrate: zeroBalance.address}, 1n);
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ const transferTx = () => collection.transfer(zeroBalance, {Substrate: zeroBalance.address});
+ await expect(transferTx()).to.be.rejected;
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
+ });
+
+ itSub.ifWithPallets('ReFungible: Sponsoring is rate limited', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
+ sponsorTransferTimeout: 1000,
+ }});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+
+ const token = await collection.mintToken(alice, 100n, {Substrate: zeroBalance.address});
+ await token.transfer(zeroBalance, {Substrate: alice.address});
+
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ const transferTx = () => token.transfer(zeroBalance, {Substrate: alice.address});
+ await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees');
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
+ });
+
+ itSub('NFT: Sponsoring of createItem is rate limited', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
+ sponsoredDataRateLimit: {blocks: 1000},
+ sponsorTransferTimeout: 1000,
+ }});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ await collection.setPermissions(alice, {mintMode: true, access: 'AllowList'});
+ await collection.addToAllowList(alice, {Substrate: zeroBalance.address});
+
+ await collection.mintToken(zeroBalance, {Substrate: zeroBalance.address});
+
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ const mintTx = () => collection.mintToken(zeroBalance, {Substrate: zeroBalance.address});
+ await expect(mintTx()).to.be.rejectedWith('Inability to pay some fees');
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
+ });
+});
+
+describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+ let ownerZeroBalance: IKeyringPair;
+ let senderZeroBalance: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie, ownerZeroBalance, senderZeroBalance] = await helper.arrange.createAccounts([100n, 100n, 100n, 0n, 0n], donor);
+ });
+ });
+
+ itSub('(!negative test!) Confirm sponsorship for a collection that never existed', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ const confirmSponsorshipTx = () => helper.collection.confirmSponsorship(bob, collectionId);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('(!negative test!) Confirm sponsorship using a non-sponsor address', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ });
+
+ itSub('(!negative test!) Confirm sponsorship using owner address', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ const confirmSponsorshipTx = () => collection.confirmSponsorship(alice);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ });
+
+ itSub('(!negative test!) Confirm sponsorship by collection admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.addAdmin(alice, {Substrate: charlie.address});
+ const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ });
+
+ itSub('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ });
+
+ itSub('(!negative test!) Confirm sponsorship in a collection that was destroyed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.burn(alice);
+ const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
+ await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ const token = await collection.mintToken(alice, {Substrate: ownerZeroBalance.address});
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ const transferTx = () => token.transfer(senderZeroBalance, {Substrate: alice.address});
+ await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees');
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(bob.address);
+ expect(sponsorBalanceAfter).to.equal(sponsorBalanceBefore);
+ });
+});
js-packages/tests/connection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/connection.test.ts
@@ -0,0 +1,32 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itSub, expect, usingPlaygrounds} from './util/index.js';
+
+describe('Connection smoke test', () => {
+ itSub('Connection can be established', async ({helper}) => {
+ const health = (await helper.callRpc('api.rpc.system.health')).toJSON();
+ expect(health).to.be.not.empty;
+ });
+
+ it('Cannot connect to 255.255.255.255', async () => {
+ await expect((async () => {
+ await usingPlaygrounds(async helper => {
+ await helper.callRpc('api.rpc.system.health');
+ }, 'ws://255.255.255.255:9944');
+ })()).to.be.eventually.rejected;
+ });
+});
js-packages/tests/createCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/createCollection.test.ts
@@ -0,0 +1,194 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets} from './util/index.js';
+import {CollectionFlag} from '@unique/playgrounds/types.js';
+import type {ICollectionCreationOptions, IProperty} from '@unique/playgrounds/types.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+
+async function mintCollectionHelper(helper: UniqueHelper, signer: IKeyringPair, options: ICollectionCreationOptions, type?: 'nft' | 'fungible' | 'refungible') {
+ let collection;
+ if(type === 'nft') {
+ collection = await helper.nft.mintCollection(signer, options);
+ } else if(type === 'fungible') {
+ collection = await helper.ft.mintCollection(signer, options, 0);
+ } else {
+ collection = await helper.rft.mintCollection(signer, options);
+ }
+ const data = await collection.getData();
+ expect(data?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(signer.address));
+ expect(data?.name).to.be.equal(options.name);
+ expect(data?.description).to.be.equal(options.description);
+ expect(data?.raw.tokenPrefix).to.be.equal(options.tokenPrefix);
+ if(options.properties) {
+ expect(data?.raw.properties).to.be.deep.equal(options.properties);
+ }
+ if(options.adminList) {
+ expect(data?.admins).to.be.deep.equal(options.adminList);
+ }
+
+ if(options.flags) {
+ if((options.flags[0] & 64) != 0)
+ expect(data?.raw.flags.erc721metadata).to.be.true;
+ if((options.flags[0] & 128) != 0)
+ expect(data?.raw.flags.foreign).to.be.false;
+ }
+
+ if(options.tokenPropertyPermissions) {
+ expect(data?.raw.tokenPropertyPermissions).to.be.deep.equal(options.tokenPropertyPermissions);
+ }
+
+ return collection;
+}
+
+describe('integration test: ext. createCollection():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+ itSub('Create new NFT collection', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 'nft');
+ });
+ itSub('Create new NFT collection whith collection_name of maximum length (64 bytes)', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {name: 'A'.repeat(64), description: 'descr', tokenPrefix: 'COL'}, 'nft');
+ });
+ itSub('Create new NFT collection whith collection_description of maximum length (256 bytes)', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {name: 'name', description: 'A'.repeat(256), tokenPrefix: 'COL'}, 'nft');
+ });
+ itSub('Create new NFT collection whith token_prefix of maximum length (16 bytes)', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(16)}, 'nft');
+ });
+
+ itSub('Create new Fungible collection', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'fungible');
+ });
+
+ itSub.ifWithPallets('Create new ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'refungible');
+ });
+
+ itSub('create new collection with properties', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {
+ name: 'name', description: 'descr', tokenPrefix: 'COL',
+ properties: [{key: 'key1', value: 'val1'}],
+ tokenPropertyPermissions: [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}],
+ }, 'nft');
+ });
+
+ itSub('create new collection with admin', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {
+ name: 'name', description: 'descr', tokenPrefix: 'COL',
+ adminList: [{Substrate: bob.address}],
+ }, 'nft');
+ });
+
+ itSub('create new collection with flags', async ({helper}) => {
+ await mintCollectionHelper(helper, alice, {
+ name: 'name', description: 'descr', tokenPrefix: 'COL',
+ flags: [CollectionFlag.Erc721metadata],
+ }, 'nft');
+
+ // User can not set Foreign flag itself
+
+ await expect(mintCollectionHelper(helper, alice, {
+ name: 'name', description: 'descr', tokenPrefix: 'COL',
+ flags: [CollectionFlag.Foreign],
+ }, 'nft')).to.be.rejectedWith(/common.NoPermission/);
+
+ await expect(mintCollectionHelper(helper, alice, {
+ name: 'name', description: 'descr', tokenPrefix: 'COL',
+ flags: [CollectionFlag.Erc721metadata, CollectionFlag.Foreign],
+ }, 'nft')).to.be.rejectedWith(/common.NoPermission/);
+ });
+
+ itSub('Create new collection with extra fields', async ({helper}) => {
+ const collection = await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'fungible');
+ await collection.setPermissions(alice, {access: 'AllowList'});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 3});
+ const data = await collection.getData();
+ const limits = await collection.getEffectiveLimits();
+ const raw = data?.raw;
+
+ expect(data?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address));
+ expect(data?.name).to.be.equal('name');
+ expect(data?.description).to.be.equal('descr');
+ expect(raw.permissions.access).to.be.equal('AllowList');
+ expect(raw.mode).to.be.deep.equal({Fungible: '0'});
+ expect(limits.accountTokenOwnershipLimit).to.be.equal(3);
+ });
+
+ itSub('New collection is not external', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
+ const data = await collection.getData();
+ expect(data?.raw.readOnly).to.be.false;
+ });
+});
+
+describe('(!negative test!) integration test: ext. createCollection():', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ itSub('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async ({helper}) => {
+ const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'A'.repeat(65), description: 'descr', tokenPrefix: 'COL'});
+ await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
+ });
+ itSub('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async ({helper}) => {
+ const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'A'.repeat(257), tokenPrefix: 'COL'});
+ await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
+ });
+ itSub('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async ({helper}) => {
+ const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(17)});
+ await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub('(!negative test!) fails when bad limits are set', async ({helper}) => {
+ const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', limits: {tokenLimit: 0}});
+ await expect(mintCollectionTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
+ });
+
+ itSub('(!negative test!) create collection with incorrect property limit (64 elements)', async ({helper}) => {
+ const props: IProperty[] = [];
+
+ for(let i = 0; i < 65; i++) {
+ props.push({key: `key${i}`, value: `value${i}`});
+ }
+ const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', properties: props});
+ await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub('(!negative test!) create collection with incorrect property limit (40 kb)', async ({helper}) => {
+ const props: IProperty[] = [];
+
+ for(let i = 0; i < 32; i++) {
+ props.push({key: `key${i}`.repeat(80), value: `value${i}`.repeat(80)});
+ }
+
+ const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', properties: props});
+ await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
+ });
+});
js-packages/tests/createItem.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/createItem.test.ts
@@ -0,0 +1,272 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets} from './util/index.js';
+import type {IProperty, ICrossAccountId} from '@unique/playgrounds/types.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+
+async function mintTokenHelper(helper: UniqueHelper, collection: any, signer: IKeyringPair, owner: ICrossAccountId, type: 'nft' | 'fungible' | 'refungible'='nft', properties?: IProperty[]) {
+ let token;
+ const itemCountBefore = await helper.collection.getLastTokenId(collection.collectionId);
+ const itemBalanceBefore = (await helper.callRpc('api.rpc.unique.balance', [collection.collectionId, owner, 0])).toBigInt();
+ if(type === 'nft') {
+ token = await collection.mintToken(signer, owner, properties);
+ } else if(type === 'fungible') {
+ await collection.mint(signer, 10n, owner);
+ } else {
+ token = await collection.mintToken(signer, 100n, owner, properties);
+ }
+
+ const itemCountAfter = await helper.collection.getLastTokenId(collection.collectionId);
+ const itemBalanceAfter = (await helper.callRpc('api.rpc.unique.balance', [collection.collectionId, owner, 0])).toBigInt();
+
+ if(type === 'fungible') {
+ expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);
+ } else {
+ expect(itemCountAfter).to.be.equal(itemCountBefore + 1);
+ }
+
+ return token;
+}
+
+
+describe('integration test: ext. ():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Create new item in NFT collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await mintTokenHelper(helper, collection, alice, {Substrate: alice.address});
+ });
+ itSub('Create new item in Fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}, 'fungible');
+ });
+ itSub('Check events on create new item in Fungible collection', async ({helper}) => {
+ const {collectionId} = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
+ const to = {Substrate: alice.address};
+ {
+ const createData = {fungible: {value: 100}};
+ const events = await helper.executeExtrinsic(alice, 'api.tx.unique.createItem', [collectionId, to, createData as any]);
+ const result = helper.util.extractTokensFromCreationResult(events);
+ expect(result.tokens[0].amount).to.be.equal(100n);
+ expect(result.tokens[0].collectionId).to.be.equal(collectionId);
+ expect(result.tokens[0].owner).to.be.deep.equal(to);
+ }
+ {
+ const createData = {fungible: {value: 50}};
+ const events = await helper.executeExtrinsic(alice, 'api.tx.unique.createItem', [collectionId, to, createData as any]);
+ const result = helper.util.extractTokensFromCreationResult(events);
+ expect(result.tokens[0].amount).to.be.equal(50n);
+ expect(result.tokens[0].collectionId).to.be.equal(collectionId);
+ expect(result.tokens[0].owner).to.be.deep.equal(to);
+ }
+ });
+ itSub.ifWithPallets('Create new item in ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}, 'refungible');
+ });
+ itSub('Create new item in NFT collection with collection admin permissions', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await mintTokenHelper(helper, collection, bob, {Substrate: alice.address});
+ });
+ itSub('Create new item in Fungible collection with collection admin permissions', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}, 'fungible');
+ });
+ itSub.ifWithPallets('Create new item in ReFungible collection with collection admin permissions', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}, 'refungible');
+ });
+
+ itSub('Set property Admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL',
+ properties: [{key: 'k', value: 'v'}],
+ tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: false, mutable: true, collectionAdmin: true}}],
+ });
+ await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]);
+ });
+
+ itSub('Set property AdminConst', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL',
+ properties: [{key: 'k', value: 'v'}],
+ tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}}],
+ });
+ await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]);
+ });
+
+ itSub('Set property itemOwnerOrAdmin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL',
+ properties: [{key: 'k', value: 'v'}],
+ tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}],
+ });
+ await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]);
+ });
+
+ itSub('Check total pieces of Fungible token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ const amount = 10n;
+ await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'fungible');
+ {
+ const totalPieces = await collection.getTotalPieces();
+ expect(totalPieces).to.be.equal(amount);
+ }
+ await collection.transfer(bob, {Substrate: alice.address}, 1n);
+ {
+ const totalPieces = await collection.getTotalPieces();
+ expect(totalPieces).to.be.equal(amount);
+ }
+ });
+
+ itSub('Check total pieces of NFT token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const amount = 1n;
+ const token = await mintTokenHelper(helper, collection, alice, {Substrate: bob.address});
+ {
+ const totalPieces = await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, token.tokenId]);
+ expect(totalPieces?.unwrap().toBigInt()).to.be.equal(amount);
+ }
+ await token.transfer(bob, {Substrate: alice.address});
+ {
+ const totalPieces = await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, token.tokenId]);
+ expect(totalPieces?.unwrap().toBigInt()).to.be.equal(amount);
+ }
+ });
+
+ itSub.ifWithPallets('Check total pieces of ReFungible token', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const amount = 100n;
+ const token = await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'refungible');
+ {
+ const totalPieces = await token.getTotalPieces();
+ expect(totalPieces).to.be.equal(amount);
+ }
+ await token.transfer(bob, {Substrate: alice.address}, 60n);
+ {
+ const totalPieces = await token.getTotalPieces();
+ expect(totalPieces).to.be.equal(amount);
+ }
+ });
+});
+
+describe('Negative integration test: ext. createItem():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Regular user cannot create new item in NFT collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const mintTx = () => collection.mintToken(bob, {Substrate: bob.address});
+ await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
+ });
+ itSub('Regular user cannot create new item in Fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ const mintTx = () => collection.mint(bob, 10n, {Substrate: bob.address});
+ await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
+ });
+ itSub.ifWithPallets('Regular user cannot create new item in ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const mintTx = () => collection.mintToken(bob, 100n, {Substrate: bob.address});
+ await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
+ });
+
+ itSub('No editing rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL',
+ tokenPropertyPermissions: [{key: 'k', permission: {mutable: false, collectionAdmin: false, tokenOwner: false}}],
+ });
+ const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]);
+ await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('User doesnt have editing rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL',
+ tokenPropertyPermissions: [{key: 'k', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}],
+ });
+ const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]);
+ await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Adding property without access rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]);
+ await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Adding more than 64 prps', async ({helper}) => {
+ const props: IProperty[] = [];
+
+ for(let i = 0; i < 65; i++) {
+ props.push({key: `key${i}`, value: `value${i}`});
+ }
+
+
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, props);
+ await expect(mintTx()).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub('Trying to add bigger property than allowed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'k1', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
+ {key: 'k2', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
+ ],
+ });
+ const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [
+ {key: 'k1', value: 'vvvvvv'.repeat(5000)},
+ {key: 'k2', value: 'vvv'.repeat(5000)},
+ ]);
+ await expect(mintTx()).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+ });
+
+ itSub('Check total pieces for invalid Fungible token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+ const invalidTokenId = 1_000_000;
+ expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true;
+ expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n);
+ });
+
+ itSub('Check total pieces for invalid NFT token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const invalidTokenId = 1_000_000;
+ expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true;
+ expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n);
+ });
+
+ itSub.ifWithPallets('Check total pieces for invalid Refungible token', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const invalidTokenId = 1_000_000;
+ expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true;
+ expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n);
+ });
+});
js-packages/tests/createMultipleItems.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/createMultipleItems.test.ts
@@ -0,0 +1,374 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, Pallets, itSub} from './util/index.js';
+
+describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ itSub('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: '1'}]},
+ {properties: [{key: 'data', value: '2'}]},
+ {properties: [{key: 'data', value: '3'}]},
+ ];
+ const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ for(const [i, token] of tokens.entries()) {
+ const tokenData = await token.getData();
+ expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
+ expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
+ }
+ });
+
+ itSub('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const args = [
+ {value: 1n},
+ {value: 2n},
+ {value: 3n},
+ ];
+ await helper.ft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, args, {Substrate: alice.address});
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(6n);
+ });
+
+ itSub.ifWithPallets('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const args = [
+ {pieces: 1n},
+ {pieces: 2n},
+ {pieces: 3n},
+ ];
+ const tokens = await helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+
+ for(const [i, token] of tokens.entries()) {
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(BigInt(i + 1));
+ }
+ });
+
+ itSub('Can mint amount of items equals to collection limits', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ limits: {
+ tokenLimit: 2,
+ },
+ });
+ const args = [{}, {}];
+ await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ });
+
+ itSub('Create 0x31, 0x32, 0x33 items in active NFT with property Admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: false, mutable: true, collectionAdmin: true}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: '1'}]},
+ {properties: [{key: 'data', value: '2'}]},
+ {properties: [{key: 'data', value: '3'}]},
+ ];
+ const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ for(const [i, token] of tokens.entries()) {
+ const tokenData = await token.getData();
+ expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
+ expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
+ }
+ });
+
+ itSub('Create 0x31, 0x32, 0x33 items in active NFT with property AdminConst', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: '1'}]},
+ {properties: [{key: 'data', value: '2'}]},
+ {properties: [{key: 'data', value: '3'}]},
+ ];
+ const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ for(const [i, token] of tokens.entries()) {
+ const tokenData = await token.getData();
+ expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
+ expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
+ }
+ });
+
+ itSub('Create 0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: '1'}]},
+ {properties: [{key: 'data', value: '2'}]},
+ {properties: [{key: 'data', value: '3'}]},
+ ];
+ const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ for(const [i, token] of tokens.entries()) {
+ const tokenData = await token.getData();
+ expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
+ expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
+ }
+ });
+});
+
+describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Regular user cannot create items in active NFT collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const args = [
+ {},
+ {},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
+ });
+
+ itSub('Regular user cannot create items in active Fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const args = [
+ {value: 1n},
+ {value: 2n},
+ {value: 3n},
+ ];
+ const mintTx = () => helper.ft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, args, {Substrate: alice.address});
+ await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
+ });
+
+ itSub.ifWithPallets('Regular user cannot create items in active ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const args = [
+ {pieces: 1n},
+ {pieces: 1n},
+ {pieces: 1n},
+ ];
+ const mintTx = () => helper.rft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
+ });
+
+ itSub('Create token in not existing collection', async ({helper}) => {
+ const collectionId = 1_000_000;
+ const args = [
+ {},
+ {},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(bob, collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Create NFTs that has reached the maximum data limit', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: 'A'.repeat(32769)}]},
+ {properties: [{key: 'data', value: 'B'.repeat(32769)}]},
+ {properties: [{key: 'data', value: 'C'.repeat(32769)}]},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub.ifWithPallets('Create Refungible tokens that has reached the maximum data limit', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+ ],
+ });
+ const args = [
+ {pieces: 10n, properties: [{key: 'data', value: 'A'.repeat(32769)}]},
+ {pieces: 10n, properties: [{key: 'data', value: 'B'.repeat(32769)}]},
+ {pieces: 10n, properties: [{key: 'data', value: 'C'.repeat(32769)}]},
+ ];
+ const mintTx = () => helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub.ifWithPallets('Create tokens with different types', [Pallets.ReFungible], async ({helper}) => {
+ const {collectionId} = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+
+ const types = ['NFT', 'Fungible', 'ReFungible'];
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.createMultipleItems',
+ [collectionId, {Substrate: alice.address}, types],
+ )).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/);
+ });
+
+ itSub('Create tokens with different data limits <> maximum data limit', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: 'A'}]},
+ {properties: [{key: 'data', value: 'B'.repeat(32769)}]},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub('Fails when minting tokens exceeds collectionLimits amount', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+ ],
+ limits: {
+ tokenLimit: 1,
+ },
+ });
+ const args = [
+ {},
+ {},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
+ });
+
+ itSub('User doesnt have editing rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'data', permission: {tokenOwner: false, mutable: true, collectionAdmin: false}},
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: 'A'}]},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Adding property without access rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ properties: [
+ {
+ key: 'data',
+ value: 'v',
+ },
+ ],
+ });
+ const args = [
+ {properties: [{key: 'data', value: 'A'}]},
+ ];
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Adding more than 64 prps', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const prps = [];
+
+ for(let i = 0; i < 65; i++) {
+ prps.push({key: `key${i}`, value: `value${i}`});
+ }
+
+ const args = [
+ {properties: prps},
+ {properties: prps},
+ {properties: prps},
+ ];
+
+ const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
+ await expect(mintTx()).to.be.rejectedWith('Verification Error');
+ });
+});
js-packages/tests/createMultipleItemsEx.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/createMultipleItemsEx.test.ts
@@ -0,0 +1,442 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, Pallets, itSub} from './util/index.js';
+import type {IProperty} from '@unique/playgrounds/types.js';
+
+describe('Integration Test: createMultipleItemsEx', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('can initialize multiple NFT with different owners', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ },
+ {
+ owner: {Substrate: bob.address},
+ },
+ {
+ owner: {Substrate: charlie.address},
+ },
+ ];
+
+ const tokens = await collection.mintMultipleTokens(alice, args);
+ for(const [i, token] of tokens.entries()) {
+ expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
+ }
+ });
+
+ itSub('createMultipleItemsEx with property Admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: false,
+ },
+ },
+ ],
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'v1'}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'v2'}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'v3'}],
+ },
+ ];
+
+ const tokens = await collection.mintMultipleTokens(alice, args);
+ for(const [i, token] of tokens.entries()) {
+ expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
+ expect(await token.getData()).to.not.be.empty;
+ }
+ });
+
+ itSub('createMultipleItemsEx with property AdminConst', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: false,
+ collectionAdmin: true,
+ tokenOwner: false,
+ },
+ },
+ ],
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'v1'}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'v2'}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'v3'}],
+ },
+ ];
+
+ const tokens = await collection.mintMultipleTokens(alice, args);
+ for(const [i, token] of tokens.entries()) {
+ expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
+ expect(await token.getData()).to.not.be.empty;
+ }
+ });
+
+ itSub('createMultipleItemsEx with property itemOwnerOrAdmin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: false,
+ collectionAdmin: true,
+ tokenOwner: true,
+ },
+ },
+ ],
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'v1'}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'v2'}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'v3'}],
+ },
+ ];
+
+ const tokens = await collection.mintMultipleTokens(alice, args);
+ for(const [i, token] of tokens.entries()) {
+ expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
+ expect(await token.getData()).to.not.be.empty;
+ }
+ });
+
+ itSub('can initialize fungible with multiple owners', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ }, 0);
+
+ await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
+ Fungible: new Map([
+ [JSON.stringify({Substrate: alice.address}), 50],
+ [JSON.stringify({Substrate: bob.address}), 100],
+ ]),
+ }], true);
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(50n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(100n);
+ });
+
+ itSub.ifWithPallets('can initialize an RFT with multiple owners', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'k', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}},
+ ],
+ });
+
+ await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx', [collection.collectionId, {
+ RefungibleMultipleOwners: {
+ users: new Map([
+ [JSON.stringify({Substrate: alice.address}), 1],
+ [JSON.stringify({Substrate: bob.address}), 2],
+ ]),
+ properties: [
+ {key: 'k', value: 'v'},
+ ],
+ },
+ }], true);
+ const tokenId = await collection.getLastTokenId();
+ expect(tokenId).to.be.equal(1);
+ expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);
+ expect(await collection.getTokenBalance(1, {Substrate: bob.address})).to.be.equal(2n);
+ });
+
+ itSub.ifWithPallets('can initialize multiple RFTs with the same owner', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {key: 'k', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}},
+ ],
+ });
+
+ await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx', [collection.collectionId, {
+ RefungibleMultipleItems: [
+ {
+ user: {Substrate: alice.address}, pieces: 1,
+ properties: [
+ {key: 'k', value: 'v1'},
+ ],
+ },
+ {
+ user: {Substrate: alice.address}, pieces: 3,
+ properties: [
+ {key: 'k', value: 'v2'},
+ ],
+ },
+ ],
+ }], true);
+
+ expect(await collection.getLastTokenId()).to.be.equal(2);
+ expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);
+ expect(await collection.getTokenBalance(2, {Substrate: alice.address})).to.be.equal(3n);
+
+ const tokenData1 = await helper.rft.getToken(collection.collectionId, 1);
+ expect(tokenData1).to.not.be.null;
+ expect(tokenData1?.properties[0]).to.be.deep.equal({key: 'k', value: 'v1'});
+
+ const tokenData2 = await helper.rft.getToken(collection.collectionId, 2);
+ expect(tokenData2).to.not.be.null;
+ expect(tokenData2?.properties[0]).to.be.deep.equal({key: 'k', value: 'v2'});
+ });
+});
+
+describe('Negative test: createMultipleItemsEx', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('No editing rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: true,
+ collectionAdmin: false,
+ tokenOwner: false,
+ },
+ },
+ ],
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'v1'}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'v2'}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'v3'}],
+ },
+ ];
+
+ await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('User doesnt have editing rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: false,
+ collectionAdmin: false,
+ tokenOwner: false,
+ },
+ },
+ ],
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'v1'}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'v2'}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'v3'}],
+ },
+ ];
+
+ await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Adding property without access rights', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'v1'}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'v2'}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'v3'}],
+ },
+ ];
+
+ await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Adding more than 64 properties', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: true,
+ },
+ },
+ ],
+ });
+
+ const properties: IProperty[] = [];
+
+ for(let i = 0; i < 65; i++) {
+ properties.push({key: `k${i}`, value: `v${i}`});
+ }
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: properties,
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: properties,
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: properties,
+ },
+ ];
+
+ await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith('Verification Error');
+ });
+
+ itSub('Trying to add bigger property than allowed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'name',
+ description: 'descr',
+ tokenPrefix: 'COL',
+ tokenPropertyPermissions: [
+ {
+ key: 'k',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: true,
+ },
+ },
+ ],
+ });
+
+ const args = [
+ {
+ owner: {Substrate: alice.address},
+ properties: [{key: 'k', value: 'A'.repeat(32769)}],
+ },
+ {
+ owner: {Substrate: bob.address},
+ properties: [{key: 'k', value: 'A'.repeat(32769)}],
+ },
+ {
+ owner: {Substrate: charlie.address},
+ properties: [{key: 'k', value: 'A'.repeat(32769)}],
+ },
+ ];
+
+ await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith('Verification Error');
+ });
+});
js-packages/tests/creditFeesToTreasury.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/creditFeesToTreasury.seqtest.ts
@@ -0,0 +1,166 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {ApiPromise} from '@polkadot/api';
+import {usingPlaygrounds, expect, itSub} from './util/index.js';
+import type {u32} from '@polkadot/types-codec';
+
+const TREASURY = '5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z';
+const saneMinimumFee = 0.05;
+const saneMaximumFee = 0.5;
+const createCollectionDeposit = 100;
+
+// Skip the inflation block pauses if the block is close to inflation block
+// until the inflation happens
+/*eslint no-async-promise-executor: "off"*/
+function skipInflationBlock(api: ApiPromise): Promise<void> {
+ const promise = new Promise<void>(async (resolve) => {
+ const inflationBlockInterval = api.consts.inflation.inflationBlockInterval as u32;
+ const blockInterval = inflationBlockInterval.toNumber();
+ const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => {
+ const currentBlock = head.number.toNumber();
+ if(currentBlock % blockInterval < blockInterval - 10) {
+ unsubscribe();
+ resolve();
+ } else {
+ console.log(`Skipping inflation block, current block: ${currentBlock}`);
+ }
+ });
+ });
+
+ return promise;
+}
+
+describe('integration test: Fees must be credited to Treasury:', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Total issuance does not change', async ({helper}) => {
+ const api = helper.getApi();
+ await skipInflationBlock(api);
+ await helper.wait.newBlocks(1);
+
+ const totalBefore = (await helper.callRpc('api.query.balances.totalIssuance', [])).toBigInt();
+
+ await helper.balance.transferToSubstrate(alice, bob.address, 1n);
+
+ const totalAfter = (await helper.callRpc('api.query.balances.totalIssuance', [])).toBigInt();
+
+ expect(totalAfter).to.be.equal(totalBefore);
+ });
+
+ itSub('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async ({helper}) => {
+ await skipInflationBlock(helper.getApi());
+ await helper.wait.newBlocks(1);
+
+ const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+
+ const amount = 1n;
+ await helper.balance.transferToSubstrate(alice, bob.address, amount);
+
+ const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY);
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+
+ const fee = aliceBalanceBefore - aliceBalanceAfter - amount;
+ const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;
+
+ expect(treasuryIncrease).to.be.equal(fee);
+ });
+
+ itSub('Treasury balance increased by failed tx fee', async ({helper}) => {
+ const api = helper.getApi();
+ await helper.wait.newBlocks(1);
+
+ const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ await expect(helper.signTransaction(bob, api.tx.balances.forceSetBalance(alice.address, 0))).to.be.rejected;
+
+ const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY);
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ const fee = bobBalanceBefore - bobBalanceAfter;
+ const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;
+
+ expect(treasuryIncrease).to.be.equal(fee);
+ });
+
+ itSub('NFT Transactions also send fees to Treasury', async ({helper}) => {
+ await skipInflationBlock(helper.getApi());
+ await helper.wait.newBlocks(1);
+
+ const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+
+ await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY);
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+ const fee = aliceBalanceBefore - aliceBalanceAfter;
+ const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;
+
+ expect(treasuryIncrease).to.be.equal(fee);
+ });
+
+ itSub('Fees are sane', async ({helper}) => {
+ const unique = helper.balance.getOneTokenNominal();
+ await skipInflationBlock(helper.getApi());
+ await helper.wait.newBlocks(1);
+
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+
+ await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+ const fee = aliceBalanceBefore - aliceBalanceAfter;
+
+ expect(fee / unique < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true;
+ expect(fee / unique < BigInt(Math.ceil(saneMinimumFee + createCollectionDeposit))).to.be.true;
+ });
+
+ itSub('NFT Transfer fee is close to 0.1 Unique', async ({helper}) => {
+ await skipInflationBlock(helper.getApi());
+ await helper.wait.newBlocks(1);
+
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+ await token.transfer(alice, {Substrate: bob.address});
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+
+ const fee = Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal());
+ const expectedTransferFee = 0.1;
+ // fee drifts because of NextFeeMultiplier
+ const tolerance = 0.001;
+
+ expect(Math.abs(fee - expectedTransferFee)).to.be.lessThan(tolerance);
+ });
+});
js-packages/tests/destroyCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/destroyCollection.test.ts
@@ -0,0 +1,120 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, expect, usingPlaygrounds, Pallets} from './util/index.js';
+
+describe('integration test: ext. destroyCollection():', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ itSub('NFT collection can be destroyed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ await collection.burn(alice);
+ expect(await collection.getData()).to.be.null;
+ });
+ itSub('Fungible collection can be destroyed', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ }, 0);
+ await collection.burn(alice);
+ expect(await collection.getData()).to.be.null;
+ });
+ itSub.ifWithPallets('ReFungible collection can be destroyed', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ await collection.burn(alice);
+ expect(await collection.getData()).to.be.null;
+ });
+});
+
+describe('(!negative test!) integration test: ext. destroyCollection():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('(!negative test!) Destroy a collection that never existed', async ({helper}) => {
+ const collectionId = 1_000_000;
+ await expect(helper.collection.burn(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+ itSub('(!negative test!) Destroy a collection that has already been destroyed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ await collection.burn(alice);
+ await expect(collection.burn(alice)).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+ itSub('(!negative test!) Destroy a collection using non-owner account', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ await expect(collection.burn(bob)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+ itSub('(!negative test!) Destroy a collection using collection admin account', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await expect(collection.burn(bob)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+ itSub('fails when OwnerCanDestroy == false', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ limits: {
+ ownerCanDestroy: false,
+ },
+ });
+ await expect(collection.burn(alice)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+ itSub('fails when a collection still has a token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ });
+ await collection.mintToken(alice, {Substrate: alice.address});
+ await expect(collection.burn(alice)).to.be.rejectedWith(/common\.CantDestroyNotEmptyCollection/);
+ });
+});
js-packages/tests/enableDisableTransfer.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/enableDisableTransfer.test.ts
@@ -0,0 +1,82 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+
+describe('Enable/Disable Transfers', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('User can transfer token with enabled transfer flag', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ limits: {
+ transfersEnabled: true,
+ },
+ });
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ await token.transfer(alice, {Substrate: bob.address});
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ });
+
+ itSub('User can\'n transfer token with disabled transfer flag', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ limits: {
+ transfersEnabled: false,
+ },
+ });
+ const token = await collection.mintToken(alice, {Substrate: alice.address});
+ await expect(token.transfer(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.TransferNotAllowed/);
+ });
+});
+
+describe('Negative Enable/Disable Transfers', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('Non-owner cannot change transfer flag', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test',
+ description: 'test',
+ tokenPrefix: 'test',
+ limits: {
+ transfersEnabled: true,
+ },
+ });
+
+ await expect(collection.setLimits(bob, {transfersEnabled: false})).to.be.rejectedWith(/common\.NoPermission/);
+ });
+});
js-packages/tests/eth/abi/collectionHelpers.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/collectionHelpers.json
@@ -0,0 +1,267 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "collectionId",
+ "type": "address"
+ }
+ ],
+ "name": "CollectionChanged",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "collectionId",
+ "type": "address"
+ }
+ ],
+ "name": "CollectionCreated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "collectionId",
+ "type": "address"
+ }
+ ],
+ "name": "CollectionDestroyed",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint32", "name": "collectionId", "type": "uint32" }
+ ],
+ "name": "collectionAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionCreationFee",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "collectionAddress",
+ "type": "address"
+ }
+ ],
+ "name": "collectionId",
+ "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "name", "type": "string" },
+ { "internalType": "string", "name": "description", "type": "string" },
+ {
+ "internalType": "string",
+ "name": "token_prefix",
+ "type": "string"
+ },
+ {
+ "internalType": "enum CollectionMode",
+ "name": "mode",
+ "type": "uint8"
+ },
+ { "internalType": "uint8", "name": "decimals", "type": "uint8" },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ {
+ "components": [
+ {
+ "internalType": "enum TokenPermissionField",
+ "name": "code",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct PropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct TokenPropertyPermission[]",
+ "name": "token_property_permissions",
+ "type": "tuple[]"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress[]",
+ "name": "admin_list",
+ "type": "tuple[]"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "nesting_settings",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct CollectionLimitValue[]",
+ "name": "limits",
+ "type": "tuple[]"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "pending_sponsor",
+ "type": "tuple"
+ },
+ {
+ "internalType": "CollectionFlags",
+ "name": "flags",
+ "type": "uint8"
+ }
+ ],
+ "internalType": "struct CreateCollectionData",
+ "name": "data",
+ "type": "tuple"
+ }
+ ],
+ "name": "createCollection",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string", "name": "name", "type": "string" },
+ { "internalType": "uint8", "name": "decimals", "type": "uint8" },
+ { "internalType": "string", "name": "description", "type": "string" },
+ { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+ ],
+ "name": "createFTCollection",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string", "name": "name", "type": "string" },
+ { "internalType": "string", "name": "description", "type": "string" },
+ { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+ ],
+ "name": "createNFTCollection",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string", "name": "name", "type": "string" },
+ { "internalType": "string", "name": "description", "type": "string" },
+ { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+ ],
+ "name": "createRFTCollection",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "collectionAddress",
+ "type": "address"
+ }
+ ],
+ "name": "destroyCollection",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "collectionAddress",
+ "type": "address"
+ }
+ ],
+ "name": "isCollectionExist",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "collection", "type": "address" },
+ { "internalType": "string", "name": "baseUri", "type": "string" }
+ ],
+ "name": "makeCollectionERC721MetadataCompatible",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/contractHelpers.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/contractHelpers.json
@@ -0,0 +1,326 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "ContractSponsorRemoved",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "sponsor",
+ "type": "address"
+ }
+ ],
+ "name": "ContractSponsorSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "sponsor",
+ "type": "address"
+ }
+ ],
+ "name": "ContractSponsorshipConfirmed",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "allowed",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "allowlistEnabled",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "confirmSponsorship",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "contractOwner",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "hasPendingSponsor",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "hasSponsor",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "removeSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "selfSponsoredEnable",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ { "internalType": "address", "name": "sponsor", "type": "address" }
+ ],
+ "name": "setSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ { "internalType": "uint256", "name": "feeLimit", "type": "uint256" }
+ ],
+ "name": "setSponsoringFeeLimit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "enum SponsoringModeT",
+ "name": "mode",
+ "type": "uint8"
+ }
+ ],
+ "name": "setSponsoringMode",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }
+ ],
+ "name": "setSponsoringRateLimit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "sponsor",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct OptionCrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "sponsoringEnabled",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "sponsoringFeeLimit",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "sponsoringRateLimit",
+ "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ { "internalType": "address", "name": "user", "type": "address" },
+ { "internalType": "bool", "name": "isAllowed", "type": "bool" }
+ ],
+ "name": "toggleAllowed",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ { "internalType": "bool", "name": "enabled", "type": "bool" }
+ ],
+ "name": "toggleAllowlist",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/fungible.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/fungible.json
@@ -0,0 +1,722 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "newAdmin",
+ "type": "tuple"
+ }
+ ],
+ "name": "addCollectionAdminCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "addToCollectionAllowListCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "address", "name": "spender", "type": "address" }
+ ],
+ "name": "allowance",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "spender",
+ "type": "tuple"
+ }
+ ],
+ "name": "allowanceCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "allowlistedCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "spender", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "approve",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "spender",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "approveCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" }
+ ],
+ "name": "balanceOf",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ }
+ ],
+ "name": "balanceOfCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "burnFromCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "newOwner",
+ "type": "tuple"
+ }
+ ],
+ "name": "changeCollectionOwnerCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionAdmins",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionHelperAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionLimits",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct OptionUint256",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct CollectionLimit[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNesting",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionOwner",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "collectionProperties",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+ "name": "collectionProperty",
+ "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionSponsor",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "confirmCollectionSponsorship",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "contractAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "deleteCollectionProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "description",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "hasCollectionPendingSponsor",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "isOwnerOrAdminCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "mint",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "internalType": "struct AmountForAddress[]",
+ "name": "amounts",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintBulk",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "mintCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "admin",
+ "type": "tuple"
+ }
+ ],
+ "name": "removeCollectionAdminCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "removeCollectionSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "removeFromCollectionAllowListCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+ ],
+ "name": "setCollectionAccess",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct OptionUint256",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct CollectionLimit",
+ "name": "limit",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionLimit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+ "name": "setCollectionMintMode",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "collectionNestingAndPermissions",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setCollectionProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "sponsor",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionSponsorCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transfer",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferFrom",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferFromCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "uniqueCollectionType",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/fungibleDeprecated.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/fungibleDeprecated.json
@@ -0,0 +1,151 @@
+[
+ {
+ "inputs": [
+ { "internalType": "address", "name": "newAdmin", "type": "address" }
+ ],
+ "name": "addCollectionAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "addToCollectionAllowList",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "burnFrom",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "newOwner", "type": "address" }
+ ],
+ "name": "changeCollectionOwner",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+ "name": "deleteCollectionProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "isOwnerOrAdmin",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "admin", "type": "address" }
+ ],
+ "name": "removeCollectionAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "removeFromCollectionAllowList",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "name": "setCollectionProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "sponsor", "type": "address" }
+ ],
+ "name": "setCollectionSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNestingPermissions",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionPermissionField",
+ "name": "field",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct CollectionNestingPermission[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNestingRestrictedCollectionIds",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
+ ],
+ "internalType": "struct CollectionNesting",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bool", "name": "enable", "type": "bool" },
+ {
+ "internalType": "address[]",
+ "name": "collections",
+ "type": "address[]"
+ }
+ ],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/nativeFungible.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/nativeFungible.json
@@ -0,0 +1,201 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "address", "name": "spender", "type": "address" }
+ ],
+ "name": "allowance",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "spender", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "approve",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" }
+ ],
+ "name": "balanceOf",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ }
+ ],
+ "name": "balanceOfCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transfer",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferFrom",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferFromCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/nonFungible.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/nonFungible.json
@@ -0,0 +1,988 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "approved",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "bool",
+ "name": "approved",
+ "type": "bool"
+ }
+ ],
+ "name": "ApprovalForAll",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "TokenChanged",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "newAdmin",
+ "type": "tuple"
+ }
+ ],
+ "name": "addCollectionAdminCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "addToCollectionAllowListCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "allowlistedCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "approved", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "approve",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "approved",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "approveCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" }
+ ],
+ "name": "balanceOf",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ }
+ ],
+ "name": "balanceOfCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "burn",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "burnFromCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "newOwner",
+ "type": "tuple"
+ }
+ ],
+ "name": "changeCollectionOwnerCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionAdmins",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionHelperAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionLimits",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct OptionUint256",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct CollectionLimit[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNesting",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionOwner",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "collectionProperties",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+ "name": "collectionProperty",
+ "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionSponsor",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "confirmCollectionSponsorship",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "contractAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "deleteCollectionProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "deleteProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "description",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "getApproved",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "hasCollectionPendingSponsor",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "address", "name": "operator", "type": "address" }
+ ],
+ "name": "isApprovedForAll",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "isOwnerOrAdminCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
+ "name": "mint",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct MintTokenData[]",
+ "name": "data",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintBulkCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "string", "name": "tokenUri", "type": "string" }
+ ],
+ "name": "mintWithTokenURI",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "nextTokenId",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "ownerOf",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "ownerOfCross",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "properties",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string", "name": "key", "type": "string" }
+ ],
+ "name": "property",
+ "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "admin",
+ "type": "tuple"
+ }
+ ],
+ "name": "removeCollectionAdminCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "removeCollectionSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "removeFromCollectionAllowListCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "bytes", "name": "data", "type": "bytes" }
+ ],
+ "name": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "operator", "type": "address" },
+ { "internalType": "bool", "name": "approved", "type": "bool" }
+ ],
+ "name": "setApprovalForAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+ ],
+ "name": "setCollectionAccess",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct OptionUint256",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct CollectionLimit",
+ "name": "limit",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionLimit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+ "name": "setCollectionMintMode",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "collectionNestingAndPermissions",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setCollectionProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "sponsor",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionSponsorCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ {
+ "components": [
+ {
+ "internalType": "enum TokenPermissionField",
+ "name": "code",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct PropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct TokenPropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setTokenPropertyPermissions",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "index", "type": "uint256" }
+ ],
+ "name": "tokenByIndex",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "uint256", "name": "index", "type": "uint256" }
+ ],
+ "name": "tokenOfOwnerByIndex",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "tokenPropertyPermissions",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ {
+ "components": [
+ {
+ "internalType": "enum TokenPermissionField",
+ "name": "code",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct PropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct TokenPropertyPermission[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "tokenURI",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transfer",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transferCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transferFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transferFromCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "uniqueCollectionType",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/nonFungibleDeprecated.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/nonFungibleDeprecated.json
@@ -0,0 +1,172 @@
+[
+ {
+ "inputs": [
+ { "internalType": "address", "name": "newAdmin", "type": "address" }
+ ],
+ "name": "addCollectionAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "addToCollectionAllowList",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "burnFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+ "name": "deleteCollectionProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "isOwnerOrAdmin",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "admin", "type": "address" }
+ ],
+ "name": "removeCollectionAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "removeFromCollectionAllowList",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "name": "setCollectionProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "sponsor", "type": "address" }
+ ],
+ "name": "setCollectionSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "name": "setProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "newOwner", "type": "address" }
+ ],
+ "name": "changeCollectionOwner",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string", "name": "key", "type": "string" }
+ ],
+ "name": "deleteProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNestingPermissions",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionPermissionField",
+ "name": "field",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct CollectionNestingPermission[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNestingRestrictedCollectionIds",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
+ ],
+ "internalType": "struct CollectionNesting",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bool", "name": "enable", "type": "bool" },
+ {
+ "internalType": "address[]",
+ "name": "collections",
+ "type": "address[]"
+ }
+ ],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/reFungible.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/reFungible.json
@@ -0,0 +1,995 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "approved",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "bool",
+ "name": "approved",
+ "type": "bool"
+ }
+ ],
+ "name": "ApprovalForAll",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "TokenChanged",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "newAdmin",
+ "type": "tuple"
+ }
+ ],
+ "name": "addCollectionAdminCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "addToCollectionAllowListCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "allowlistedCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "approved", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "approve",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" }
+ ],
+ "name": "balanceOf",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ }
+ ],
+ "name": "balanceOfCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "burn",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "burnFromCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "newOwner",
+ "type": "tuple"
+ }
+ ],
+ "name": "changeCollectionOwnerCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionAdmins",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionHelperAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionLimits",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct OptionUint256",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct CollectionLimit[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNesting",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionOwner",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "collectionProperties",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+ "name": "collectionProperty",
+ "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionSponsor",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "confirmCollectionSponsorship",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "contractAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "deleteCollectionProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "deleteProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "description",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "getApproved",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "hasCollectionPendingSponsor",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "address", "name": "operator", "type": "address" }
+ ],
+ "name": "isApprovedForAll",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "isOwnerOrAdminCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
+ "name": "mint",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "components": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "eth",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "sub",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ },
+ { "internalType": "uint128", "name": "pieces", "type": "uint128" }
+ ],
+ "internalType": "struct OwnerPieces[]",
+ "name": "owners",
+ "type": "tuple[]"
+ },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct MintTokenData[]",
+ "name": "tokenProperties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintBulkCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "string", "name": "tokenUri", "type": "string" }
+ ],
+ "name": "mintWithTokenURI",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "nextTokenId",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "ownerOf",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "ownerOfCross",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string[]", "name": "keys", "type": "string[]" }
+ ],
+ "name": "properties",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string", "name": "key", "type": "string" }
+ ],
+ "name": "property",
+ "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "admin",
+ "type": "tuple"
+ }
+ ],
+ "name": "removeCollectionAdminCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "removeCollectionSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "user",
+ "type": "tuple"
+ }
+ ],
+ "name": "removeFromCollectionAllowListCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "bytes", "name": "data", "type": "bytes" }
+ ],
+ "name": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "operator", "type": "address" },
+ { "internalType": "bool", "name": "approved", "type": "bool" }
+ ],
+ "name": "setApprovalForAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+ ],
+ "name": "setCollectionAccess",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionLimitField",
+ "name": "field",
+ "type": "uint8"
+ },
+ {
+ "components": [
+ { "internalType": "bool", "name": "status", "type": "bool" },
+ { "internalType": "uint256", "name": "value", "type": "uint256" }
+ ],
+ "internalType": "struct OptionUint256",
+ "name": "value",
+ "type": "tuple"
+ }
+ ],
+ "internalType": "struct CollectionLimit",
+ "name": "limit",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionLimit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+ "name": "setCollectionMintMode",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ {
+ "internalType": "bool",
+ "name": "collection_admin",
+ "type": "bool"
+ },
+ {
+ "internalType": "address[]",
+ "name": "restricted",
+ "type": "address[]"
+ }
+ ],
+ "internalType": "struct CollectionNestingAndPermission",
+ "name": "collectionNestingAndPermissions",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setCollectionProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "sponsor",
+ "type": "tuple"
+ }
+ ],
+ "name": "setCollectionSponsorCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "internalType": "struct Property[]",
+ "name": "properties",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setProperties",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ {
+ "components": [
+ {
+ "internalType": "enum TokenPermissionField",
+ "name": "code",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct PropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct TokenPropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "setTokenPropertyPermissions",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "index", "type": "uint256" }
+ ],
+ "name": "tokenByIndex",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "token", "type": "uint256" }
+ ],
+ "name": "tokenContractAddress",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "uint256", "name": "index", "type": "uint256" }
+ ],
+ "name": "tokenOfOwnerByIndex",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "tokenPropertyPermissions",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ {
+ "components": [
+ {
+ "internalType": "enum TokenPermissionField",
+ "name": "code",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct PropertyPermission[]",
+ "name": "permissions",
+ "type": "tuple[]"
+ }
+ ],
+ "internalType": "struct TokenPropertyPermission[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "tokenURI",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transfer",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transferCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transferFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "transferFromCross",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "uniqueCollectionType",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/reFungibleDeprecated.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/reFungibleDeprecated.json
@@ -0,0 +1,200 @@
+[
+ {
+ "inputs": [
+ { "internalType": "address", "name": "newAdmin", "type": "address" }
+ ],
+ "name": "addCollectionAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "addToCollectionAllowList",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+ ],
+ "name": "burnFrom",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+ "name": "deleteCollectionProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "isOwnerOrAdmin",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "admin", "type": "address" }
+ ],
+ "name": "removeCollectionAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "user", "type": "address" }
+ ],
+ "name": "removeFromCollectionAllowList",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "name": "setCollectionProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "sponsor", "type": "address" }
+ ],
+ "name": "setCollectionSponsor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string", "name": "key", "type": "string" },
+ { "internalType": "bytes", "name": "value", "type": "bytes" }
+ ],
+ "name": "setProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "newOwner", "type": "address" }
+ ],
+ "name": "changeCollectionOwner",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+ { "internalType": "string", "name": "key", "type": "string" }
+ ],
+ "name": "deleteProperty",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
+ ],
+ "name": "mintBulk",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ {
+ "components": [
+ { "internalType": "uint256", "name": "field_0", "type": "uint256" },
+ { "internalType": "string", "name": "field_1", "type": "string" }
+ ],
+ "internalType": "struct Tuple0[]",
+ "name": "tokens",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintBulkWithTokenURI",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNestingPermissions",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "enum CollectionPermissionField",
+ "name": "field",
+ "type": "uint8"
+ },
+ { "internalType": "bool", "name": "value", "type": "bool" }
+ ],
+ "internalType": "struct CollectionNestingPermission[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "collectionNestingRestrictedCollectionIds",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "bool", "name": "token_owner", "type": "bool" },
+ { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
+ ],
+ "internalType": "struct CollectionNesting",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bool", "name": "enable", "type": "bool" },
+ {
+ "internalType": "address[]",
+ "name": "collections",
+ "type": "address[]"
+ }
+ ],
+ "name": "setCollectionNesting",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/reFungibleToken.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/reFungibleToken.json
@@ -0,0 +1,286 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" },
+ { "internalType": "address", "name": "spender", "type": "address" }
+ ],
+ "name": "allowance",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "spender",
+ "type": "tuple"
+ }
+ ],
+ "name": "allowanceCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "spender", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "approve",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "spender",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "approveCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "owner", "type": "address" }
+ ],
+ "name": "balanceOf",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "owner",
+ "type": "tuple"
+ }
+ ],
+ "name": "balanceOfCross",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "burnFromCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "parentToken",
+ "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "parentTokenId",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "repartition",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+ ],
+ "name": "supportsInterface",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transfer",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "address", "name": "to", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferFrom",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "from",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ { "internalType": "address", "name": "eth", "type": "address" },
+ { "internalType": "uint256", "name": "sub", "type": "uint256" }
+ ],
+ "internalType": "struct CrossAddress",
+ "name": "to",
+ "type": "tuple"
+ },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "transferFromCross",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/abi/reFungibleTokenDeprecated.jsondiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/abi/reFungibleTokenDeprecated.json
@@ -0,0 +1,12 @@
+[
+ {
+ "inputs": [
+ { "internalType": "address", "name": "from", "type": "address" },
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
+ ],
+ "name": "burnFrom",
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
js-packages/tests/eth/allowlist.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/allowlist.test.ts
@@ -0,0 +1,212 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets} from '../util/index.js';
+import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util/index.js';
+import {CreateCollectionData} from './util/playgrounds/types.js';
+
+describe('EVM contract allowlist', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Contract allowlist can be toggled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const flipper = await helper.eth.deployFlipper(owner);
+ const helpers = helper.ethNativeContract.contractHelpers(owner);
+
+ // Any user is allowed by default
+ expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;
+
+ // Enable
+ await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
+ expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.true;
+
+ // Disable
+ await helpers.methods.toggleAllowlist(flipper.options.address, false).send({from: owner});
+ expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;
+ });
+
+ itEth('Non-allowlisted user can\'t call contract with allowlist enabled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const flipper = await helper.eth.deployFlipper(owner);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+
+ // User can flip with allowlist disabled
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // Tx will be reverted if user is not in allowlist
+ await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
+ await expect(flipper.methods.flip().send({from: caller})).to.rejected;
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // Adding caller to allowlist will make contract callable again
+ await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.false;
+ });
+});
+
+describe('EVM collection allowlist', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ // Soft-deprecated
+ itEth('Collection allowlist can be added and removed by [eth] address', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const user = helper.eth.createAccount();
+ const crossUser = helper.ethCrossAccount.fromAddress(user);
+
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
+ await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
+ expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;
+
+ await collectionEvm.methods.removeFromCollectionAllowList(user).send({from: owner});
+ expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
+ });
+
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, requiredPallets: []},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {
+ const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+ const [userSub] = await helper.arrange.createAccounts([10n], donor);
+ const userEth = await helper.eth.createAccountWithBalance(donor);
+ const mintParams = testCase.mode === 'ft' ? [userEth, 100] : [userEth];
+
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+ const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);
+ const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);
+ const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
+
+ // Can addToCollectionAllowListCross:
+ expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
+ await collectionEvm.methods.addToCollectionAllowListCross(userCrossSub).send({from: owner});
+ await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});
+ await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});
+
+ // Accounts are in allowed list:
+ expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;
+ expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;
+ expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;
+ expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;
+
+ await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #1
+ await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #2
+ await collectionEvm.methods.setCollectionAccess(SponsoringMode.Allowlisted).send({from: owner});
+
+ // allowlisted account can transfer and transferCross from eth:
+ await collectionEvm.methods.transfer(owner, 1).send({from: userEth});
+ await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});
+
+ if(testCase.mode === 'ft') {
+ expect(await helper.ft.getBalance(collectionId, {Ethereum: owner})).to.eq(1n);
+ expect(await helper.ft.getBalance(collectionId, {Substrate: userSub.address})).to.eq(2n);
+ } else {
+ expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});
+ expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});
+ }
+
+ // allowlisted cross substrate accounts can transfer from Substrate:
+ testCase.mode === 'ft'
+ ? await helper.ft.transfer(userSub, collectionId, {Ethereum: userEth}, 2n)
+ : await helper.collection.transferToken(userSub, collectionId, 2, {Ethereum: userEth});
+
+ // can removeFromCollectionAllowListCross:
+ await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});
+ await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossEth).send({from: owner});
+ expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
+ expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;
+ expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.false;
+ expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;
+
+ // cannot transfer anymore
+ await collectionEvm.methods.mint(...mintParams).send({from: owner});
+ await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);
+ }));
+
+ [
+ // cross-methods
+ {mode: 'nft' as const, cross: true, requiredPallets: []},
+ {mode: 'rft' as const, cross: true, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, cross: true, requiredPallets: []},
+ // soft-deprecated
+ {mode: 'nft' as const, cross: false, requiredPallets: []},
+ {mode: 'rft' as const, cross: false, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, cross: false, requiredPallets: []},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Non-owner cannot add or remove from collection allowlist ${testCase.cross ? 'cross ' : ''}${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {
+ // Select methods:
+ const addToAllowList = testCase.cross ? 'addToCollectionAllowListCross' : 'addToCollectionAllowList';
+ const removeFromAllowList = testCase.cross ? 'removeFromCollectionAllowListCross' : 'removeFromCollectionAllowList';
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const notOwner = await helper.eth.createAccountWithBalance(donor);
+ const userSub = donor;
+ const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);
+ const userEth = helper.eth.createAccount();
+ const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);
+
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);
+
+ expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
+ expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;
+
+ // 1. notOwner cannot add to allow list:
+ // 1.1 plain ethereum or cross address:
+ await expect(collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ // 1.2 cross-substrate address:
+ if(testCase.cross)
+ await expect(collectionEvm.methods[addToAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+
+ // 2. owner can add to allow list:
+ // 2.1 plain ethereum or cross address:
+ await collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).send({from: owner});
+ // 2.2 cross-substrate address:
+ if(testCase.cross) {
+ await collectionEvm.methods[addToAllowList](userCrossSub).send({from: owner});
+ expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;
+ }
+ expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;
+
+ // 3. notOwner cannot remove from allow list:
+ // 3.1 plain ethereum or cross address:
+ await expect(collectionEvm.methods[removeFromAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ // 3.2 cross-substrate address:
+ if(testCase.cross)
+ await expect(collectionEvm.methods[removeFromAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ }));
+});
js-packages/tests/eth/api/CollectionHelpers.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/CollectionHelpers.sol
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface CollectionHelpersEvents {
+ event CollectionCreated(address indexed owner, address indexed collectionId);
+ event CollectionDestroyed(address indexed collectionId);
+ event CollectionChanged(address indexed collectionId);
+}
+
+/// @title Contract, which allows users to operate with collections
+/// @dev the ERC-165 identifier for this interface is 0x94e5af0d
+interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
+ /// Create a collection
+ /// @return address Address of the newly created collection
+ /// @dev EVM selector for this function is: 0x72b5bea7,
+ /// or in textual repr: createCollection((string,string,string,uint8,uint8,(string,bytes)[],(string,(uint8,bool)[])[],(address,uint256)[],(bool,bool,address[]),(uint8,uint256)[],(address,uint256),uint8))
+ function createCollection(CreateCollectionData memory data) external payable returns (address);
+
+ /// Create an NFT collection
+ /// @param name Name of the collection
+ /// @param description Informative description of the collection
+ /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
+ /// @return address Address of the newly created collection
+ /// @dev EVM selector for this function is: 0x844af658,
+ /// or in textual repr: createNFTCollection(string,string,string)
+ function createNFTCollection(
+ string memory name,
+ string memory description,
+ string memory tokenPrefix
+ ) external payable returns (address);
+
+ // /// Create an NFT collection
+ // /// @param name Name of the collection
+ // /// @param description Informative description of the collection
+ // /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
+ // /// @return address Address of the newly created collection
+ // /// @dev EVM selector for this function is: 0xe34a6844,
+ // /// or in textual repr: createNonfungibleCollection(string,string,string)
+ // function createNonfungibleCollection(string memory name, string memory description, string memory tokenPrefix) external payable returns (address);
+
+ /// @dev EVM selector for this function is: 0xab173450,
+ /// or in textual repr: createRFTCollection(string,string,string)
+ function createRFTCollection(
+ string memory name,
+ string memory description,
+ string memory tokenPrefix
+ ) external payable returns (address);
+
+ /// @dev EVM selector for this function is: 0x7335b79f,
+ /// or in textual repr: createFTCollection(string,uint8,string,string)
+ function createFTCollection(
+ string memory name,
+ uint8 decimals,
+ string memory description,
+ string memory tokenPrefix
+ ) external payable returns (address);
+
+ /// @dev EVM selector for this function is: 0x85624258,
+ /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string)
+ function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external;
+
+ /// @dev EVM selector for this function is: 0x564e321f,
+ /// or in textual repr: destroyCollection(address)
+ function destroyCollection(address collectionAddress) external;
+
+ /// Check if a collection exists
+ /// @param collectionAddress Address of the collection in question
+ /// @return bool Does the collection exist?
+ /// @dev EVM selector for this function is: 0xc3de1494,
+ /// or in textual repr: isCollectionExist(address)
+ function isCollectionExist(address collectionAddress) external view returns (bool);
+
+ /// @dev EVM selector for this function is: 0xd23a7ab1,
+ /// or in textual repr: collectionCreationFee()
+ function collectionCreationFee() external view returns (uint256);
+
+ /// Returns address of a collection.
+ /// @param collectionId - CollectionId of the collection
+ /// @return eth mirror address of the collection
+ /// @dev EVM selector for this function is: 0x2e716683,
+ /// or in textual repr: collectionAddress(uint32)
+ function collectionAddress(uint32 collectionId) external view returns (address);
+
+ /// Returns collectionId of a collection.
+ /// @param collectionAddress - Eth address of the collection
+ /// @return collectionId of the collection
+ /// @dev EVM selector for this function is: 0xb5cb7498,
+ /// or in textual repr: collectionId(address)
+ function collectionId(address collectionAddress) external view returns (uint32);
+}
+
+/// Collection properties
+struct CreateCollectionData {
+ /// Collection name
+ string name;
+ /// Collection description
+ string description;
+ /// Token prefix
+ string token_prefix;
+ /// Token type (NFT, FT or RFT)
+ CollectionMode mode;
+ /// Fungible token precision
+ uint8 decimals;
+ /// Custom Properties
+ Property[] properties;
+ /// Permissions for token properties
+ TokenPropertyPermission[] token_property_permissions;
+ /// Collection admins
+ CrossAddress[] admin_list;
+ /// Nesting settings
+ CollectionNestingAndPermission nesting_settings;
+ /// Collection limits
+ CollectionLimitValue[] limits;
+ /// Collection sponsor
+ CrossAddress pending_sponsor;
+ /// Extra collection flags
+ CollectionFlags flags;
+}
+
+type CollectionFlags is uint8;
+
+library CollectionFlagsLib {
+ /// Tokens in foreign collections can be transferred, but not burnt
+ CollectionFlags constant foreignField = CollectionFlags.wrap(128);
+ /// Supports ERC721Metadata
+ CollectionFlags constant erc721metadataField = CollectionFlags.wrap(64);
+ /// External collections can't be managed using `unique` api
+ CollectionFlags constant externalField = CollectionFlags.wrap(1);
+
+ /// Reserved flags
+ function reservedField(uint8 value) public pure returns (CollectionFlags) {
+ require(value < 1 << 5, "out of bound value");
+ return CollectionFlags.wrap(value << 1);
+ }
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimitValue {
+ CollectionLimitField field;
+ uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+ /// How many tokens can a user have on one account.
+ AccountTokenOwnership,
+ /// How many bytes of data are available for sponsorship.
+ SponsoredDataSize,
+ /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+ SponsoredDataRateLimit,
+ /// How many tokens can be mined into this collection.
+ TokenLimit,
+ /// Timeouts for transfer sponsoring.
+ SponsorTransferTimeout,
+ /// Timeout for sponsoring an approval in passed blocks.
+ SponsorApproveTimeout,
+ /// Whether the collection owner of the collection can send tokens (which belong to other users).
+ OwnerCanTransfer,
+ /// Can the collection owner burn other people's tokens.
+ OwnerCanDestroy,
+ /// Is it possible to send tokens from this collection between users.
+ TransferEnabled
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+ /// Owner of token can nest tokens under it.
+ bool token_owner;
+ /// Admin of token collection can nest tokens under token.
+ bool collection_admin;
+ /// If set - only tokens from specified collections can be nested.
+ address[] restricted;
+}
+
+/// Ethereum representation of Token Property Permissions.
+struct TokenPropertyPermission {
+ /// Token property key.
+ string key;
+ /// Token property permissions.
+ PropertyPermission[] permissions;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+struct PropertyPermission {
+ /// TokenPermission field.
+ TokenPermissionField code;
+ /// TokenPermission value.
+ bool value;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+enum TokenPermissionField {
+ /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+ Mutable,
+ /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+ TokenOwner,
+ /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+ CollectionAdmin
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+ string key;
+ bytes value;
+}
+
+/// Type of tokens in collection
+enum CollectionMode {
+ /// Nonfungible
+ Nonfungible,
+ /// Fungible
+ Fungible,
+ /// Refungible
+ Refungible
+}
js-packages/tests/eth/api/ContractHelpers.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/ContractHelpers.sol
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface ContractHelpersEvents {
+ event ContractSponsorSet(address indexed contractAddress, address sponsor);
+ event ContractSponsorshipConfirmed(address indexed contractAddress, address sponsor);
+ event ContractSponsorRemoved(address indexed contractAddress);
+}
+
+/// @title Magic contract, which allows users to reconfigure other contracts
+/// @dev the ERC-165 identifier for this interface is 0x30afad04
+interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
+ /// Get user, which deployed specified contract
+ /// @dev May return zero address in case if contract is deployed
+ /// using uniquenetwork evm-migration pallet, or using other terms not
+ /// intended by pallet-evm
+ /// @dev Returns zero address if contract does not exists
+ /// @param contractAddress Contract to get owner of
+ /// @return address Owner of contract
+ /// @dev EVM selector for this function is: 0x5152b14c,
+ /// or in textual repr: contractOwner(address)
+ function contractOwner(address contractAddress) external view returns (address);
+
+ /// Set sponsor.
+ /// @param contractAddress Contract for which a sponsor is being established.
+ /// @param sponsor User address who set as pending sponsor.
+ /// @dev EVM selector for this function is: 0xf01fba93,
+ /// or in textual repr: setSponsor(address,address)
+ function setSponsor(address contractAddress, address sponsor) external;
+
+ /// Set contract as self sponsored.
+ ///
+ /// @param contractAddress Contract for which a self sponsoring is being enabled.
+ /// @dev EVM selector for this function is: 0x89f7d9ae,
+ /// or in textual repr: selfSponsoredEnable(address)
+ function selfSponsoredEnable(address contractAddress) external;
+
+ /// Remove sponsor.
+ ///
+ /// @param contractAddress Contract for which a sponsorship is being removed.
+ /// @dev EVM selector for this function is: 0xef784250,
+ /// or in textual repr: removeSponsor(address)
+ function removeSponsor(address contractAddress) external;
+
+ /// Confirm sponsorship.
+ ///
+ /// @dev Caller must be same that set via [`setSponsor`].
+ ///
+ /// @param contractAddress Сontract for which need to confirm sponsorship.
+ /// @dev EVM selector for this function is: 0xabc00001,
+ /// or in textual repr: confirmSponsorship(address)
+ function confirmSponsorship(address contractAddress) external;
+
+ /// Get current sponsor.
+ ///
+ /// @param contractAddress The contract for which a sponsor is requested.
+ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
+ /// @dev EVM selector for this function is: 0x766c4f37,
+ /// or in textual repr: sponsor(address)
+ function sponsor(address contractAddress) external view returns (OptionCrossAddress memory);
+
+ /// Check tat contract has confirmed sponsor.
+ ///
+ /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
+ /// @return **true** if contract has confirmed sponsor.
+ /// @dev EVM selector for this function is: 0x97418603,
+ /// or in textual repr: hasSponsor(address)
+ function hasSponsor(address contractAddress) external view returns (bool);
+
+ /// Check tat contract has pending sponsor.
+ ///
+ /// @param contractAddress The contract for which the presence of a pending sponsor is checked.
+ /// @return **true** if contract has pending sponsor.
+ /// @dev EVM selector for this function is: 0x39b9b242,
+ /// or in textual repr: hasPendingSponsor(address)
+ function hasPendingSponsor(address contractAddress) external view returns (bool);
+
+ /// @dev EVM selector for this function is: 0x6027dc61,
+ /// or in textual repr: sponsoringEnabled(address)
+ function sponsoringEnabled(address contractAddress) external view returns (bool);
+
+ /// @dev EVM selector for this function is: 0xfde8a560,
+ /// or in textual repr: setSponsoringMode(address,uint8)
+ function setSponsoringMode(address contractAddress, SponsoringModeT mode) external;
+
+ /// Get current contract sponsoring rate limit
+ /// @param contractAddress Contract to get sponsoring rate limit of
+ /// @return uint32 Amount of blocks between two sponsored transactions
+ /// @dev EVM selector for this function is: 0xf29694d8,
+ /// or in textual repr: sponsoringRateLimit(address)
+ function sponsoringRateLimit(address contractAddress) external view returns (uint32);
+
+ /// Set contract sponsoring rate limit
+ /// @dev Sponsoring rate limit - is a minimum amount of blocks that should
+ /// pass between two sponsored transactions
+ /// @param contractAddress Contract to change sponsoring rate limit of
+ /// @param rateLimit Target rate limit
+ /// @dev Only contract owner can change this setting
+ /// @dev EVM selector for this function is: 0x77b6c908,
+ /// or in textual repr: setSponsoringRateLimit(address,uint32)
+ function setSponsoringRateLimit(address contractAddress, uint32 rateLimit) external;
+
+ /// Set contract sponsoring fee limit
+ /// @dev Sponsoring fee limit - is maximum fee that could be spent by
+ /// single transaction
+ /// @param contractAddress Contract to change sponsoring fee limit of
+ /// @param feeLimit Fee limit
+ /// @dev Only contract owner can change this setting
+ /// @dev EVM selector for this function is: 0x03aed665,
+ /// or in textual repr: setSponsoringFeeLimit(address,uint256)
+ function setSponsoringFeeLimit(address contractAddress, uint256 feeLimit) external;
+
+ /// Get current contract sponsoring fee limit
+ /// @param contractAddress Contract to get sponsoring fee limit of
+ /// @return uint256 Maximum amount of fee that could be spent by single
+ /// transaction
+ /// @dev EVM selector for this function is: 0x75b73606,
+ /// or in textual repr: sponsoringFeeLimit(address)
+ function sponsoringFeeLimit(address contractAddress) external view returns (uint256);
+
+ /// Is specified user present in contract allow list
+ /// @dev Contract owner always implicitly included
+ /// @param contractAddress Contract to check allowlist of
+ /// @param user User to check
+ /// @return bool Is specified users exists in contract allowlist
+ /// @dev EVM selector for this function is: 0x5c658165,
+ /// or in textual repr: allowed(address,address)
+ function allowed(address contractAddress, address user) external view returns (bool);
+
+ /// Toggle user presence in contract allowlist
+ /// @param contractAddress Contract to change allowlist of
+ /// @param user Which user presence should be toggled
+ /// @param isAllowed `true` if user should be allowed to be sponsored
+ /// or call this contract, `false` otherwise
+ /// @dev Only contract owner can change this setting
+ /// @dev EVM selector for this function is: 0x4706cc1c,
+ /// or in textual repr: toggleAllowed(address,address,bool)
+ function toggleAllowed(
+ address contractAddress,
+ address user,
+ bool isAllowed
+ ) external;
+
+ /// Is this contract has allowlist access enabled
+ /// @dev Allowlist always can have users, and it is used for two purposes:
+ /// in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
+ /// in case of allowlist access enabled, only users from allowlist may call this contract
+ /// @param contractAddress Contract to get allowlist access of
+ /// @return bool Is specified contract has allowlist access enabled
+ /// @dev EVM selector for this function is: 0xc772ef6c,
+ /// or in textual repr: allowlistEnabled(address)
+ function allowlistEnabled(address contractAddress) external view returns (bool);
+
+ /// Toggle contract allowlist access
+ /// @param contractAddress Contract to change allowlist access of
+ /// @param enabled Should allowlist access to be enabled?
+ /// @dev EVM selector for this function is: 0x36de20f5,
+ /// or in textual repr: toggleAllowlist(address,bool)
+ function toggleAllowlist(address contractAddress, bool enabled) external;
+}
+
+/// Available contract sponsoring modes
+enum SponsoringModeT {
+ /// Sponsoring is disabled
+ Disabled,
+ /// Only users from allowlist will be sponsored
+ Allowlisted,
+ /// All users will be sponsored
+ Generous
+}
+
+/// Optional value
+struct OptionCrossAddress {
+ /// Shows the status of accessibility of value
+ bool status;
+ /// Actual value if `status` is true
+ CrossAddress value;
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
js-packages/tests/eth/api/UniqueFungible.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/UniqueFungible.sol
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @title A contract that allows you to work with collections.
+/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
+interface Collection is Dummy, ERC165 {
+ // /// Set collection property.
+ // ///
+ // /// @param key Property key.
+ // /// @param value Propery value.
+ // /// @dev EVM selector for this function is: 0x2f073f66,
+ // /// or in textual repr: setCollectionProperty(string,bytes)
+ // function setCollectionProperty(string memory key, bytes memory value) external;
+
+ /// Set collection properties.
+ ///
+ /// @param properties Vector of properties key/value pair.
+ /// @dev EVM selector for this function is: 0x50b26b2a,
+ /// or in textual repr: setCollectionProperties((string,bytes)[])
+ function setCollectionProperties(Property[] memory properties) external;
+
+ // /// Delete collection property.
+ // ///
+ // /// @param key Property key.
+ // /// @dev EVM selector for this function is: 0x7b7debce,
+ // /// or in textual repr: deleteCollectionProperty(string)
+ // function deleteCollectionProperty(string memory key) external;
+
+ /// Delete collection properties.
+ ///
+ /// @param keys Properties keys.
+ /// @dev EVM selector for this function is: 0xee206ee3,
+ /// or in textual repr: deleteCollectionProperties(string[])
+ function deleteCollectionProperties(string[] memory keys) external;
+
+ /// Get collection property.
+ ///
+ /// @dev Throws error if key not found.
+ ///
+ /// @param key Property key.
+ /// @return bytes The property corresponding to the key.
+ /// @dev EVM selector for this function is: 0xcf24fd6d,
+ /// or in textual repr: collectionProperty(string)
+ function collectionProperty(string memory key) external view returns (bytes memory);
+
+ /// Get collection properties.
+ ///
+ /// @param keys Properties keys. Empty keys for all propertyes.
+ /// @return Vector of properties key/value pairs.
+ /// @dev EVM selector for this function is: 0x285fb8e6,
+ /// or in textual repr: collectionProperties(string[])
+ function collectionProperties(string[] memory keys) external view returns (Property[] memory);
+
+ // /// Set the sponsor of the collection.
+ // ///
+ // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+ // ///
+ // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+ // /// @dev EVM selector for this function is: 0x7623402e,
+ // /// or in textual repr: setCollectionSponsor(address)
+ // function setCollectionSponsor(address sponsor) external;
+
+ /// Set the sponsor of the collection.
+ ///
+ /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+ ///
+ /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
+ /// @dev EVM selector for this function is: 0x84a1d5a8,
+ /// or in textual repr: setCollectionSponsorCross((address,uint256))
+ function setCollectionSponsorCross(CrossAddress memory sponsor) external;
+
+ /// Whether there is a pending sponsor.
+ /// @dev EVM selector for this function is: 0x058ac185,
+ /// or in textual repr: hasCollectionPendingSponsor()
+ function hasCollectionPendingSponsor() external view returns (bool);
+
+ /// Collection sponsorship confirmation.
+ ///
+ /// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+ /// @dev EVM selector for this function is: 0x3c50e97a,
+ /// or in textual repr: confirmCollectionSponsorship()
+ function confirmCollectionSponsorship() external;
+
+ /// Remove collection sponsor.
+ /// @dev EVM selector for this function is: 0x6e0326a3,
+ /// or in textual repr: removeCollectionSponsor()
+ function removeCollectionSponsor() external;
+
+ /// Get current sponsor.
+ ///
+ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
+ /// @dev EVM selector for this function is: 0x6ec0a9f1,
+ /// or in textual repr: collectionSponsor()
+ function collectionSponsor() external view returns (CrossAddress memory);
+
+ /// Get current collection limits.
+ ///
+ /// @return Array of collection limits
+ /// @dev EVM selector for this function is: 0xf63bc572,
+ /// or in textual repr: collectionLimits()
+ function collectionLimits() external view returns (CollectionLimit[] memory);
+
+ /// Set limits for the collection.
+ /// @dev Throws error if limit not found.
+ /// @param limit Some limit.
+ /// @dev EVM selector for this function is: 0x2316ee74,
+ /// or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
+ function setCollectionLimit(CollectionLimit memory limit) external;
+
+ /// Get contract address.
+ /// @dev EVM selector for this function is: 0xf6b4dfb4,
+ /// or in textual repr: contractAddress()
+ function contractAddress() external view returns (address);
+
+ /// Add collection admin.
+ /// @param newAdmin Cross account administrator address.
+ /// @dev EVM selector for this function is: 0x859aa7d6,
+ /// or in textual repr: addCollectionAdminCross((address,uint256))
+ function addCollectionAdminCross(CrossAddress memory newAdmin) external;
+
+ /// Remove collection admin.
+ /// @param admin Cross account administrator address.
+ /// @dev EVM selector for this function is: 0x6c0cd173,
+ /// or in textual repr: removeCollectionAdminCross((address,uint256))
+ function removeCollectionAdminCross(CrossAddress memory admin) external;
+
+ // /// Add collection admin.
+ // /// @param newAdmin Address of the added administrator.
+ // /// @dev EVM selector for this function is: 0x92e462c7,
+ // /// or in textual repr: addCollectionAdmin(address)
+ // function addCollectionAdmin(address newAdmin) external;
+
+ // /// Remove collection admin.
+ // ///
+ // /// @param admin Address of the removed administrator.
+ // /// @dev EVM selector for this function is: 0xfafd7b42,
+ // /// or in textual repr: removeCollectionAdmin(address)
+ // function removeCollectionAdmin(address admin) external;
+
+ /// @dev EVM selector for this function is: 0x0b9f3890,
+ /// or in textual repr: setCollectionNesting((bool,bool,address[]))
+ function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
+
+ // /// Toggle accessibility of collection nesting.
+ // ///
+ // /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+ // /// @dev EVM selector for this function is: 0x112d4586,
+ // /// or in textual repr: setCollectionNesting(bool)
+ // function setCollectionNesting(bool enable) external;
+
+ // /// Toggle accessibility of collection nesting.
+ // ///
+ // /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+ // /// @param collections Addresses of collections that will be available for nesting.
+ // /// @dev EVM selector for this function is: 0x64872396,
+ // /// or in textual repr: setCollectionNesting(bool,address[])
+ // function setCollectionNesting(bool enable, address[] memory collections) external;
+
+ /// @dev EVM selector for this function is: 0x92c660a8,
+ /// or in textual repr: collectionNesting()
+ function collectionNesting() external view returns (CollectionNestingAndPermission memory);
+
+ // /// Returns nesting for a collection
+ // /// @dev EVM selector for this function is: 0x22d25bfe,
+ // /// or in textual repr: collectionNestingRestrictedCollectionIds()
+ // function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
+
+ // /// Returns permissions for a collection
+ // /// @dev EVM selector for this function is: 0x5b2eaf4b,
+ // /// or in textual repr: collectionNestingPermissions()
+ // function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
+
+ /// Set the collection access method.
+ /// @param mode Access mode
+ /// @dev EVM selector for this function is: 0x41835d4c,
+ /// or in textual repr: setCollectionAccess(uint8)
+ function setCollectionAccess(AccessMode mode) external;
+
+ /// Checks that user allowed to operate with collection.
+ ///
+ /// @param user User address to check.
+ /// @dev EVM selector for this function is: 0x91b6df49,
+ /// or in textual repr: allowlistedCross((address,uint256))
+ function allowlistedCross(CrossAddress memory user) external view returns (bool);
+
+ // /// Add the user to the allowed list.
+ // ///
+ // /// @param user Address of a trusted user.
+ // /// @dev EVM selector for this function is: 0x67844fe6,
+ // /// or in textual repr: addToCollectionAllowList(address)
+ // function addToCollectionAllowList(address user) external;
+
+ /// Add user to allowed list.
+ ///
+ /// @param user User cross account address.
+ /// @dev EVM selector for this function is: 0xa0184a3a,
+ /// or in textual repr: addToCollectionAllowListCross((address,uint256))
+ function addToCollectionAllowListCross(CrossAddress memory user) external;
+
+ // /// Remove the user from the allowed list.
+ // ///
+ // /// @param user Address of a removed user.
+ // /// @dev EVM selector for this function is: 0x85c51acb,
+ // /// or in textual repr: removeFromCollectionAllowList(address)
+ // function removeFromCollectionAllowList(address user) external;
+
+ /// Remove user from allowed list.
+ ///
+ /// @param user User cross account address.
+ /// @dev EVM selector for this function is: 0x09ba452a,
+ /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))
+ function removeFromCollectionAllowListCross(CrossAddress memory user) external;
+
+ /// Switch permission for minting.
+ ///
+ /// @param mode Enable if "true".
+ /// @dev EVM selector for this function is: 0x00018e84,
+ /// or in textual repr: setCollectionMintMode(bool)
+ function setCollectionMintMode(bool mode) external;
+
+ // /// Check that account is the owner or admin of the collection
+ // ///
+ // /// @param user account to verify
+ // /// @return "true" if account is the owner or admin
+ // /// @dev EVM selector for this function is: 0x9811b0c7,
+ // /// or in textual repr: isOwnerOrAdmin(address)
+ // function isOwnerOrAdmin(address user) external view returns (bool);
+
+ /// Check that account is the owner or admin of the collection
+ ///
+ /// @param user User cross account to verify
+ /// @return "true" if account is the owner or admin
+ /// @dev EVM selector for this function is: 0x3e75a905,
+ /// or in textual repr: isOwnerOrAdminCross((address,uint256))
+ function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
+
+ /// Returns collection type
+ ///
+ /// @return `Fungible` or `NFT` or `ReFungible`
+ /// @dev EVM selector for this function is: 0xd34b55b8,
+ /// or in textual repr: uniqueCollectionType()
+ function uniqueCollectionType() external view returns (string memory);
+
+ /// Get collection owner.
+ ///
+ /// @return Tuble with sponsor address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0xdf727d3b,
+ /// or in textual repr: collectionOwner()
+ function collectionOwner() external view returns (CrossAddress memory);
+
+ // /// Changes collection owner to another account
+ // ///
+ // /// @dev Owner can be changed only by current owner
+ // /// @param newOwner new owner account
+ // /// @dev EVM selector for this function is: 0x4f53e226,
+ // /// or in textual repr: changeCollectionOwner(address)
+ // function changeCollectionOwner(address newOwner) external;
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() external view returns (CrossAddress[] memory);
+
+ /// Changes collection owner to another account
+ ///
+ /// @dev Owner can be changed only by current owner
+ /// @param newOwner new owner cross account
+ /// @dev EVM selector for this function is: 0x6496c497,
+ /// or in textual repr: changeCollectionOwnerCross((address,uint256))
+ function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+ /// Access grant for owner and admins. Used as default.
+ Normal,
+ /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+ AllowList
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+struct CollectionNestingPermission {
+ CollectionPermissionField field;
+ bool value;
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+enum CollectionPermissionField {
+ /// Owner of token can nest tokens under it.
+ TokenOwner,
+ /// Admin of token collection can nest tokens under token.
+ CollectionAdmin
+}
+
+/// Nested collections.
+struct CollectionNesting {
+ bool token_owner;
+ uint256[] ids;
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+ /// Owner of token can nest tokens under it.
+ bool token_owner;
+ /// Admin of token collection can nest tokens under token.
+ bool collection_admin;
+ /// If set - only tokens from specified collections can be nested.
+ address[] restricted;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimit {
+ CollectionLimitField field;
+ OptionUint256 value;
+}
+
+/// Optional value
+struct OptionUint256 {
+ /// Shows the status of accessibility of value
+ bool status;
+ /// Actual value if `status` is true
+ uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+ /// How many tokens can a user have on one account.
+ AccountTokenOwnership,
+ /// How many bytes of data are available for sponsorship.
+ SponsoredDataSize,
+ /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+ SponsoredDataRateLimit,
+ /// How many tokens can be mined into this collection.
+ TokenLimit,
+ /// Timeouts for transfer sponsoring.
+ SponsorTransferTimeout,
+ /// Timeout for sponsoring an approval in passed blocks.
+ SponsorApproveTimeout,
+ /// Whether the collection owner of the collection can send tokens (which belong to other users).
+ OwnerCanTransfer,
+ /// Can the collection owner burn other people's tokens.
+ OwnerCanDestroy,
+ /// Is it possible to send tokens from this collection between users.
+ TransferEnabled
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+ string key;
+ bytes value;
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x69d14d3e
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+ /// @dev Function to check the amount of tokens that an owner allowed to a spender.
+ /// @param owner crossAddress The address which owns the funds.
+ /// @param spender crossAddress The address which will spend the funds.
+ /// @return A uint256 specifying the amount of tokens still available for the spender.
+ /// @dev EVM selector for this function is: 0xe0af4bd7,
+ /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
+ function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
+
+ /// @notice A description for the collection.
+ /// @dev EVM selector for this function is: 0x7284e416,
+ /// or in textual repr: description()
+ function description() external view returns (string memory);
+
+ /// @dev EVM selector for this function is: 0x269e6158,
+ /// or in textual repr: mintCross((address,uint256),uint256)
+ function mintCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0x0ecd0ab0,
+ /// or in textual repr: approveCross((address,uint256),uint256)
+ function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
+
+ // /// Burn tokens from account
+ // /// @dev Function that burns an `amount` of the tokens of a given account,
+ // /// deducting from the sender's allowance for said account.
+ // /// @param from The account whose tokens will be burnt.
+ // /// @param amount The amount that will be burnt.
+ // /// @dev EVM selector for this function is: 0x79cc6790,
+ // /// or in textual repr: burnFrom(address,uint256)
+ // function burnFrom(address from, uint256 amount) external returns (bool);
+
+ /// Burn tokens from account
+ /// @dev Function that burns an `amount` of the tokens of a given account,
+ /// deducting from the sender's allowance for said account.
+ /// @param from The account whose tokens will be burnt.
+ /// @param amount The amount that will be burnt.
+ /// @dev EVM selector for this function is: 0xbb2f5a58,
+ /// or in textual repr: burnFromCross((address,uint256),uint256)
+ function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
+
+ /// Mint tokens for multiple accounts.
+ /// @param amounts array of pairs of account address and amount
+ /// @dev EVM selector for this function is: 0x1acf2d55,
+ /// or in textual repr: mintBulk((address,uint256)[])
+ function mintBulk(AmountForAddress[] memory amounts) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0x2ada85ff,
+ /// or in textual repr: transferCross((address,uint256),uint256)
+ function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0xd5cf430b,
+ /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+ function transferFromCross(
+ CrossAddress memory from,
+ CrossAddress memory to,
+ uint256 amount
+ ) external returns (bool);
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() external view returns (address);
+
+ /// @notice Balance of account
+ /// @param owner An cross address for whom to query the balance
+ /// @return The number of fingibles owned by `owner`, possibly zero
+ /// @dev EVM selector for this function is: 0xec069398,
+ /// or in textual repr: balanceOfCross((address,uint256))
+ function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+}
+
+struct AmountForAddress {
+ address to;
+ uint256 amount;
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x40c10f19
+interface ERC20Mintable is Dummy, ERC165 {
+ /// Mint tokens for `to` account.
+ /// @param to account that will receive minted tokens
+ /// @param amount amount of tokens to mint
+ /// @dev EVM selector for this function is: 0x40c10f19,
+ /// or in textual repr: mint(address,uint256)
+ function mint(address to, uint256 amount) external returns (bool);
+}
+
+/// @dev inlined interface
+interface ERC20Events {
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+ /// @dev EVM selector for this function is: 0x06fdde03,
+ /// or in textual repr: name()
+ function name() external view returns (string memory);
+
+ /// @dev EVM selector for this function is: 0x95d89b41,
+ /// or in textual repr: symbol()
+ function symbol() external view returns (string memory);
+
+ /// @dev EVM selector for this function is: 0x18160ddd,
+ /// or in textual repr: totalSupply()
+ function totalSupply() external view returns (uint256);
+
+ /// @dev EVM selector for this function is: 0x313ce567,
+ /// or in textual repr: decimals()
+ function decimals() external view returns (uint8);
+
+ /// @dev EVM selector for this function is: 0x70a08231,
+ /// or in textual repr: balanceOf(address)
+ function balanceOf(address owner) external view returns (uint256);
+
+ /// @dev EVM selector for this function is: 0xa9059cbb,
+ /// or in textual repr: transfer(address,uint256)
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0x23b872dd,
+ /// or in textual repr: transferFrom(address,address,uint256)
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0x095ea7b3,
+ /// or in textual repr: approve(address,uint256)
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0xdd62ed3e,
+ /// or in textual repr: allowance(address,address)
+ function allowance(address owner, address spender) external view returns (uint256);
+}
+
+interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
js-packages/tests/eth/api/UniqueNFT.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/UniqueNFT.sol
@@ -0,0 +1,855 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface ERC721TokenEvent {
+ event TokenChanged(uint256 indexed tokenId);
+}
+
+/// @title A contract that allows to set and delete token properties and change token property permissions.
+/// @dev the ERC-165 identifier for this interface is 0xde0695c2
+interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
+ // /// @notice Set permissions for token property.
+ // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+ // /// @param key Property key.
+ // /// @param isMutable Permission to mutate property.
+ // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
+ // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
+ // /// @dev EVM selector for this function is: 0x222d97fa,
+ // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
+ // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
+
+ /// @notice Set permissions for token property.
+ /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+ /// @param permissions Permissions for keys.
+ /// @dev EVM selector for this function is: 0xbd92983a,
+ /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
+ function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
+
+ /// @notice Get permissions for token properties.
+ /// @dev EVM selector for this function is: 0xf23d7790,
+ /// or in textual repr: tokenPropertyPermissions()
+ function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
+
+ // /// @notice Set token property value.
+ // /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ // /// @param tokenId ID of the token.
+ // /// @param key Property key.
+ // /// @param value Property value.
+ // /// @dev EVM selector for this function is: 0x1752d67b,
+ // /// or in textual repr: setProperty(uint256,string,bytes)
+ // function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
+
+ /// @notice Set token properties value.
+ /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ /// @param tokenId ID of the token.
+ /// @param properties settable properties
+ /// @dev EVM selector for this function is: 0x14ed3a6e,
+ /// or in textual repr: setProperties(uint256,(string,bytes)[])
+ function setProperties(uint256 tokenId, Property[] memory properties) external;
+
+ // /// @notice Delete token property value.
+ // /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ // /// @param tokenId ID of the token.
+ // /// @param key Property key.
+ // /// @dev EVM selector for this function is: 0x066111d1,
+ // /// or in textual repr: deleteProperty(uint256,string)
+ // function deleteProperty(uint256 tokenId, string memory key) external;
+
+ /// @notice Delete token properties value.
+ /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ /// @param tokenId ID of the token.
+ /// @param keys Properties key.
+ /// @dev EVM selector for this function is: 0xc472d371,
+ /// or in textual repr: deleteProperties(uint256,string[])
+ function deleteProperties(uint256 tokenId, string[] memory keys) external;
+
+ /// @notice Get token property value.
+ /// @dev Throws error if key not found
+ /// @param tokenId ID of the token.
+ /// @param key Property key.
+ /// @return Property value bytes
+ /// @dev EVM selector for this function is: 0x7228c327,
+ /// or in textual repr: property(uint256,string)
+ function property(uint256 tokenId, string memory key) external view returns (bytes memory);
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+ string key;
+ bytes value;
+}
+
+/// Ethereum representation of Token Property Permissions.
+struct TokenPropertyPermission {
+ /// Token property key.
+ string key;
+ /// Token property permissions.
+ PropertyPermission[] permissions;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+struct PropertyPermission {
+ /// TokenPermission field.
+ TokenPermissionField code;
+ /// TokenPermission value.
+ bool value;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+enum TokenPermissionField {
+ /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+ Mutable,
+ /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+ TokenOwner,
+ /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+ CollectionAdmin
+}
+
+/// @title A contract that allows you to work with collections.
+/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
+interface Collection is Dummy, ERC165 {
+ // /// Set collection property.
+ // ///
+ // /// @param key Property key.
+ // /// @param value Propery value.
+ // /// @dev EVM selector for this function is: 0x2f073f66,
+ // /// or in textual repr: setCollectionProperty(string,bytes)
+ // function setCollectionProperty(string memory key, bytes memory value) external;
+
+ /// Set collection properties.
+ ///
+ /// @param properties Vector of properties key/value pair.
+ /// @dev EVM selector for this function is: 0x50b26b2a,
+ /// or in textual repr: setCollectionProperties((string,bytes)[])
+ function setCollectionProperties(Property[] memory properties) external;
+
+ // /// Delete collection property.
+ // ///
+ // /// @param key Property key.
+ // /// @dev EVM selector for this function is: 0x7b7debce,
+ // /// or in textual repr: deleteCollectionProperty(string)
+ // function deleteCollectionProperty(string memory key) external;
+
+ /// Delete collection properties.
+ ///
+ /// @param keys Properties keys.
+ /// @dev EVM selector for this function is: 0xee206ee3,
+ /// or in textual repr: deleteCollectionProperties(string[])
+ function deleteCollectionProperties(string[] memory keys) external;
+
+ /// Get collection property.
+ ///
+ /// @dev Throws error if key not found.
+ ///
+ /// @param key Property key.
+ /// @return bytes The property corresponding to the key.
+ /// @dev EVM selector for this function is: 0xcf24fd6d,
+ /// or in textual repr: collectionProperty(string)
+ function collectionProperty(string memory key) external view returns (bytes memory);
+
+ /// Get collection properties.
+ ///
+ /// @param keys Properties keys. Empty keys for all propertyes.
+ /// @return Vector of properties key/value pairs.
+ /// @dev EVM selector for this function is: 0x285fb8e6,
+ /// or in textual repr: collectionProperties(string[])
+ function collectionProperties(string[] memory keys) external view returns (Property[] memory);
+
+ // /// Set the sponsor of the collection.
+ // ///
+ // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+ // ///
+ // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+ // /// @dev EVM selector for this function is: 0x7623402e,
+ // /// or in textual repr: setCollectionSponsor(address)
+ // function setCollectionSponsor(address sponsor) external;
+
+ /// Set the sponsor of the collection.
+ ///
+ /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+ ///
+ /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
+ /// @dev EVM selector for this function is: 0x84a1d5a8,
+ /// or in textual repr: setCollectionSponsorCross((address,uint256))
+ function setCollectionSponsorCross(CrossAddress memory sponsor) external;
+
+ /// Whether there is a pending sponsor.
+ /// @dev EVM selector for this function is: 0x058ac185,
+ /// or in textual repr: hasCollectionPendingSponsor()
+ function hasCollectionPendingSponsor() external view returns (bool);
+
+ /// Collection sponsorship confirmation.
+ ///
+ /// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+ /// @dev EVM selector for this function is: 0x3c50e97a,
+ /// or in textual repr: confirmCollectionSponsorship()
+ function confirmCollectionSponsorship() external;
+
+ /// Remove collection sponsor.
+ /// @dev EVM selector for this function is: 0x6e0326a3,
+ /// or in textual repr: removeCollectionSponsor()
+ function removeCollectionSponsor() external;
+
+ /// Get current sponsor.
+ ///
+ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
+ /// @dev EVM selector for this function is: 0x6ec0a9f1,
+ /// or in textual repr: collectionSponsor()
+ function collectionSponsor() external view returns (CrossAddress memory);
+
+ /// Get current collection limits.
+ ///
+ /// @return Array of collection limits
+ /// @dev EVM selector for this function is: 0xf63bc572,
+ /// or in textual repr: collectionLimits()
+ function collectionLimits() external view returns (CollectionLimit[] memory);
+
+ /// Set limits for the collection.
+ /// @dev Throws error if limit not found.
+ /// @param limit Some limit.
+ /// @dev EVM selector for this function is: 0x2316ee74,
+ /// or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
+ function setCollectionLimit(CollectionLimit memory limit) external;
+
+ /// Get contract address.
+ /// @dev EVM selector for this function is: 0xf6b4dfb4,
+ /// or in textual repr: contractAddress()
+ function contractAddress() external view returns (address);
+
+ /// Add collection admin.
+ /// @param newAdmin Cross account administrator address.
+ /// @dev EVM selector for this function is: 0x859aa7d6,
+ /// or in textual repr: addCollectionAdminCross((address,uint256))
+ function addCollectionAdminCross(CrossAddress memory newAdmin) external;
+
+ /// Remove collection admin.
+ /// @param admin Cross account administrator address.
+ /// @dev EVM selector for this function is: 0x6c0cd173,
+ /// or in textual repr: removeCollectionAdminCross((address,uint256))
+ function removeCollectionAdminCross(CrossAddress memory admin) external;
+
+ // /// Add collection admin.
+ // /// @param newAdmin Address of the added administrator.
+ // /// @dev EVM selector for this function is: 0x92e462c7,
+ // /// or in textual repr: addCollectionAdmin(address)
+ // function addCollectionAdmin(address newAdmin) external;
+
+ // /// Remove collection admin.
+ // ///
+ // /// @param admin Address of the removed administrator.
+ // /// @dev EVM selector for this function is: 0xfafd7b42,
+ // /// or in textual repr: removeCollectionAdmin(address)
+ // function removeCollectionAdmin(address admin) external;
+
+ /// @dev EVM selector for this function is: 0x0b9f3890,
+ /// or in textual repr: setCollectionNesting((bool,bool,address[]))
+ function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
+
+ // /// Toggle accessibility of collection nesting.
+ // ///
+ // /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+ // /// @dev EVM selector for this function is: 0x112d4586,
+ // /// or in textual repr: setCollectionNesting(bool)
+ // function setCollectionNesting(bool enable) external;
+
+ // /// Toggle accessibility of collection nesting.
+ // ///
+ // /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+ // /// @param collections Addresses of collections that will be available for nesting.
+ // /// @dev EVM selector for this function is: 0x64872396,
+ // /// or in textual repr: setCollectionNesting(bool,address[])
+ // function setCollectionNesting(bool enable, address[] memory collections) external;
+
+ /// @dev EVM selector for this function is: 0x92c660a8,
+ /// or in textual repr: collectionNesting()
+ function collectionNesting() external view returns (CollectionNestingAndPermission memory);
+
+ // /// Returns nesting for a collection
+ // /// @dev EVM selector for this function is: 0x22d25bfe,
+ // /// or in textual repr: collectionNestingRestrictedCollectionIds()
+ // function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
+
+ // /// Returns permissions for a collection
+ // /// @dev EVM selector for this function is: 0x5b2eaf4b,
+ // /// or in textual repr: collectionNestingPermissions()
+ // function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
+
+ /// Set the collection access method.
+ /// @param mode Access mode
+ /// @dev EVM selector for this function is: 0x41835d4c,
+ /// or in textual repr: setCollectionAccess(uint8)
+ function setCollectionAccess(AccessMode mode) external;
+
+ /// Checks that user allowed to operate with collection.
+ ///
+ /// @param user User address to check.
+ /// @dev EVM selector for this function is: 0x91b6df49,
+ /// or in textual repr: allowlistedCross((address,uint256))
+ function allowlistedCross(CrossAddress memory user) external view returns (bool);
+
+ // /// Add the user to the allowed list.
+ // ///
+ // /// @param user Address of a trusted user.
+ // /// @dev EVM selector for this function is: 0x67844fe6,
+ // /// or in textual repr: addToCollectionAllowList(address)
+ // function addToCollectionAllowList(address user) external;
+
+ /// Add user to allowed list.
+ ///
+ /// @param user User cross account address.
+ /// @dev EVM selector for this function is: 0xa0184a3a,
+ /// or in textual repr: addToCollectionAllowListCross((address,uint256))
+ function addToCollectionAllowListCross(CrossAddress memory user) external;
+
+ // /// Remove the user from the allowed list.
+ // ///
+ // /// @param user Address of a removed user.
+ // /// @dev EVM selector for this function is: 0x85c51acb,
+ // /// or in textual repr: removeFromCollectionAllowList(address)
+ // function removeFromCollectionAllowList(address user) external;
+
+ /// Remove user from allowed list.
+ ///
+ /// @param user User cross account address.
+ /// @dev EVM selector for this function is: 0x09ba452a,
+ /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))
+ function removeFromCollectionAllowListCross(CrossAddress memory user) external;
+
+ /// Switch permission for minting.
+ ///
+ /// @param mode Enable if "true".
+ /// @dev EVM selector for this function is: 0x00018e84,
+ /// or in textual repr: setCollectionMintMode(bool)
+ function setCollectionMintMode(bool mode) external;
+
+ // /// Check that account is the owner or admin of the collection
+ // ///
+ // /// @param user account to verify
+ // /// @return "true" if account is the owner or admin
+ // /// @dev EVM selector for this function is: 0x9811b0c7,
+ // /// or in textual repr: isOwnerOrAdmin(address)
+ // function isOwnerOrAdmin(address user) external view returns (bool);
+
+ /// Check that account is the owner or admin of the collection
+ ///
+ /// @param user User cross account to verify
+ /// @return "true" if account is the owner or admin
+ /// @dev EVM selector for this function is: 0x3e75a905,
+ /// or in textual repr: isOwnerOrAdminCross((address,uint256))
+ function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
+
+ /// Returns collection type
+ ///
+ /// @return `Fungible` or `NFT` or `ReFungible`
+ /// @dev EVM selector for this function is: 0xd34b55b8,
+ /// or in textual repr: uniqueCollectionType()
+ function uniqueCollectionType() external view returns (string memory);
+
+ /// Get collection owner.
+ ///
+ /// @return Tuble with sponsor address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0xdf727d3b,
+ /// or in textual repr: collectionOwner()
+ function collectionOwner() external view returns (CrossAddress memory);
+
+ // /// Changes collection owner to another account
+ // ///
+ // /// @dev Owner can be changed only by current owner
+ // /// @param newOwner new owner account
+ // /// @dev EVM selector for this function is: 0x4f53e226,
+ // /// or in textual repr: changeCollectionOwner(address)
+ // function changeCollectionOwner(address newOwner) external;
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() external view returns (CrossAddress[] memory);
+
+ /// Changes collection owner to another account
+ ///
+ /// @dev Owner can be changed only by current owner
+ /// @param newOwner new owner cross account
+ /// @dev EVM selector for this function is: 0x6496c497,
+ /// or in textual repr: changeCollectionOwnerCross((address,uint256))
+ function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+ /// Access grant for owner and admins. Used as default.
+ Normal,
+ /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+ AllowList
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+struct CollectionNestingPermission {
+ CollectionPermissionField field;
+ bool value;
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+enum CollectionPermissionField {
+ /// Owner of token can nest tokens under it.
+ TokenOwner,
+ /// Admin of token collection can nest tokens under token.
+ CollectionAdmin
+}
+
+/// Nested collections.
+struct CollectionNesting {
+ bool token_owner;
+ uint256[] ids;
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+ /// Owner of token can nest tokens under it.
+ bool token_owner;
+ /// Admin of token collection can nest tokens under token.
+ bool collection_admin;
+ /// If set - only tokens from specified collections can be nested.
+ address[] restricted;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimit {
+ CollectionLimitField field;
+ OptionUint256 value;
+}
+
+/// Optional value
+struct OptionUint256 {
+ /// Shows the status of accessibility of value
+ bool status;
+ /// Actual value if `status` is true
+ uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+ /// How many tokens can a user have on one account.
+ AccountTokenOwnership,
+ /// How many bytes of data are available for sponsorship.
+ SponsoredDataSize,
+ /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+ SponsoredDataRateLimit,
+ /// How many tokens can be mined into this collection.
+ TokenLimit,
+ /// Timeouts for transfer sponsoring.
+ SponsorTransferTimeout,
+ /// Timeout for sponsoring an approval in passed blocks.
+ SponsorApproveTimeout,
+ /// Whether the collection owner of the collection can send tokens (which belong to other users).
+ OwnerCanTransfer,
+ /// Can the collection owner burn other people's tokens.
+ OwnerCanDestroy,
+ /// Is it possible to send tokens from this collection between users.
+ TransferEnabled
+}
+
+/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
+/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
+interface ERC721Metadata is Dummy, ERC165 {
+ // /// @notice A descriptive name for a collection of NFTs in this contract
+ // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+ // /// @dev EVM selector for this function is: 0x06fdde03,
+ // /// or in textual repr: name()
+ // function name() external view returns (string memory);
+
+ // /// @notice An abbreviated name for NFTs in this contract
+ // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+ // /// @dev EVM selector for this function is: 0x95d89b41,
+ // /// or in textual repr: symbol()
+ // function symbol() external view returns (string memory);
+
+ /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+ ///
+ /// @dev If the token has a `url` property and it is not empty, it is returned.
+ /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
+ /// If the collection property `baseURI` is empty or absent, return "" (empty string)
+ /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
+ /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
+ ///
+ /// @return token's const_metadata
+ /// @dev EVM selector for this function is: 0xc87b56dd,
+ /// or in textual repr: tokenURI(uint256)
+ function tokenURI(uint256 tokenId) external view returns (string memory);
+}
+
+/// @title ERC721 Token that can be irreversibly burned (destroyed).
+/// @dev the ERC-165 identifier for this interface is 0x42966c68
+interface ERC721Burnable is Dummy, ERC165 {
+ /// @notice Burns a specific ERC721 token.
+ /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+ /// operator of the current owner.
+ /// @param tokenId The NFT to approve
+ /// @dev EVM selector for this function is: 0x42966c68,
+ /// or in textual repr: burn(uint256)
+ function burn(uint256 tokenId) external;
+}
+
+/// @title ERC721 minting logic.
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+interface ERC721UniqueMintable is Dummy, ERC165 {
+ /// @notice Function to mint a token.
+ /// @param to The new owner
+ /// @return uint256 The id of the newly minted token
+ /// @dev EVM selector for this function is: 0x6a627842,
+ /// or in textual repr: mint(address)
+ function mint(address to) external returns (uint256);
+
+ // /// @notice Function to mint a token.
+ // /// @dev `tokenId` should be obtained with `nextTokenId` method,
+ // /// unlike standard, you can't specify it manually
+ // /// @param to The new owner
+ // /// @param tokenId ID of the minted NFT
+ // /// @dev EVM selector for this function is: 0x40c10f19,
+ // /// or in textual repr: mint(address,uint256)
+ // function mint(address to, uint256 tokenId) external returns (bool);
+
+ /// @notice Function to mint token with the given tokenUri.
+ /// @param to The new owner
+ /// @param tokenUri Token URI that would be stored in the NFT properties
+ /// @return uint256 The id of the newly minted token
+ /// @dev EVM selector for this function is: 0x45c17782,
+ /// or in textual repr: mintWithTokenURI(address,string)
+ function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
+ // /// @notice Function to mint token with the given tokenUri.
+ // /// @dev `tokenId` should be obtained with `nextTokenId` method,
+ // /// unlike standard, you can't specify it manually
+ // /// @param to The new owner
+ // /// @param tokenId ID of the minted NFT
+ // /// @param tokenUri Token URI that would be stored in the NFT properties
+ // /// @dev EVM selector for this function is: 0x50bb4e7f,
+ // /// or in textual repr: mintWithTokenURI(address,uint256,string)
+ // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
+
+}
+
+/// @title Unique extensions for ERC721.
+/// @dev the ERC-165 identifier for this interface is 0x9b397d16
+interface ERC721UniqueExtensions is Dummy, ERC165 {
+ /// @notice A descriptive name for a collection of NFTs in this contract
+ /// @dev EVM selector for this function is: 0x06fdde03,
+ /// or in textual repr: name()
+ function name() external view returns (string memory);
+
+ /// @notice An abbreviated name for NFTs in this contract
+ /// @dev EVM selector for this function is: 0x95d89b41,
+ /// or in textual repr: symbol()
+ function symbol() external view returns (string memory);
+
+ /// @notice A description for the collection.
+ /// @dev EVM selector for this function is: 0x7284e416,
+ /// or in textual repr: description()
+ function description() external view returns (string memory);
+
+ // /// Returns the owner (in cross format) of the token.
+ // ///
+ // /// @param tokenId Id for the token.
+ // /// @dev EVM selector for this function is: 0x2b29dace,
+ // /// or in textual repr: crossOwnerOf(uint256)
+ // function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
+
+ /// Returns the owner (in cross format) of the token.
+ ///
+ /// @param tokenId Id for the token.
+ /// @dev EVM selector for this function is: 0xcaa3a4d0,
+ /// or in textual repr: ownerOfCross(uint256)
+ function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
+
+ /// @notice Count all NFTs assigned to an owner
+ /// @param owner An cross address for whom to query the balance
+ /// @return The number of NFTs owned by `owner`, possibly zero
+ /// @dev EVM selector for this function is: 0xec069398,
+ /// or in textual repr: balanceOfCross((address,uint256))
+ function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+ /// Returns the token properties.
+ ///
+ /// @param tokenId Id for the token.
+ /// @param keys Properties keys. Empty keys for all propertyes.
+ /// @return Vector of properties key/value pairs.
+ /// @dev EVM selector for this function is: 0xe07ede7e,
+ /// or in textual repr: properties(uint256,string[])
+ function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
+
+ /// @notice Set or reaffirm the approved address for an NFT
+ /// @dev The zero address indicates there is no approved address.
+ /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+ /// operator of the current owner.
+ /// @param approved The new substrate address approved NFT controller
+ /// @param tokenId The NFT to approve
+ /// @dev EVM selector for this function is: 0x0ecd0ab0,
+ /// or in textual repr: approveCross((address,uint256),uint256)
+ function approveCross(CrossAddress memory approved, uint256 tokenId) external;
+
+ /// @notice Transfer ownership of an NFT
+ /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+ /// is the zero address. Throws if `tokenId` is not a valid NFT.
+ /// @param to The new owner
+ /// @param tokenId The NFT to transfer
+ /// @dev EVM selector for this function is: 0xa9059cbb,
+ /// or in textual repr: transfer(address,uint256)
+ function transfer(address to, uint256 tokenId) external;
+
+ /// @notice Transfer ownership of an NFT
+ /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+ /// is the zero address. Throws if `tokenId` is not a valid NFT.
+ /// @param to The new owner
+ /// @param tokenId The NFT to transfer
+ /// @dev EVM selector for this function is: 0x2ada85ff,
+ /// or in textual repr: transferCross((address,uint256),uint256)
+ function transferCross(CrossAddress memory to, uint256 tokenId) external;
+
+ /// @notice Transfer ownership of an NFT from cross account address to cross account address
+ /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+ /// is the zero address. Throws if `tokenId` is not a valid NFT.
+ /// @param from Cross acccount address of current owner
+ /// @param to Cross acccount address of new owner
+ /// @param tokenId The NFT to transfer
+ /// @dev EVM selector for this function is: 0xd5cf430b,
+ /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+ function transferFromCross(
+ CrossAddress memory from,
+ CrossAddress memory to,
+ uint256 tokenId
+ ) external;
+
+ // /// @notice Burns a specific ERC721 token.
+ // /// @dev Throws unless `msg.sender` is the current owner or an authorized
+ // /// operator for this NFT. Throws if `from` is not the current owner. Throws
+ // /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+ // /// @param from The current owner of the NFT
+ // /// @param tokenId The NFT to transfer
+ // /// @dev EVM selector for this function is: 0x79cc6790,
+ // /// or in textual repr: burnFrom(address,uint256)
+ // function burnFrom(address from, uint256 tokenId) external;
+
+ /// @notice Burns a specific ERC721 token.
+ /// @dev Throws unless `msg.sender` is the current owner or an authorized
+ /// operator for this NFT. Throws if `from` is not the current owner. Throws
+ /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+ /// @param from The current owner of the NFT
+ /// @param tokenId The NFT to transfer
+ /// @dev EVM selector for this function is: 0xbb2f5a58,
+ /// or in textual repr: burnFromCross((address,uint256),uint256)
+ function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
+
+ /// @notice Returns next free NFT ID.
+ /// @dev EVM selector for this function is: 0x75794a3c,
+ /// or in textual repr: nextTokenId()
+ function nextTokenId() external view returns (uint256);
+
+ // /// @notice Function to mint multiple tokens.
+ // /// @dev `tokenIds` should be an array of consecutive numbers and first number
+ // /// should be obtained with `nextTokenId` method
+ // /// @param to The new owner
+ // /// @param tokenIds IDs of the minted NFTs
+ // /// @dev EVM selector for this function is: 0x44a9945e,
+ // /// or in textual repr: mintBulk(address,uint256[])
+ // function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
+
+ /// @notice Function to mint a token.
+ /// @param data Array of pairs of token owner and token's properties for minted token
+ /// @dev EVM selector for this function is: 0xab427b0c,
+ /// or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[])
+ function mintBulkCross(MintTokenData[] memory data) external returns (bool);
+
+ // /// @notice Function to mint multiple tokens with the given tokenUris.
+ // /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+ // /// numbers and first number should be obtained with `nextTokenId` method
+ // /// @param to The new owner
+ // /// @param tokens array of pairs of token ID and token URI for minted tokens
+ // /// @dev EVM selector for this function is: 0x36543006,
+ // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
+ // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
+
+ /// @notice Function to mint a token.
+ /// @param to The new owner crossAccountId
+ /// @param properties Properties of minted token
+ /// @return uint256 The id of the newly minted token
+ /// @dev EVM selector for this function is: 0xb904db03,
+ /// or in textual repr: mintCross((address,uint256),(string,bytes)[])
+ function mintCross(CrossAddress memory to, Property[] memory properties) external returns (uint256);
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() external view returns (address);
+}
+
+/// Data for creation token with uri.
+struct TokenUri {
+ /// Id of new token.
+ uint256 id;
+ /// Uri of new token.
+ string uri;
+}
+
+/// Token minting parameters
+struct MintTokenData {
+ /// Minted token owner
+ CrossAddress owner;
+ /// Minted token properties
+ Property[] properties;
+}
+
+/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
+/// @dev the ERC-165 identifier for this interface is 0x780e9d63
+interface ERC721Enumerable is Dummy, ERC165 {
+ /// @notice Enumerate valid NFTs
+ /// @param index A counter less than `totalSupply()`
+ /// @return The token identifier for the `index`th NFT,
+ /// (sort order not specified)
+ /// @dev EVM selector for this function is: 0x4f6ccce7,
+ /// or in textual repr: tokenByIndex(uint256)
+ function tokenByIndex(uint256 index) external view returns (uint256);
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0x2f745c59,
+ /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
+ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
+
+ /// @notice Count NFTs tracked by this contract
+ /// @return A count of valid NFTs tracked by this contract, where each one of
+ /// them has an assigned and queryable owner not equal to the zero address
+ /// @dev EVM selector for this function is: 0x18160ddd,
+ /// or in textual repr: totalSupply()
+ function totalSupply() external view returns (uint256);
+}
+
+/// @dev inlined interface
+interface ERC721Events {
+ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+ event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+}
+
+/// @title ERC-721 Non-Fungible Token Standard
+/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
+/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+interface ERC721 is Dummy, ERC165, ERC721Events {
+ /// @notice Count all NFTs assigned to an owner
+ /// @dev NFTs assigned to the zero address are considered invalid, and this
+ /// function throws for queries about the zero address.
+ /// @param owner An address for whom to query the balance
+ /// @return The number of NFTs owned by `owner`, possibly zero
+ /// @dev EVM selector for this function is: 0x70a08231,
+ /// or in textual repr: balanceOf(address)
+ function balanceOf(address owner) external view returns (uint256);
+
+ /// @notice Find the owner of an NFT
+ /// @dev NFTs assigned to zero address are considered invalid, and queries
+ /// about them do throw.
+ /// @param tokenId The identifier for an NFT
+ /// @return The address of the owner of the NFT
+ /// @dev EVM selector for this function is: 0x6352211e,
+ /// or in textual repr: ownerOf(uint256)
+ function ownerOf(uint256 tokenId) external view returns (address);
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0xb88d4fde,
+ /// or in textual repr: safeTransferFrom(address,address,uint256,bytes)
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) external;
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0x42842e0e,
+ /// or in textual repr: safeTransferFrom(address,address,uint256)
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+ /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+ /// THEY MAY BE PERMANENTLY LOST
+ /// @dev Throws unless `msg.sender` is the current owner or an authorized
+ /// operator for this NFT. Throws if `from` is not the current owner. Throws
+ /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+ /// @param from The current owner of the NFT
+ /// @param to The new owner
+ /// @param tokenId The NFT to transfer
+ /// @dev EVM selector for this function is: 0x23b872dd,
+ /// or in textual repr: transferFrom(address,address,uint256)
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /// @notice Set or reaffirm the approved address for an NFT
+ /// @dev The zero address indicates there is no approved address.
+ /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+ /// operator of the current owner.
+ /// @param approved The new approved NFT controller
+ /// @param tokenId The NFT to approve
+ /// @dev EVM selector for this function is: 0x095ea7b3,
+ /// or in textual repr: approve(address,uint256)
+ function approve(address approved, uint256 tokenId) external;
+
+ /// @notice Sets or unsets the approval of a given operator.
+ /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf.
+ /// @param operator Operator
+ /// @param approved Should operator status be granted or revoked?
+ /// @dev EVM selector for this function is: 0xa22cb465,
+ /// or in textual repr: setApprovalForAll(address,bool)
+ function setApprovalForAll(address operator, bool approved) external;
+
+ /// @notice Get the approved address for a single NFT
+ /// @dev Throws if `tokenId` is not a valid NFT
+ /// @param tokenId The NFT to find the approved address for
+ /// @return The approved address for this NFT, or the zero address if there is none
+ /// @dev EVM selector for this function is: 0x081812fc,
+ /// or in textual repr: getApproved(uint256)
+ function getApproved(uint256 tokenId) external view returns (address);
+
+ /// @notice Tells whether the given `owner` approves the `operator`.
+ /// @dev EVM selector for this function is: 0xe985e9c5,
+ /// or in textual repr: isApprovedForAll(address,address)
+ function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
+
+interface UniqueNFT is
+ Dummy,
+ ERC165,
+ ERC721,
+ ERC721Enumerable,
+ ERC721UniqueExtensions,
+ ERC721UniqueMintable,
+ ERC721Burnable,
+ ERC721Metadata,
+ Collection,
+ TokenProperties
+{}
js-packages/tests/eth/api/UniqueNativeFungible.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/UniqueNativeFungible.sol
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x1313556c
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+ /// @dev EVM selector for this function is: 0xec069398,
+ /// or in textual repr: balanceOfCross((address,uint256))
+ function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+ /// @dev EVM selector for this function is: 0x2ada85ff,
+ /// or in textual repr: transferCross((address,uint256),uint256)
+ function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0xd5cf430b,
+ /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+ function transferFromCross(
+ CrossAddress memory from,
+ CrossAddress memory to,
+ uint256 amount
+ ) external returns (bool);
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
+
+/// @dev inlined interface
+interface ERC20Events {
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+ /// @dev EVM selector for this function is: 0xdd62ed3e,
+ /// or in textual repr: allowance(address,address)
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ /// @dev EVM selector for this function is: 0x095ea7b3,
+ /// or in textual repr: approve(address,uint256)
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0x70a08231,
+ /// or in textual repr: balanceOf(address)
+ function balanceOf(address owner) external view returns (uint256);
+
+ /// @dev EVM selector for this function is: 0x313ce567,
+ /// or in textual repr: decimals()
+ function decimals() external view returns (uint8);
+
+ /// @dev EVM selector for this function is: 0x06fdde03,
+ /// or in textual repr: name()
+ function name() external view returns (string memory);
+
+ /// @dev EVM selector for this function is: 0x95d89b41,
+ /// or in textual repr: symbol()
+ function symbol() external view returns (string memory);
+
+ /// @dev EVM selector for this function is: 0x18160ddd,
+ /// or in textual repr: totalSupply()
+ function totalSupply() external view returns (uint256);
+
+ /// @dev EVM selector for this function is: 0xa9059cbb,
+ /// or in textual repr: transfer(address,uint256)
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /// @dev EVM selector for this function is: 0x23b872dd,
+ /// or in textual repr: transferFrom(address,address,uint256)
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+}
+
+interface UniqueNativeFungible is Dummy, ERC165, ERC20, ERC20UniqueExtensions {}
js-packages/tests/eth/api/UniqueRefungible.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/UniqueRefungible.sol
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface ERC721TokenEvent {
+ event TokenChanged(uint256 indexed tokenId);
+}
+
+/// @title A contract that allows to set and delete token properties and change token property permissions.
+/// @dev the ERC-165 identifier for this interface is 0xde0695c2
+interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
+ // /// @notice Set permissions for token property.
+ // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+ // /// @param key Property key.
+ // /// @param isMutable Permission to mutate property.
+ // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
+ // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
+ // /// @dev EVM selector for this function is: 0x222d97fa,
+ // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
+ // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
+
+ /// @notice Set permissions for token property.
+ /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+ /// @param permissions Permissions for keys.
+ /// @dev EVM selector for this function is: 0xbd92983a,
+ /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
+ function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
+
+ /// @notice Get permissions for token properties.
+ /// @dev EVM selector for this function is: 0xf23d7790,
+ /// or in textual repr: tokenPropertyPermissions()
+ function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
+
+ // /// @notice Set token property value.
+ // /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ // /// @param tokenId ID of the token.
+ // /// @param key Property key.
+ // /// @param value Property value.
+ // /// @dev EVM selector for this function is: 0x1752d67b,
+ // /// or in textual repr: setProperty(uint256,string,bytes)
+ // function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
+
+ /// @notice Set token properties value.
+ /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ /// @param tokenId ID of the token.
+ /// @param properties settable properties
+ /// @dev EVM selector for this function is: 0x14ed3a6e,
+ /// or in textual repr: setProperties(uint256,(string,bytes)[])
+ function setProperties(uint256 tokenId, Property[] memory properties) external;
+
+ // /// @notice Delete token property value.
+ // /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ // /// @param tokenId ID of the token.
+ // /// @param key Property key.
+ // /// @dev EVM selector for this function is: 0x066111d1,
+ // /// or in textual repr: deleteProperty(uint256,string)
+ // function deleteProperty(uint256 tokenId, string memory key) external;
+
+ /// @notice Delete token properties value.
+ /// @dev Throws error if `msg.sender` has no permission to edit the property.
+ /// @param tokenId ID of the token.
+ /// @param keys Properties key.
+ /// @dev EVM selector for this function is: 0xc472d371,
+ /// or in textual repr: deleteProperties(uint256,string[])
+ function deleteProperties(uint256 tokenId, string[] memory keys) external;
+
+ /// @notice Get token property value.
+ /// @dev Throws error if key not found
+ /// @param tokenId ID of the token.
+ /// @param key Property key.
+ /// @return Property value bytes
+ /// @dev EVM selector for this function is: 0x7228c327,
+ /// or in textual repr: property(uint256,string)
+ function property(uint256 tokenId, string memory key) external view returns (bytes memory);
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+ string key;
+ bytes value;
+}
+
+/// Ethereum representation of Token Property Permissions.
+struct TokenPropertyPermission {
+ /// Token property key.
+ string key;
+ /// Token property permissions.
+ PropertyPermission[] permissions;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+struct PropertyPermission {
+ /// TokenPermission field.
+ TokenPermissionField code;
+ /// TokenPermission value.
+ bool value;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+enum TokenPermissionField {
+ /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+ Mutable,
+ /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+ TokenOwner,
+ /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+ CollectionAdmin
+}
+
+/// @title A contract that allows you to work with collections.
+/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
+interface Collection is Dummy, ERC165 {
+ // /// Set collection property.
+ // ///
+ // /// @param key Property key.
+ // /// @param value Propery value.
+ // /// @dev EVM selector for this function is: 0x2f073f66,
+ // /// or in textual repr: setCollectionProperty(string,bytes)
+ // function setCollectionProperty(string memory key, bytes memory value) external;
+
+ /// Set collection properties.
+ ///
+ /// @param properties Vector of properties key/value pair.
+ /// @dev EVM selector for this function is: 0x50b26b2a,
+ /// or in textual repr: setCollectionProperties((string,bytes)[])
+ function setCollectionProperties(Property[] memory properties) external;
+
+ // /// Delete collection property.
+ // ///
+ // /// @param key Property key.
+ // /// @dev EVM selector for this function is: 0x7b7debce,
+ // /// or in textual repr: deleteCollectionProperty(string)
+ // function deleteCollectionProperty(string memory key) external;
+
+ /// Delete collection properties.
+ ///
+ /// @param keys Properties keys.
+ /// @dev EVM selector for this function is: 0xee206ee3,
+ /// or in textual repr: deleteCollectionProperties(string[])
+ function deleteCollectionProperties(string[] memory keys) external;
+
+ /// Get collection property.
+ ///
+ /// @dev Throws error if key not found.
+ ///
+ /// @param key Property key.
+ /// @return bytes The property corresponding to the key.
+ /// @dev EVM selector for this function is: 0xcf24fd6d,
+ /// or in textual repr: collectionProperty(string)
+ function collectionProperty(string memory key) external view returns (bytes memory);
+
+ /// Get collection properties.
+ ///
+ /// @param keys Properties keys. Empty keys for all propertyes.
+ /// @return Vector of properties key/value pairs.
+ /// @dev EVM selector for this function is: 0x285fb8e6,
+ /// or in textual repr: collectionProperties(string[])
+ function collectionProperties(string[] memory keys) external view returns (Property[] memory);
+
+ // /// Set the sponsor of the collection.
+ // ///
+ // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+ // ///
+ // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+ // /// @dev EVM selector for this function is: 0x7623402e,
+ // /// or in textual repr: setCollectionSponsor(address)
+ // function setCollectionSponsor(address sponsor) external;
+
+ /// Set the sponsor of the collection.
+ ///
+ /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+ ///
+ /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
+ /// @dev EVM selector for this function is: 0x84a1d5a8,
+ /// or in textual repr: setCollectionSponsorCross((address,uint256))
+ function setCollectionSponsorCross(CrossAddress memory sponsor) external;
+
+ /// Whether there is a pending sponsor.
+ /// @dev EVM selector for this function is: 0x058ac185,
+ /// or in textual repr: hasCollectionPendingSponsor()
+ function hasCollectionPendingSponsor() external view returns (bool);
+
+ /// Collection sponsorship confirmation.
+ ///
+ /// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+ /// @dev EVM selector for this function is: 0x3c50e97a,
+ /// or in textual repr: confirmCollectionSponsorship()
+ function confirmCollectionSponsorship() external;
+
+ /// Remove collection sponsor.
+ /// @dev EVM selector for this function is: 0x6e0326a3,
+ /// or in textual repr: removeCollectionSponsor()
+ function removeCollectionSponsor() external;
+
+ /// Get current sponsor.
+ ///
+ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
+ /// @dev EVM selector for this function is: 0x6ec0a9f1,
+ /// or in textual repr: collectionSponsor()
+ function collectionSponsor() external view returns (CrossAddress memory);
+
+ /// Get current collection limits.
+ ///
+ /// @return Array of collection limits
+ /// @dev EVM selector for this function is: 0xf63bc572,
+ /// or in textual repr: collectionLimits()
+ function collectionLimits() external view returns (CollectionLimit[] memory);
+
+ /// Set limits for the collection.
+ /// @dev Throws error if limit not found.
+ /// @param limit Some limit.
+ /// @dev EVM selector for this function is: 0x2316ee74,
+ /// or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
+ function setCollectionLimit(CollectionLimit memory limit) external;
+
+ /// Get contract address.
+ /// @dev EVM selector for this function is: 0xf6b4dfb4,
+ /// or in textual repr: contractAddress()
+ function contractAddress() external view returns (address);
+
+ /// Add collection admin.
+ /// @param newAdmin Cross account administrator address.
+ /// @dev EVM selector for this function is: 0x859aa7d6,
+ /// or in textual repr: addCollectionAdminCross((address,uint256))
+ function addCollectionAdminCross(CrossAddress memory newAdmin) external;
+
+ /// Remove collection admin.
+ /// @param admin Cross account administrator address.
+ /// @dev EVM selector for this function is: 0x6c0cd173,
+ /// or in textual repr: removeCollectionAdminCross((address,uint256))
+ function removeCollectionAdminCross(CrossAddress memory admin) external;
+
+ // /// Add collection admin.
+ // /// @param newAdmin Address of the added administrator.
+ // /// @dev EVM selector for this function is: 0x92e462c7,
+ // /// or in textual repr: addCollectionAdmin(address)
+ // function addCollectionAdmin(address newAdmin) external;
+
+ // /// Remove collection admin.
+ // ///
+ // /// @param admin Address of the removed administrator.
+ // /// @dev EVM selector for this function is: 0xfafd7b42,
+ // /// or in textual repr: removeCollectionAdmin(address)
+ // function removeCollectionAdmin(address admin) external;
+
+ /// @dev EVM selector for this function is: 0x0b9f3890,
+ /// or in textual repr: setCollectionNesting((bool,bool,address[]))
+ function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
+
+ // /// Toggle accessibility of collection nesting.
+ // ///
+ // /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+ // /// @dev EVM selector for this function is: 0x112d4586,
+ // /// or in textual repr: setCollectionNesting(bool)
+ // function setCollectionNesting(bool enable) external;
+
+ // /// Toggle accessibility of collection nesting.
+ // ///
+ // /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+ // /// @param collections Addresses of collections that will be available for nesting.
+ // /// @dev EVM selector for this function is: 0x64872396,
+ // /// or in textual repr: setCollectionNesting(bool,address[])
+ // function setCollectionNesting(bool enable, address[] memory collections) external;
+
+ /// @dev EVM selector for this function is: 0x92c660a8,
+ /// or in textual repr: collectionNesting()
+ function collectionNesting() external view returns (CollectionNestingAndPermission memory);
+
+ // /// Returns nesting for a collection
+ // /// @dev EVM selector for this function is: 0x22d25bfe,
+ // /// or in textual repr: collectionNestingRestrictedCollectionIds()
+ // function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
+
+ // /// Returns permissions for a collection
+ // /// @dev EVM selector for this function is: 0x5b2eaf4b,
+ // /// or in textual repr: collectionNestingPermissions()
+ // function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
+
+ /// Set the collection access method.
+ /// @param mode Access mode
+ /// @dev EVM selector for this function is: 0x41835d4c,
+ /// or in textual repr: setCollectionAccess(uint8)
+ function setCollectionAccess(AccessMode mode) external;
+
+ /// Checks that user allowed to operate with collection.
+ ///
+ /// @param user User address to check.
+ /// @dev EVM selector for this function is: 0x91b6df49,
+ /// or in textual repr: allowlistedCross((address,uint256))
+ function allowlistedCross(CrossAddress memory user) external view returns (bool);
+
+ // /// Add the user to the allowed list.
+ // ///
+ // /// @param user Address of a trusted user.
+ // /// @dev EVM selector for this function is: 0x67844fe6,
+ // /// or in textual repr: addToCollectionAllowList(address)
+ // function addToCollectionAllowList(address user) external;
+
+ /// Add user to allowed list.
+ ///
+ /// @param user User cross account address.
+ /// @dev EVM selector for this function is: 0xa0184a3a,
+ /// or in textual repr: addToCollectionAllowListCross((address,uint256))
+ function addToCollectionAllowListCross(CrossAddress memory user) external;
+
+ // /// Remove the user from the allowed list.
+ // ///
+ // /// @param user Address of a removed user.
+ // /// @dev EVM selector for this function is: 0x85c51acb,
+ // /// or in textual repr: removeFromCollectionAllowList(address)
+ // function removeFromCollectionAllowList(address user) external;
+
+ /// Remove user from allowed list.
+ ///
+ /// @param user User cross account address.
+ /// @dev EVM selector for this function is: 0x09ba452a,
+ /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))
+ function removeFromCollectionAllowListCross(CrossAddress memory user) external;
+
+ /// Switch permission for minting.
+ ///
+ /// @param mode Enable if "true".
+ /// @dev EVM selector for this function is: 0x00018e84,
+ /// or in textual repr: setCollectionMintMode(bool)
+ function setCollectionMintMode(bool mode) external;
+
+ // /// Check that account is the owner or admin of the collection
+ // ///
+ // /// @param user account to verify
+ // /// @return "true" if account is the owner or admin
+ // /// @dev EVM selector for this function is: 0x9811b0c7,
+ // /// or in textual repr: isOwnerOrAdmin(address)
+ // function isOwnerOrAdmin(address user) external view returns (bool);
+
+ /// Check that account is the owner or admin of the collection
+ ///
+ /// @param user User cross account to verify
+ /// @return "true" if account is the owner or admin
+ /// @dev EVM selector for this function is: 0x3e75a905,
+ /// or in textual repr: isOwnerOrAdminCross((address,uint256))
+ function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
+
+ /// Returns collection type
+ ///
+ /// @return `Fungible` or `NFT` or `ReFungible`
+ /// @dev EVM selector for this function is: 0xd34b55b8,
+ /// or in textual repr: uniqueCollectionType()
+ function uniqueCollectionType() external view returns (string memory);
+
+ /// Get collection owner.
+ ///
+ /// @return Tuble with sponsor address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0xdf727d3b,
+ /// or in textual repr: collectionOwner()
+ function collectionOwner() external view returns (CrossAddress memory);
+
+ // /// Changes collection owner to another account
+ // ///
+ // /// @dev Owner can be changed only by current owner
+ // /// @param newOwner new owner account
+ // /// @dev EVM selector for this function is: 0x4f53e226,
+ // /// or in textual repr: changeCollectionOwner(address)
+ // function changeCollectionOwner(address newOwner) external;
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() external view returns (CrossAddress[] memory);
+
+ /// Changes collection owner to another account
+ ///
+ /// @dev Owner can be changed only by current owner
+ /// @param newOwner new owner cross account
+ /// @dev EVM selector for this function is: 0x6496c497,
+ /// or in textual repr: changeCollectionOwnerCross((address,uint256))
+ function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+ /// Access grant for owner and admins. Used as default.
+ Normal,
+ /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+ AllowList
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+struct CollectionNestingPermission {
+ CollectionPermissionField field;
+ bool value;
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+enum CollectionPermissionField {
+ /// Owner of token can nest tokens under it.
+ TokenOwner,
+ /// Admin of token collection can nest tokens under token.
+ CollectionAdmin
+}
+
+/// Nested collections.
+struct CollectionNesting {
+ bool token_owner;
+ uint256[] ids;
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+ /// Owner of token can nest tokens under it.
+ bool token_owner;
+ /// Admin of token collection can nest tokens under token.
+ bool collection_admin;
+ /// If set - only tokens from specified collections can be nested.
+ address[] restricted;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimit {
+ CollectionLimitField field;
+ OptionUint256 value;
+}
+
+/// Optional value
+struct OptionUint256 {
+ /// Shows the status of accessibility of value
+ bool status;
+ /// Actual value if `status` is true
+ uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+ /// How many tokens can a user have on one account.
+ AccountTokenOwnership,
+ /// How many bytes of data are available for sponsorship.
+ SponsoredDataSize,
+ /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+ SponsoredDataRateLimit,
+ /// How many tokens can be mined into this collection.
+ TokenLimit,
+ /// Timeouts for transfer sponsoring.
+ SponsorTransferTimeout,
+ /// Timeout for sponsoring an approval in passed blocks.
+ SponsorApproveTimeout,
+ /// Whether the collection owner of the collection can send tokens (which belong to other users).
+ OwnerCanTransfer,
+ /// Can the collection owner burn other people's tokens.
+ OwnerCanDestroy,
+ /// Is it possible to send tokens from this collection between users.
+ TransferEnabled
+}
+
+/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
+/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
+interface ERC721Metadata is Dummy, ERC165 {
+ // /// @notice A descriptive name for a collection of NFTs in this contract
+ // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+ // /// @dev EVM selector for this function is: 0x06fdde03,
+ // /// or in textual repr: name()
+ // function name() external view returns (string memory);
+
+ // /// @notice An abbreviated name for NFTs in this contract
+ // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+ // /// @dev EVM selector for this function is: 0x95d89b41,
+ // /// or in textual repr: symbol()
+ // function symbol() external view returns (string memory);
+
+ /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+ ///
+ /// @dev If the token has a `url` property and it is not empty, it is returned.
+ /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
+ /// If the collection property `baseURI` is empty or absent, return "" (empty string)
+ /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
+ /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
+ ///
+ /// @return token's const_metadata
+ /// @dev EVM selector for this function is: 0xc87b56dd,
+ /// or in textual repr: tokenURI(uint256)
+ function tokenURI(uint256 tokenId) external view returns (string memory);
+}
+
+/// @title ERC721 Token that can be irreversibly burned (destroyed).
+/// @dev the ERC-165 identifier for this interface is 0x42966c68
+interface ERC721Burnable is Dummy, ERC165 {
+ /// @notice Burns a specific ERC721 token.
+ /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
+ /// operator of the current owner.
+ /// @param tokenId The RFT to approve
+ /// @dev EVM selector for this function is: 0x42966c68,
+ /// or in textual repr: burn(uint256)
+ function burn(uint256 tokenId) external;
+}
+
+/// @title ERC721 minting logic.
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+interface ERC721UniqueMintable is Dummy, ERC165 {
+ /// @notice Function to mint a token.
+ /// @param to The new owner
+ /// @return uint256 The id of the newly minted token
+ /// @dev EVM selector for this function is: 0x6a627842,
+ /// or in textual repr: mint(address)
+ function mint(address to) external returns (uint256);
+
+ // /// @notice Function to mint a token.
+ // /// @dev `tokenId` should be obtained with `nextTokenId` method,
+ // /// unlike standard, you can't specify it manually
+ // /// @param to The new owner
+ // /// @param tokenId ID of the minted RFT
+ // /// @dev EVM selector for this function is: 0x40c10f19,
+ // /// or in textual repr: mint(address,uint256)
+ // function mint(address to, uint256 tokenId) external returns (bool);
+
+ /// @notice Function to mint token with the given tokenUri.
+ /// @param to The new owner
+ /// @param tokenUri Token URI that would be stored in the NFT properties
+ /// @return uint256 The id of the newly minted token
+ /// @dev EVM selector for this function is: 0x45c17782,
+ /// or in textual repr: mintWithTokenURI(address,string)
+ function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
+ // /// @notice Function to mint token with the given tokenUri.
+ // /// @dev `tokenId` should be obtained with `nextTokenId` method,
+ // /// unlike standard, you can't specify it manually
+ // /// @param to The new owner
+ // /// @param tokenId ID of the minted RFT
+ // /// @param tokenUri Token URI that would be stored in the RFT properties
+ // /// @dev EVM selector for this function is: 0x50bb4e7f,
+ // /// or in textual repr: mintWithTokenURI(address,uint256,string)
+ // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
+
+}
+
+/// @title Unique extensions for ERC721.
+/// @dev the ERC-165 identifier for this interface is 0x4abaabdb
+interface ERC721UniqueExtensions is Dummy, ERC165 {
+ /// @notice A descriptive name for a collection of NFTs in this contract
+ /// @dev EVM selector for this function is: 0x06fdde03,
+ /// or in textual repr: name()
+ function name() external view returns (string memory);
+
+ /// @notice An abbreviated name for NFTs in this contract
+ /// @dev EVM selector for this function is: 0x95d89b41,
+ /// or in textual repr: symbol()
+ function symbol() external view returns (string memory);
+
+ /// @notice A description for the collection.
+ /// @dev EVM selector for this function is: 0x7284e416,
+ /// or in textual repr: description()
+ function description() external view returns (string memory);
+
+ // /// Returns the owner (in cross format) of the token.
+ // ///
+ // /// @param tokenId Id for the token.
+ // /// @dev EVM selector for this function is: 0x2b29dace,
+ // /// or in textual repr: crossOwnerOf(uint256)
+ // function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
+
+ /// Returns the owner (in cross format) of the token.
+ ///
+ /// @param tokenId Id for the token.
+ /// @dev EVM selector for this function is: 0xcaa3a4d0,
+ /// or in textual repr: ownerOfCross(uint256)
+ function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
+
+ /// @notice Count all RFTs assigned to an owner
+ /// @param owner An cross address for whom to query the balance
+ /// @return The number of RFTs owned by `owner`, possibly zero
+ /// @dev EVM selector for this function is: 0xec069398,
+ /// or in textual repr: balanceOfCross((address,uint256))
+ function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+ /// Returns the token properties.
+ ///
+ /// @param tokenId Id for the token.
+ /// @param keys Properties keys. Empty keys for all propertyes.
+ /// @return Vector of properties key/value pairs.
+ /// @dev EVM selector for this function is: 0xe07ede7e,
+ /// or in textual repr: properties(uint256,string[])
+ function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
+
+ /// @notice Transfer ownership of an RFT
+ /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+ /// is the zero address. Throws if `tokenId` is not a valid RFT.
+ /// Throws if RFT pieces have multiple owners.
+ /// @param to The new owner
+ /// @param tokenId The RFT to transfer
+ /// @dev EVM selector for this function is: 0xa9059cbb,
+ /// or in textual repr: transfer(address,uint256)
+ function transfer(address to, uint256 tokenId) external;
+
+ /// @notice Transfer ownership of an RFT
+ /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+ /// is the zero address. Throws if `tokenId` is not a valid RFT.
+ /// Throws if RFT pieces have multiple owners.
+ /// @param to The new owner
+ /// @param tokenId The RFT to transfer
+ /// @dev EVM selector for this function is: 0x2ada85ff,
+ /// or in textual repr: transferCross((address,uint256),uint256)
+ function transferCross(CrossAddress memory to, uint256 tokenId) external;
+
+ /// @notice Transfer ownership of an RFT
+ /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+ /// is the zero address. Throws if `tokenId` is not a valid RFT.
+ /// Throws if RFT pieces have multiple owners.
+ /// @param to The new owner
+ /// @param tokenId The RFT to transfer
+ /// @dev EVM selector for this function is: 0xd5cf430b,
+ /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+ function transferFromCross(
+ CrossAddress memory from,
+ CrossAddress memory to,
+ uint256 tokenId
+ ) external;
+
+ // /// @notice Burns a specific ERC721 token.
+ // /// @dev Throws unless `msg.sender` is the current owner or an authorized
+ // /// operator for this RFT. Throws if `from` is not the current owner. Throws
+ // /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+ // /// Throws if RFT pieces have multiple owners.
+ // /// @param from The current owner of the RFT
+ // /// @param tokenId The RFT to transfer
+ // /// @dev EVM selector for this function is: 0x79cc6790,
+ // /// or in textual repr: burnFrom(address,uint256)
+ // function burnFrom(address from, uint256 tokenId) external;
+
+ /// @notice Burns a specific ERC721 token.
+ /// @dev Throws unless `msg.sender` is the current owner or an authorized
+ /// operator for this RFT. Throws if `from` is not the current owner. Throws
+ /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+ /// Throws if RFT pieces have multiple owners.
+ /// @param from The current owner of the RFT
+ /// @param tokenId The RFT to transfer
+ /// @dev EVM selector for this function is: 0xbb2f5a58,
+ /// or in textual repr: burnFromCross((address,uint256),uint256)
+ function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
+
+ /// @notice Returns next free RFT ID.
+ /// @dev EVM selector for this function is: 0x75794a3c,
+ /// or in textual repr: nextTokenId()
+ function nextTokenId() external view returns (uint256);
+
+ // /// @notice Function to mint multiple tokens.
+ // /// @dev `tokenIds` should be an array of consecutive numbers and first number
+ // /// should be obtained with `nextTokenId` method
+ // /// @param to The new owner
+ // /// @param tokenIds IDs of the minted RFTs
+ // /// @dev EVM selector for this function is: 0x44a9945e,
+ // /// or in textual repr: mintBulk(address,uint256[])
+ // function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
+
+ /// @notice Function to mint a token.
+ /// @param tokenProperties Properties of minted token
+ /// @dev EVM selector for this function is: 0xdf7a5db7,
+ /// or in textual repr: mintBulkCross((((address,uint256),uint128)[],(string,bytes)[])[])
+ function mintBulkCross(MintTokenData[] memory tokenProperties) external returns (bool);
+
+ // /// @notice Function to mint multiple tokens with the given tokenUris.
+ // /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+ // /// numbers and first number should be obtained with `nextTokenId` method
+ // /// @param to The new owner
+ // /// @param tokens array of pairs of token ID and token URI for minted tokens
+ // /// @dev EVM selector for this function is: 0x36543006,
+ // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
+ // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
+
+ /// @notice Function to mint a token.
+ /// @param to The new owner crossAccountId
+ /// @param properties Properties of minted token
+ /// @return uint256 The id of the newly minted token
+ /// @dev EVM selector for this function is: 0xb904db03,
+ /// or in textual repr: mintCross((address,uint256),(string,bytes)[])
+ function mintCross(CrossAddress memory to, Property[] memory properties) external returns (uint256);
+
+ /// Returns EVM address for refungible token
+ ///
+ /// @param token ID of the token
+ /// @dev EVM selector for this function is: 0xab76fac6,
+ /// or in textual repr: tokenContractAddress(uint256)
+ function tokenContractAddress(uint256 token) external view returns (address);
+
+ /// @notice Returns collection helper contract address
+ /// @dev EVM selector for this function is: 0x1896cce6,
+ /// or in textual repr: collectionHelperAddress()
+ function collectionHelperAddress() external view returns (address);
+}
+
+/// Data for creation token with uri.
+struct TokenUri {
+ /// Id of new token.
+ uint256 id;
+ /// Uri of new token.
+ string uri;
+}
+
+/// Token minting parameters
+struct MintTokenData {
+ /// Minted token owner and number of pieces
+ OwnerPieces[] owners;
+ /// Minted token properties
+ Property[] properties;
+}
+
+/// Token minting parameters
+struct OwnerPieces {
+ /// Minted token owner
+ CrossAddress owner;
+ /// Number of token pieces
+ uint128 pieces;
+}
+
+/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
+/// @dev the ERC-165 identifier for this interface is 0x780e9d63
+interface ERC721Enumerable is Dummy, ERC165 {
+ /// @notice Enumerate valid RFTs
+ /// @param index A counter less than `totalSupply()`
+ /// @return The token identifier for the `index`th NFT,
+ /// (sort order not specified)
+ /// @dev EVM selector for this function is: 0x4f6ccce7,
+ /// or in textual repr: tokenByIndex(uint256)
+ function tokenByIndex(uint256 index) external view returns (uint256);
+
+ /// Not implemented
+ /// @dev EVM selector for this function is: 0x2f745c59,
+ /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
+ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
+
+ /// @notice Count RFTs tracked by this contract
+ /// @return A count of valid RFTs tracked by this contract, where each one of
+ /// them has an assigned and queryable owner not equal to the zero address
+ /// @dev EVM selector for this function is: 0x18160ddd,
+ /// or in textual repr: totalSupply()
+ function totalSupply() external view returns (uint256);
+}
+
+/// @dev inlined interface
+interface ERC721Events {
+ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+ event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+}
+
+/// @title ERC-721 Non-Fungible Token Standard
+/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
+/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+interface ERC721 is Dummy, ERC165, ERC721Events {
+ /// @notice Count all RFTs assigned to an owner
+ /// @dev RFTs assigned to the zero address are considered invalid, and this
+ /// function throws for queries about the zero address.
+ /// @param owner An address for whom to query the balance
+ /// @return The number of RFTs owned by `owner`, possibly zero
+ /// @dev EVM selector for this function is: 0x70a08231,
+ /// or in textual repr: balanceOf(address)
+ function balanceOf(address owner) external view returns (uint256);
+
+ /// @notice Find the owner of an RFT
+ /// @dev RFTs assigned to zero address are considered invalid, and queries
+ /// about them do throw.
+ /// Returns special 0xffffffffffffffffffffffffffffffffffffffff address for
+ /// the tokens that are partially owned.
+ /// @param tokenId The identifier for an RFT
+ /// @return The address of the owner of the RFT
+ /// @dev EVM selector for this function is: 0x6352211e,
+ /// or in textual repr: ownerOf(uint256)
+ function ownerOf(uint256 tokenId) external view returns (address);
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0xb88d4fde,
+ /// or in textual repr: safeTransferFrom(address,address,uint256,bytes)
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) external;
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0x42842e0e,
+ /// or in textual repr: safeTransferFrom(address,address,uint256)
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE
+ /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+ /// THEY MAY BE PERMANENTLY LOST
+ /// @dev Throws unless `msg.sender` is the current owner or an authorized
+ /// operator for this RFT. Throws if `from` is not the current owner. Throws
+ /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+ /// Throws if RFT pieces have multiple owners.
+ /// @param from The current owner of the NFT
+ /// @param to The new owner
+ /// @param tokenId The NFT to transfer
+ /// @dev EVM selector for this function is: 0x23b872dd,
+ /// or in textual repr: transferFrom(address,address,uint256)
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external;
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0x095ea7b3,
+ /// or in textual repr: approve(address,uint256)
+ function approve(address approved, uint256 tokenId) external;
+
+ /// @notice Sets or unsets the approval of a given operator.
+ /// The `operator` is allowed to transfer all token pieces of the `caller` on their behalf.
+ /// @param operator Operator
+ /// @param approved Should operator status be granted or revoked?
+ /// @dev EVM selector for this function is: 0xa22cb465,
+ /// or in textual repr: setApprovalForAll(address,bool)
+ function setApprovalForAll(address operator, bool approved) external;
+
+ /// @dev Not implemented
+ /// @dev EVM selector for this function is: 0x081812fc,
+ /// or in textual repr: getApproved(uint256)
+ function getApproved(uint256 tokenId) external view returns (address);
+
+ /// @notice Tells whether the given `owner` approves the `operator`.
+ /// @dev EVM selector for this function is: 0xe985e9c5,
+ /// or in textual repr: isApprovedForAll(address,address)
+ function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
+
+interface UniqueRefungible is
+ Dummy,
+ ERC165,
+ ERC721,
+ ERC721Enumerable,
+ ERC721UniqueExtensions,
+ ERC721UniqueMintable,
+ ERC721Burnable,
+ ERC721Metadata,
+ Collection,
+ TokenProperties
+{}
js-packages/tests/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/api/UniqueRefungibleToken.sol
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x5755c3f2
+interface ERC1633 is Dummy, ERC165 {
+ /// @dev EVM selector for this function is: 0x80a54001,
+ /// or in textual repr: parentToken()
+ function parentToken() external view returns (address);
+
+ /// @dev EVM selector for this function is: 0xd7f083f3,
+ /// or in textual repr: parentTokenId()
+ function parentTokenId() external view returns (uint256);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0xedd3a564
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+ /// @dev Function to check the amount of tokens that an owner allowed to a spender.
+ /// @param owner crossAddress The address which owns the funds.
+ /// @param spender crossAddress The address which will spend the funds.
+ /// @return A uint256 specifying the amount of tokens still available for the spender.
+ /// @dev EVM selector for this function is: 0xe0af4bd7,
+ /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
+ function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
+
+ // /// @dev Function that burns an amount of the token of a given account,
+ // /// deducting from the sender's allowance for said account.
+ // /// @param from The account whose tokens will be burnt.
+ // /// @param amount The amount that will be burnt.
+ // /// @dev EVM selector for this function is: 0x79cc6790,
+ // /// or in textual repr: burnFrom(address,uint256)
+ // function burnFrom(address from, uint256 amount) external returns (bool);
+
+ /// @dev Function that burns an amount of the token of a given account,
+ /// deducting from the sender's allowance for said account.
+ /// @param from The account whose tokens will be burnt.
+ /// @param amount The amount that will be burnt.
+ /// @dev EVM selector for this function is: 0xbb2f5a58,
+ /// or in textual repr: burnFromCross((address,uint256),uint256)
+ function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
+
+ /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
+ /// Beware that changing an allowance with this method brings the risk that someone may use both the old
+ /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
+ /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
+ /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ /// @param spender The crossaccount which will spend the funds.
+ /// @param amount The amount of tokens to be spent.
+ /// @dev EVM selector for this function is: 0x0ecd0ab0,
+ /// or in textual repr: approveCross((address,uint256),uint256)
+ function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
+
+ /// @notice Balance of account
+ /// @param owner An cross address for whom to query the balance
+ /// @return The number of fingibles owned by `owner`, possibly zero
+ /// @dev EVM selector for this function is: 0xec069398,
+ /// or in textual repr: balanceOfCross((address,uint256))
+ function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+ /// @dev Function that changes total amount of the tokens.
+ /// Throws if `msg.sender` doesn't owns all of the tokens.
+ /// @param amount New total amount of the tokens.
+ /// @dev EVM selector for this function is: 0xd2418ca7,
+ /// or in textual repr: repartition(uint256)
+ function repartition(uint256 amount) external returns (bool);
+
+ /// @dev Transfer token for a specified address
+ /// @param to The crossaccount to transfer to.
+ /// @param amount The amount to be transferred.
+ /// @dev EVM selector for this function is: 0x2ada85ff,
+ /// or in textual repr: transferCross((address,uint256),uint256)
+ function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+ /// @dev Transfer tokens from one address to another
+ /// @param from The address which you want to send tokens from
+ /// @param to The address which you want to transfer to
+ /// @param amount the amount of tokens to be transferred
+ /// @dev EVM selector for this function is: 0xd5cf430b,
+ /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+ function transferFromCross(
+ CrossAddress memory from,
+ CrossAddress memory to,
+ uint256 amount
+ ) external returns (bool);
+}
+
+/// Cross account struct
+struct CrossAddress {
+ address eth;
+ uint256 sub;
+}
+
+/// @dev inlined interface
+interface ERC20Events {
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+/// @title Standard ERC20 token
+///
+/// @dev Implementation of the basic standard token.
+/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
+/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+ /// @return the name of the token.
+ /// @dev EVM selector for this function is: 0x06fdde03,
+ /// or in textual repr: name()
+ function name() external view returns (string memory);
+
+ /// @return the symbol of the token.
+ /// @dev EVM selector for this function is: 0x95d89b41,
+ /// or in textual repr: symbol()
+ function symbol() external view returns (string memory);
+
+ /// @dev Total number of tokens in existence
+ /// @dev EVM selector for this function is: 0x18160ddd,
+ /// or in textual repr: totalSupply()
+ function totalSupply() external view returns (uint256);
+
+ /// @dev Not supported
+ /// @dev EVM selector for this function is: 0x313ce567,
+ /// or in textual repr: decimals()
+ function decimals() external view returns (uint8);
+
+ /// @dev Gets the balance of the specified address.
+ /// @param owner The address to query the balance of.
+ /// @return An uint256 representing the amount owned by the passed address.
+ /// @dev EVM selector for this function is: 0x70a08231,
+ /// or in textual repr: balanceOf(address)
+ function balanceOf(address owner) external view returns (uint256);
+
+ /// @dev Transfer token for a specified address
+ /// @param to The address to transfer to.
+ /// @param amount The amount to be transferred.
+ /// @dev EVM selector for this function is: 0xa9059cbb,
+ /// or in textual repr: transfer(address,uint256)
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ /// @dev Transfer tokens from one address to another
+ /// @param from address The address which you want to send tokens from
+ /// @param to address The address which you want to transfer to
+ /// @param amount uint256 the amount of tokens to be transferred
+ /// @dev EVM selector for this function is: 0x23b872dd,
+ /// or in textual repr: transferFrom(address,address,uint256)
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+
+ /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
+ /// Beware that changing an allowance with this method brings the risk that someone may use both the old
+ /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
+ /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
+ /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ /// @param spender The address which will spend the funds.
+ /// @param amount The amount of tokens to be spent.
+ /// @dev EVM selector for this function is: 0x095ea7b3,
+ /// or in textual repr: approve(address,uint256)
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ /// @dev Function to check the amount of tokens that an owner allowed to a spender.
+ /// @param owner address The address which owns the funds.
+ /// @param spender address The address which will spend the funds.
+ /// @return A uint256 specifying the amount of tokens still available for the spender.
+ /// @dev EVM selector for this function is: 0xdd62ed3e,
+ /// or in textual repr: allowance(address,address)
+ function allowance(address owner, address spender) external view returns (uint256);
+}
+
+interface UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions, ERC1633 {}
js-packages/tests/eth/base.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/base.test.ts
@@ -0,0 +1,127 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+
+
+describe('Contract calls', () => {
+ let donor: IKeyringPair;
+
+ before(async function () {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Call of simple contract fee is less than 0.2 UNQ', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const flipper = await helper.eth.deployFlipper(deployer);
+
+ const cost = await helper.eth.calculateFee({Ethereum: deployer}, () => flipper.methods.flip().send({from: deployer}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
+ });
+
+ itEth('Balance transfer fee is less than 0.2 UNQ', async ({helper}) => {
+ const userA = await helper.eth.createAccountWithBalance(donor);
+ const userB = helper.eth.createAccount();
+ const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({
+ from: userA,
+ to: userB,
+ value: '1000000',
+ gas: helper.eth.DEFAULT_GAS,
+ }));
+ const balanceB = await helper.balance.getEthereum(userB);
+ expect(cost - balanceB < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
+ });
+
+ itEth('NFT transfer is close to 0.15 UNQ', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, tokenId).send(caller));
+
+ const fee = Number(cost) / Number(helper.balance.getOneTokenNominal());
+ const expectedFee = 0.15;
+ const tolerance = 0.001;
+
+ expect(Math.abs(fee - expectedFee)).to.be.lessThan(tolerance);
+ });
+});
+
+describe('ERC165 tests', () => {
+ // https://eips.ethereum.org/EIPS/eip-165
+
+ let erc721MetadataCompatibleNftCollectionId: number;
+ let simpleNftCollectionId: number;
+ let minter: string;
+
+ const BASE_URI = 'base/';
+
+ async function checkInterface(helper: EthUniqueHelper, interfaceId: string, simpleResult: boolean, compatibleResult: boolean) {
+ const simple = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(simpleNftCollectionId), 'nft', minter);
+ const compatible = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(erc721MetadataCompatibleNftCollectionId), 'nft', minter);
+
+ expect(await simple.methods.supportsInterface(interfaceId).call()).to.equal(simpleResult, `empty (not ERC721Metadata compatible) NFT collection returns not ${simpleResult}`);
+ expect(await compatible.methods.supportsInterface(interfaceId).call()).to.equal(compatibleResult, `ERC721Metadata compatible NFT collection returns not ${compatibleResult}`);
+ }
+
+ before(async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+ ({collectionId: simpleNftCollectionId} = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}));
+ minter = await helper.eth.createAccountWithBalance(donor);
+ ({collectionId: erc721MetadataCompatibleNftCollectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(minter, 'n', 'd', 'p', BASE_URI));
+ });
+ });
+
+ itEth('nonexistent interfaceID - 0xffffffff - always false', async ({helper}) => {
+ await checkInterface(helper, '0xffffffff', false, false);
+ });
+
+ itEth('ERC721 - 0x780e9d63 - support', async ({helper}) => {
+ await checkInterface(helper, '0x780e9d63', true, true);
+ });
+
+ itEth('ERC721Metadata - 0x5b5e139f - support', async ({helper}) => {
+ await checkInterface(helper, '0x5b5e139f', false, true);
+ });
+
+ itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => {
+ await checkInterface(helper, '0x780e9d63', true, true);
+ });
+
+ itEth.skip('ERC721UniqueExtensions support', async ({helper}) => {
+ await checkInterface(helper, '0xb74c26b7', true, true);
+ });
+
+ itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {
+ await checkInterface(helper, '0x42966c68', true, true);
+ });
+
+ itEth('ERC165 - 0x01ffc9a7 - support', async ({helper}) => {
+ await checkInterface(helper, '0x01ffc9a7', true, true);
+ });
+});
js-packages/tests/eth/collectionAdmin.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/collectionAdmin.test.ts
@@ -0,0 +1,469 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect} from 'chai';
+import {Pallets} from '../util/index.js';
+import type {IEthCrossAccountId} from '@unique/playgrounds/types.js';
+import {usingEthPlaygrounds, itEth} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {CreateCollectionData} from './util/playgrounds/types.js';
+
+async function recordEthFee(helper: EthUniqueHelper, userAddress: string, call: () => Promise<any>) {
+ const before = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));
+ await call();
+ await helper.wait.newBlocks(1);
+ const after = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));
+
+ expect(after < before).to.be.true;
+
+ return before - after;
+}
+
+describe('Add collection admins', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`can add account admin by owner for ${testCase.mode}`, testCase.requiredPallets, async ({helper, privateKey}) => {
+ // arrange
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const adminSub = await privateKey('//admin2');
+ const adminEth = helper.eth.createAccount().toLowerCase();
+
+ const adminDeprecated = helper.eth.createAccount().toLowerCase();
+ const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, true);
+
+ // Check isOwnerOrAdminCross returns false:
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.false;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.false;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.false;
+
+ // Soft-deprecated: can addCollectionAdmin
+ await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();
+ // Can addCollectionAdminCross for substrate and ethereum address
+ await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
+ await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
+
+ // 1. Expect api.rpc.unique.adminlist returns admins:
+ const adminListRpc = await helper.collection.getAdmins(collectionId);
+ expect(adminListRpc).to.has.length(3);
+ expect(adminListRpc).to.be.deep.contain.members([{Substrate: adminSub.address}, {Ethereum: adminEth}, {Ethereum: adminDeprecated}]);
+
+ // 2. Expect methods.collectionAdmins == api.rpc.unique.adminlist
+ let adminListEth = await collectionEvm.methods.collectionAdmins().call();
+ adminListEth = adminListEth.map((element: IEthCrossAccountId) => helper.address.convertCrossAccountFromEthCrossAccount(element));
+ expect(adminListRpc).to.be.like(adminListEth);
+
+ // 3. check isOwnerOrAdminCross returns true:
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.true;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.true;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.true;
+ });
+ });
+
+ itEth('cross account admin can mint', async ({helper}) => {
+ // arrange: create collection and accounts
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', 'uri');
+ const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+ const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+ const [adminSub] = await helper.arrange.createAccounts([100n], donor);
+ const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ // cannot mint while not admin
+ await expect(collectionEvm.methods.mint(owner).send({from: adminEth})).to.be.rejected;
+ await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
+
+ // admin (sub and eth) can mint token:
+ await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
+ await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
+ await collectionEvm.methods.mint(owner).send({from: adminEth});
+ await helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}});
+
+ expect(await helper.collection.getLastTokenId(collectionId)).to.eq(2);
+ });
+
+ itEth('cannot add invalid cross account admin', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const [admin] = await helper.arrange.createAccounts([100n, 100n], donor);
+
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ const adminCross = {
+ eth: helper.address.substrateToEth(admin.address),
+ sub: admin.addressRaw,
+ };
+ await expect(collectionEvm.methods.addCollectionAdminCross(adminCross).send()).to.be.rejected;
+ });
+
+ itEth('can verify owner with methods.isOwnerOrAdmin[Cross]', async ({helper, privateKey}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const adminDeprecated = helper.eth.createAccount();
+ const admin1Cross = helper.ethCrossAccount.fromKeyringPair(await privateKey('admin'));
+ const admin2Cross = helper.ethCrossAccount.fromAddress(helper.address.substrateToEth((await privateKey('admin3')).address));
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ // Soft-deprecated:
+ expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.false;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.false;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.false;
+
+ await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();
+ await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send();
+ await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send();
+
+ // Soft-deprecated: isOwnerOrAdmin returns true
+ expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.true;
+ // Expect isOwnerOrAdminCross return true
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.true;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.true;
+ });
+
+ // Soft-deprecated
+ itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const admin = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+ await collectionEvm.methods.addCollectionAdmin(admin).send();
+
+ const user = helper.eth.createAccount();
+ await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin}))
+ .to.be.rejectedWith('NoPermission');
+
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(1);
+ expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
+ .to.be.eq(admin.toLocaleLowerCase());
+ });
+
+ // Soft-deprecated
+ itEth('(!negative tests!) Add admin by USER is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const notAdmin = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ const user = helper.eth.createAccount();
+ await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin}))
+ .to.be.rejectedWith('NoPermission');
+
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(0);
+ });
+
+ itEth('(!negative tests!) Add [cross] admin by ADMIN is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const [admin, notAdmin] = await helper.arrange.createAccounts([10n, 10n], donor);
+ const adminCross = helper.ethCrossAccount.fromKeyringPair(admin);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ await collectionEvm.methods.addCollectionAdminCross(adminCross).send();
+
+ const notAdminCross = helper.ethCrossAccount.fromKeyringPair(notAdmin);
+ await expect(collectionEvm.methods.addCollectionAdminCross(notAdminCross).call({from: adminCross.eth}))
+ .to.be.rejectedWith('NoPermission');
+
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(1);
+
+ const admin0Cross = helper.ethCrossAccount.fromKeyringPair(adminList[0]);
+ expect(admin0Cross.eth.toLocaleLowerCase())
+ .to.be.eq(adminCross.eth.toLocaleLowerCase());
+ });
+
+ itEth('(!negative tests!) Add [cross] admin by USER is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const notAdmin0 = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ const [notAdmin1] = await helper.arrange.createAccounts([10n], donor);
+ const notAdmin1Cross = helper.ethCrossAccount.fromKeyringPair(notAdmin1);
+ await expect(collectionEvm.methods.addCollectionAdminCross(notAdmin1Cross).call({from: notAdmin0}))
+ .to.be.rejectedWith('NoPermission');
+
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(0);
+ });
+});
+
+describe('Remove collection admins', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ // Soft-deprecated
+ itEth('Remove admin by owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const newAdmin = helper.eth.createAccount();
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+ await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
+
+ {
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(1);
+ expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
+ .to.be.eq(newAdmin.toLocaleLowerCase());
+ }
+
+ await collectionEvm.methods.removeCollectionAdmin(newAdmin).send();
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(0);
+ });
+
+ itEth('Remove [cross] admin by owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const [adminSub] = await helper.arrange.createAccounts([10n], donor);
+ const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+ const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
+ await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
+
+ {
+ const adminList = await helper.collection.getAdmins(collectionId);
+ expect(adminList).to.deep.include({Substrate: adminSub.address});
+ expect(adminList).to.deep.include({Ethereum: adminEth});
+ }
+
+ await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send();
+ await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send();
+ const adminList = await helper.collection.getAdmins(collectionId);
+ expect(adminList.length).to.be.eq(0);
+
+ // Non admin cannot mint:
+ await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
+ await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected;
+ });
+
+ // Soft-deprecated
+ itEth('(!negative tests!) Remove admin by ADMIN is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ const admin0 = await helper.eth.createAccountWithBalance(donor);
+ await collectionEvm.methods.addCollectionAdmin(admin0).send();
+ const admin1 = await helper.eth.createAccountWithBalance(donor);
+ await collectionEvm.methods.addCollectionAdmin(admin1).send();
+
+ await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0}))
+ .to.be.rejectedWith('NoPermission');
+ {
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(2);
+ expect(adminList.toString().toLocaleLowerCase())
+ .to.be.deep.contains(admin0.toLocaleLowerCase())
+ .to.be.deep.contains(admin1.toLocaleLowerCase());
+ }
+ });
+
+ // Soft-deprecated
+ itEth('(!negative tests!) Remove admin by USER is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ const admin = await helper.eth.createAccountWithBalance(donor);
+ await collectionEvm.methods.addCollectionAdmin(admin).send();
+ const notAdmin = helper.eth.createAccount();
+
+ await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin}))
+ .to.be.rejectedWith('NoPermission');
+ {
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
+ .to.be.eq(admin.toLocaleLowerCase());
+ expect(adminList.length).to.be.eq(1);
+ }
+ });
+
+ itEth('(!negative tests!) Remove [cross] admin by ADMIN is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const [admin1] = await helper.arrange.createAccounts([10n], donor);
+ const admin1Cross = helper.ethCrossAccount.fromKeyringPair(admin1);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send();
+
+ const [admin2] = await helper.arrange.createAccounts([10n], donor);
+ const admin2Cross = helper.ethCrossAccount.fromKeyringPair(admin2);
+ await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send();
+
+ await expect(collectionEvm.methods.removeCollectionAdminCross(admin1Cross).call({from: admin2Cross.eth}))
+ .to.be.rejectedWith('NoPermission');
+
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(2);
+ expect(adminList.toString().toLocaleLowerCase())
+ .to.be.deep.contains(admin1.address.toLocaleLowerCase())
+ .to.be.deep.contains(admin2.address.toLocaleLowerCase());
+ });
+
+ itEth('(!negative tests!) Remove [cross] admin by USER is not allowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const [adminSub] = await helper.arrange.createAccounts([10n], donor);
+ const adminSubCross = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ await collectionEvm.methods.addCollectionAdminCross(adminSubCross).send();
+ const notAdminEth = await helper.eth.createAccountWithBalance(donor);
+
+ await expect(collectionEvm.methods.removeCollectionAdminCross(adminSubCross).call({from: notAdminEth}))
+ .to.be.rejectedWith('NoPermission');
+
+ const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+ expect(adminList.length).to.be.eq(1);
+ expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())
+ .to.be.eq(adminSub.address.toLocaleLowerCase());
+ });
+});
+
+// Soft-deprecated
+describe('Change owner tests', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Change owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const newOwner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ await collectionEvm.methods.changeCollectionOwner(newOwner).send();
+
+ expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;
+ expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.true;
+ });
+
+ itEth('change owner call fee', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const newOwner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+ const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.changeCollectionOwner(newOwner).send());
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ expect(cost > 0);
+ });
+
+ itEth('(!negative tests!) call setOwner by non owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const newOwner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ await expect(collectionEvm.methods.changeCollectionOwner(newOwner).send({from: newOwner})).to.be.rejected;
+ expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.false;
+ });
+});
+
+describe('Change substrate owner tests', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Change owner [cross]', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ownerEth = await helper.eth.createAccountWithBalance(donor);
+ const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
+ const [ownerSub] = await helper.arrange.createAccounts([10n], donor);
+ const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
+
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.false;
+
+ // Can set ethereum owner:
+ await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossEth).send({from: owner});
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossEth).call()).to.be.true;
+ expect(await helper.collection.getData(collectionId))
+ .to.have.property('normalizedOwner').that.is.eq(helper.address.ethToSubstrate(ownerEth));
+
+ // Can set Substrate owner:
+ await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossSub).send({from: ownerEth});
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.true;
+ expect(await helper.collection.getData(collectionId))
+ .to.have.property('normalizedOwner').that.is.eq(helper.address.normalizeSubstrate(ownerSub.address));
+ });
+
+ itEth.skip('change owner call fee', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const [newOwner] = await helper.arrange.createAccounts([10n], donor);
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send());
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ expect(cost > 0);
+ });
+
+ itEth('(!negative tests!) call setOwner by non owner [cross]', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const otherReceiver = await helper.eth.createAccountWithBalance(donor);
+ const [newOwner] = await helper.arrange.createAccounts([10n], donor);
+ const newOwnerCross = helper.ethCrossAccount.fromKeyringPair(newOwner);
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ await expect(collectionEvm.methods.changeCollectionOwnerCross(newOwnerCross).send({from: otherReceiver})).to.be.rejected;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.false;
+ });
+});
js-packages/tests/eth/collectionHelperAddress.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/collectionHelperAddress.test.ts
@@ -0,0 +1,70 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {COLLECTION_HELPER, Pallets} from '../util/index.js';
+
+describe('[eth]CollectionHelperAddress test: ERC20/ERC721 ', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('NFT', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress: nftCollectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+ const nftCollection = await helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);
+
+ expect((await nftCollection.methods.collectionHelperAddress().call())
+ .toString().toLowerCase()).to.be.equal(COLLECTION_HELPER);
+ });
+
+ itEth.ifWithPallets('RFT ', [Pallets.ReFungible], async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress: rftCollectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+
+ const rftCollection = await helper.ethNativeContract.collection(rftCollectionAddress, 'rft', owner);
+ expect((await rftCollection.methods.collectionHelperAddress().call())
+ .toString().toLowerCase()).to.be.equal(COLLECTION_HELPER);
+ });
+
+ itEth('FT', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', 18, 'absolutely anything', 'ROC');
+ const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ expect((await collection.methods.collectionHelperAddress().call())
+ .toString().toLowerCase()).to.be.equal(COLLECTION_HELPER);
+ });
+
+ itEth('[collectionHelpers] convert collectionId into address', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionId = 7;
+ const collectionAddress = helper.ethAddress.fromCollectionId(collectionId);
+ const helperContract = await helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await helperContract.methods.collectionAddress(collectionId).call()).to.be.equal(collectionAddress);
+ expect(parseInt(await helperContract.methods.collectionId(collectionAddress).call())).to.be.equal(collectionId);
+ });
+
+});
js-packages/tests/eth/collectionLimits.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/collectionLimits.test.ts
@@ -0,0 +1,145 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {CollectionLimitField, CreateCollectionData} from './util/playgrounds/types.js';
+
+
+describe('Can set collection limits', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {case: 'nft' as const},
+ {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {case: 'ft' as const},
+ ].map(testCase =>
+ itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'FLO', testCase.case, 18)).send();
+ const limits = {
+ accountTokenOwnershipLimit: 1000,
+ sponsoredDataSize: 1024,
+ sponsoredDataRateLimit: 30,
+ tokenLimit: 1000000,
+ sponsorTransferTimeout: 6,
+ sponsorApproveTimeout: 6,
+ ownerCanTransfer: 1,
+ ownerCanDestroy: 0,
+ transfersEnabled: 0,
+ };
+
+ const expectedLimits = {
+ accountTokenOwnershipLimit: 1000,
+ sponsoredDataSize: 1024,
+ sponsoredDataRateLimit: {blocks: 30},
+ tokenLimit: 1000000,
+ sponsorTransferTimeout: 6,
+ sponsorApproveTimeout: 6,
+ ownerCanTransfer: true,
+ ownerCanDestroy: false,
+ transfersEnabled: false,
+ };
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: limits.accountTokenOwnershipLimit}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataSize, value: {status: true, value: limits.sponsoredDataSize}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: limits.sponsoredDataRateLimit}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.TokenLimit, value: {status: true, value: limits.tokenLimit}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsorTransferTimeout, value: {status: true, value: limits.sponsorTransferTimeout}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsorApproveTimeout, value: {status: true, value: limits.sponsorApproveTimeout}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: limits.ownerCanTransfer}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanDestroy, value: {status: true, value: limits.ownerCanDestroy}}).send();
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.TransferEnabled, value: {status: true, value: limits.transfersEnabled}}).send();
+
+ // Check limits from sub:
+ const data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.limits).to.deep.eq(expectedLimits);
+ expect(await helper.collection.getEffectiveLimits(collectionId)).to.deep.eq(expectedLimits);
+ // Check limits from eth:
+ const limitsEvm = await collectionEvm.methods.collectionLimits().call({from: owner});
+ expect(limitsEvm).to.have.length(9);
+ expect(limitsEvm[0]).to.deep.eq([CollectionLimitField.AccountTokenOwnership.toString(), [true, limits.accountTokenOwnershipLimit.toString()]]);
+ expect(limitsEvm[1]).to.deep.eq([CollectionLimitField.SponsoredDataSize.toString(), [true, limits.sponsoredDataSize.toString()]]);
+ expect(limitsEvm[2]).to.deep.eq([CollectionLimitField.SponsoredDataRateLimit.toString(), [true, limits.sponsoredDataRateLimit.toString()]]);
+ expect(limitsEvm[3]).to.deep.eq([CollectionLimitField.TokenLimit.toString(), [true, limits.tokenLimit.toString()]]);
+ expect(limitsEvm[4]).to.deep.eq([CollectionLimitField.SponsorTransferTimeout.toString(), [true, limits.sponsorTransferTimeout.toString()]]);
+ expect(limitsEvm[5]).to.deep.eq([CollectionLimitField.SponsorApproveTimeout.toString(), [true, limits.sponsorApproveTimeout.toString()]]);
+ expect(limitsEvm[6]).to.deep.eq([CollectionLimitField.OwnerCanTransfer.toString(), [true, limits.ownerCanTransfer.toString()]]);
+ expect(limitsEvm[7]).to.deep.eq([CollectionLimitField.OwnerCanDestroy.toString(), [true, limits.ownerCanDestroy.toString()]]);
+ expect(limitsEvm[8]).to.deep.eq([CollectionLimitField.TransferEnabled.toString(), [true, limits.transfersEnabled.toString()]]);
+ }));
+});
+
+describe('Cannot set invalid collection limits', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {case: 'nft' as const},
+ {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {case: 'ft' as const},
+ ].map(testCase =>
+ itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
+ const invalidLimits = {
+ accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),
+ transfersEnabled: 3,
+ };
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'ISNI', testCase.case, 18)).send();
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
+
+ // Cannot set non-existing limit
+ await expect(collectionEvm.methods
+ .setCollectionLimit({field: 9, value: {status: true, value: 1}})
+ .call()).to.be.rejectedWith('Returned error: VM Exception while processing transaction: revert value not convertible into enum "CollectionLimitField"');
+
+ // Cannot disable limits
+ await expect(collectionEvm.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: false, value: 0}})
+ .call()).to.be.rejectedWith('user can\'t disable limits');
+
+ await expect(collectionEvm.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: invalidLimits.accountTokenOwnershipLimit}})
+ .call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);
+
+ await expect(collectionEvm.methods
+ .setCollectionLimit({field: CollectionLimitField.TransferEnabled, value: {status: true, value: 3}})
+ .call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);
+
+ expect(() => collectionEvm.methods
+ .setCollectionLimit({field: CollectionLimitField.SponsoredDataSize, value: {status: true, value: -1}}).send()).to.throw('value out-of-bounds');
+ }));
+
+ [
+ {case: 'nft' as const, requiredPallets: []},
+ {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {case: 'ft' as const, requiredPallets: []},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Non-owner and non-admin cannot set collection limits for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const nonOwner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'FLO', testCase.case, 18)).send();
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
+ await expect(collectionEvm.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call({from: nonOwner}))
+ .to.be.rejectedWith('NoPermission');
+
+ await expect(collectionEvm.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .send({from: nonOwner}))
+ .to.be.rejected;
+ }));
+});
js-packages/tests/eth/collectionProperties.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/collectionProperties.test.ts
@@ -0,0 +1,215 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {Pallets} from '../util/index.js';
+import type {IProperty, ITokenPropertyPermission} from '@unique/playgrounds/types.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+describe('EVM collection properties', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await _helper.arrange.createAccounts([50n], donor);
+ });
+ });
+
+ // Soft-deprecated: setCollectionProperty
+ [
+ {method: 'setCollectionProperties', mode: 'nft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
+ {method: 'setCollectionProperties', mode: 'rft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
+ {method: 'setCollectionProperties', mode: 'ft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
+ {method: 'setCollectionProperty', mode: 'nft' as const, methodParams: ['testKey', Buffer.from('testValue')], expectedProps: [{key: 'testKey', value: 'testValue'}]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Collection properties can be set: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []});
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'setCollectionProperty');
+
+ // collectionProperties returns an empty array if no properties:
+ expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like([]);
+ expect(await collectionEvm.methods.collectionProperties(['NonExistingKey']).call()).to.be.like([]);
+
+ await collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller});
+
+ const raw = (await collection.getData())?.raw;
+ expect(raw.properties).to.deep.equal(testCase.expectedProps);
+
+ // collectionProperties returns properties:
+ expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like(testCase.expectedProps.map(prop => helper.ethProperty.property(prop.key, prop.value)));
+ }));
+
+ itEth('Cannot set invalid properties', async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []});
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ await expect(contract.methods.setCollectionProperties([{key: '', value: Buffer.from('val1')}]).send({from: caller})).to.be.rejected;
+ await expect(contract.methods.setCollectionProperties([{key: 'déjà vu', value: Buffer.from('hmm...')}]).send({from: caller})).to.be.rejected;
+ await expect(contract.methods.setCollectionProperties([{key: 'a'.repeat(257), value: Buffer.from('val3')}]).send({from: caller})).to.be.rejected;
+ // TODO add more expects
+ const raw = (await collection.getData())?.raw;
+ expect(raw.properties).to.deep.equal([]);
+ });
+
+
+ // Soft-deprecated: deleteCollectionProperty
+ [
+ {method: 'deleteCollectionProperties', mode: 'nft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},
+ {method: 'deleteCollectionProperties', mode: 'rft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},
+ {method: 'deleteCollectionProperties', mode: 'ft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},
+ {method: 'deleteCollectionProperty', mode: 'nft' as const, methodParams: ['testKey1'], expectedProps: [{key: 'testKey2', value: 'testValue2'}, {key: 'testKey3', value: 'testValue3'}]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Collection properties can be deleted: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
+ const properties = [
+ {key: 'testKey1', value: 'testValue1'},
+ {key: 'testKey2', value: 'testValue2'},
+ {key: 'testKey3', value: 'testValue3'}];
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties});
+
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'deleteCollectionProperty');
+
+ await contract.methods[testCase.method](...testCase.methodParams).send({from: caller});
+
+ const raw = (await collection.getData())?.raw;
+
+ expect(raw.properties.length).to.equal(testCase.expectedProps.length);
+ expect(raw.properties).to.deep.equal(testCase.expectedProps);
+ }));
+
+ [
+ {method: 'deleteCollectionProperties', methodParams: [['testKey2']]},
+ {method: 'deleteCollectionProperty', methodParams: ['testKey2']},
+ ].map(testCase =>
+ itEth(`cannot ${testCase.method}() of non-owned collections`, async ({helper}) => {
+ const properties = [
+ {key: 'testKey1', value: 'testValue1'},
+ {key: 'testKey2', value: 'testValue2'},
+ ];
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'deleteCollectionProperty');
+
+ await expect(collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller})).to.be.rejected;
+ expect(await collection.getProperties()).to.deep.eq(properties);
+ }));
+
+ itEth('Can be read', async({helper}) => {
+ const caller = helper.eth.createAccount();
+ const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: [{key: 'testKey', value: 'testValue'}]});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ const value = await contract.methods.collectionProperty('testKey').call();
+ expect(value).to.equal(helper.getWeb3().utils.toHex('testValue'));
+ });
+});
+
+describe('Supports ERC721Metadata', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {case: 'nft' as const},
+ {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`ERC721Metadata property can be set for ${testCase.case} collection`, testCase.requiredPallets || [], async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const bruh = await helper.eth.createAccountWithBalance(donor);
+
+ const BASE_URI = 'base/';
+ const SUFFIX = 'suffix1';
+ const URI = 'uri1';
+
+ const collectionHelpers = await helper.ethNativeContract.collectionHelpers(caller);
+ const creatorMethod = testCase.case === 'rft' ? 'createRFTCollection' : 'createNFTCollection';
+
+ const {collectionId, collectionAddress} = await helper.eth[creatorMethod](caller, 'n', 'd', 'p');
+ const bruhCross = helper.ethCrossAccount.fromAddress(bruh);
+
+ const contract = await helper.ethNativeContract.collectionById(collectionId, testCase.case, caller);
+ await contract.methods.addCollectionAdminCross(bruhCross).send(); // to check that admin will work too
+
+ const collection1 = helper.nft.getCollectionObject(collectionId);
+ const data1 = await collection1.getData();
+ expect(data1?.raw.flags.erc721metadata).to.be.false;
+ expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false;
+
+ await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, BASE_URI)
+ .send({from: bruh});
+
+ expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true;
+
+ const collection2 = helper.nft.getCollectionObject(collectionId);
+ const data2 = await collection2.getData();
+ expect(data2?.raw.flags.erc721metadata).to.be.true;
+
+ const propertyPermissions = data2?.raw.tokenPropertyPermissions;
+ expect(propertyPermissions?.length).to.equal(2);
+
+ expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => tpp.key === 'URI' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner)).to.be.not.null;
+
+ expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => tpp.key === 'URISuffix' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner)).to.be.not.null;
+
+ expect(data2?.raw.properties?.find((property: IProperty) => property.key === 'baseURI' && property.value === BASE_URI)).to.be.not.null;
+
+ const token1Result = await contract.methods.mint(bruh).send();
+ const tokenId1 = token1Result.events.Transfer.returnValues.tokenId;
+
+ expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI);
+
+ await contract.methods.setProperties(tokenId1, [{key: 'URISuffix', value: Buffer.from(SUFFIX)}]).send();
+ expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
+
+ await contract.methods.setProperties(tokenId1, [{key: 'URI', value: Buffer.from(URI)}]).send();
+ expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI);
+
+ await contract.methods.deleteProperties(tokenId1, ['URI']).send();
+ expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
+
+ const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send();
+ const tokenId2 = token2Result.events.Transfer.returnValues.tokenId;
+
+ expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI);
+
+ await contract.methods.deleteProperties(tokenId2, ['URI']).send();
+ expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI);
+
+ await contract.methods.setProperties(tokenId2, [{key: 'URISuffix', value: Buffer.from(SUFFIX)}]).send();
+ expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI + SUFFIX);
+ }));
+});
js-packages/tests/eth/collectionSponsoring.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/collectionSponsoring.test.ts
@@ -0,0 +1,955 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index.js';
+import {itEth, expect} from './util/index.js';
+import {CollectionLimitField, TokenPermissionField} from './util/playgrounds/types.js';
+
+describe('evm nft collection sponsoring', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let nominal: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ // TODO: move to substrate tests
+ itEth('sponsors mint transactions', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}});
+ await collection.setSponsor(alice, alice.address);
+ await collection.confirmSponsorship(alice);
+
+ const minter = helper.eth.createAccount();
+ expect(await helper.balance.getEthereum(minter)).to.equal(0n);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', minter);
+
+ await collection.addToAllowList(alice, {Ethereum: minter});
+
+ const result = await contract.methods.mint(minter).send();
+
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: minter,
+ tokenId: '1',
+ },
+ },
+ ]);
+ });
+
+ // TODO: Temprorary off. Need refactor
+ // itWeb3('Set substrate sponsor', async ({api, web3, privateKeyWrapper}) => {
+ // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ // const collectionHelpers = evmCollectionHelpers(web3, owner);
+ // let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send();
+ // const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+ // const sponsor = privateKeyWrapper('//Alice');
+ // const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+
+ // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+ // result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});
+ // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
+
+ // const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);
+ // await submitTransactionAsync(sponsor, confirmTx);
+ // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+
+ // const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);
+ // });
+
+ [
+ 'setCollectionSponsorCross',
+ 'setCollectionSponsor', // Soft-deprecated
+ ].map(testCase =>
+ itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
+
+ let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
+ const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner, testCase === 'setCollectionSponsor');
+
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+ result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+ let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+
+ await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
+
+ sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
+ }));
+
+ [
+ 'setCollectionSponsorCross',
+ 'setCollectionSponsor', // Soft-deprecated
+ ].map(testCase =>
+ itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+
+ const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');
+
+ const collectionSub = helper.nft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor');
+
+ // Set collection sponsor:
+ await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});
+ let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+ expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+ // Account cannot confirm sponsorship if it is not set as a sponsor
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ // Sponsor can confirm sponsorship:
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+ sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+ expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+
+ // Create user with no balance:
+ const user = helper.ethCrossAccount.createAccount();
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+
+ // Set collection permissions:
+ const oldPermissions = (await collectionSub.getData())!.raw.permissions;
+ expect(oldPermissions.mintMode).to.be.false;
+ expect(oldPermissions.access).to.be.equal('Normal');
+
+ await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+ await collectionEvm.methods.addToCollectionAllowListCross(user).send({from: owner});
+ await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: 30}}).send();
+
+ const newPermissions = (await collectionSub.getData())!.raw.permissions;
+ expect(newPermissions.mintMode).to.be.true;
+ expect(newPermissions.access).to.be.equal('AllowList');
+
+ // Set token permissions
+ await collectionEvm.methods.setTokenPropertyPermissions([
+ ['key', [
+ [TokenPermissionField.TokenOwner, true],
+ ],
+ ],
+ ]).send({from: owner});
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
+
+ // User can mint token without balance:
+ {
+ const result = await collectionEvm.methods.mintCross(user, [{key: 'key', value: Buffer.from('Value')}]).send({from: user.eth});
+ const event = helper.eth.normalizeEvents(result.events)
+ .find(event => event.event === 'Transfer');
+
+ expect(event).to.be.deep.equal({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user.eth,
+ tokenId: '1',
+ },
+ });
+
+ // await collectionEvm.methods.setProperties(1, [{key: 'key', value: Buffer.from('Value1')}]).send({from: user.eth});
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
+
+ expect(await collectionEvm.methods.properties(nextTokenId, []).call())
+ .to.be.like([
+ [
+ 'key',
+ '0x' + Buffer.from('Value').toString('hex'),
+ ],
+ ]);
+ expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+ }
+ }));
+
+ itEth('Can sponsor [set token properties] via access list', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, false);
+
+ // Set collection sponsor:
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
+
+ // Sponsor can confirm sponsorship:
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+
+ // Create user with no balance:
+ const user = helper.ethCrossAccount.createAccount();
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+
+ // Set collection permissions:
+ await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+ await collectionEvm.methods.addToCollectionAllowListCross(user).send({from: owner});
+ await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+ await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: 30}}).send();
+
+ // Set token permissions
+ await collectionEvm.methods.setTokenPropertyPermissions([
+ ['key', [
+ [TokenPermissionField.TokenOwner, true],
+ ],
+ ],
+ ]).send({from: owner});
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
+
+ // User can mint token without balance:
+ {
+ const result = await collectionEvm.methods.mintCross(user, []).send({from: user.eth});
+ const event = helper.eth.normalizeEvents(result.events)
+ .find(event => event.event === 'Transfer');
+
+ expect(event).to.be.deep.equal({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user.eth,
+ tokenId: '1',
+ },
+ });
+
+ await collectionEvm.methods.setProperties(1, [{key: 'key', value: Buffer.from('Value')}]).send({from: user.eth});
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
+
+ expect(await collectionEvm.methods.properties(nextTokenId, []).call())
+ .to.be.like([
+ [
+ 'key',
+ '0x' + Buffer.from('Value').toString('hex'),
+ ],
+ ]);
+ expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+ }
+ });
+
+ // TODO: Temprorary off. Need refactor
+ // itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => {
+ // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ // const collectionHelpers = evmCollectionHelpers(web3, owner);
+ // const result = await collectionHelpers.methods.createERC721MetadataCompatibleNFTCollection('Sponsor collection', '1', '1', '').send();
+ // const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+ // const sponsor = privateKeyWrapper('//Alice');
+ // const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+
+ // await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});
+
+ // const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);
+ // await submitTransactionAsync(sponsor, confirmTx);
+
+ // const user = createEthAccount(web3);
+ // const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ // expect(nextTokenId).to.be.equal('1');
+
+ // await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+ // await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
+ // await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+
+ // const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
+ // const sponsorBalanceBefore = (await getBalance(api, [sponsor.address]))[0];
+
+ // {
+ // const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ // expect(nextTokenId).to.be.equal('1');
+ // const result = await collectionEvm.methods.mintWithTokenURI(
+ // user,
+ // nextTokenId,
+ // 'Test URI',
+ // ).send({from: user});
+ // const events = normalizeEvents(result.events);
+
+ // expect(events).to.be.deep.equal([
+ // {
+ // address: collectionIdAddress,
+ // event: 'Transfer',
+ // args: {
+ // from: '0x0000000000000000000000000000000000000000',
+ // to: user,
+ // tokenId: nextTokenId,
+ // },
+ // },
+ // ]);
+
+ // const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
+ // const sponsorBalanceAfter = (await getBalance(api, [sponsor.address]))[0];
+
+ // expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+ // expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+ // expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+ // }
+ // });
+
+ [
+ 'setCollectionSponsorCross',
+ 'setCollectionSponsor', // Soft-deprecated
+ ].map(testCase =>
+ itEth(`[${testCase}] Check that transaction via EVM spend money from sponsor address`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');
+
+ const collectionSub = helper.nft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor');
+ // Set collection sponsor:
+ await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
+ let collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+ collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+
+ const user = helper.eth.createAccount();
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+
+ const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+
+ const event = helper.eth.normalizeEvents(mintingResult.events)
+ .find(event => event.event === 'Transfer');
+ const address = helper.ethAddress.fromCollectionId(collectionId);
+
+ expect(event).to.be.deep.equal({
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: '1',
+ },
+ });
+ expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ }));
+
+ itEth('Can reassign collection sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+ const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
+ const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');
+ const collectionSub = helper.nft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ // Set and confirm sponsor:
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+
+ // Can reassign sponsor:
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
+ const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
+ expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
+ });
+});
+
+describe('evm RFT collection sponsoring', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let nominal: bigint;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ [
+ 'mintCross',
+ 'mintWithTokenURI',
+ ].map(testCase =>
+ itEth(`[${testCase}] sponsors mint transactions`, async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}, tokenPropertyPermissions: [
+ {key: 'URI', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+ ]});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ await collection.setSponsor(alice, alice.address);
+ await collection.confirmSponsorship(alice);
+
+ const minter = helper.eth.createAccount();
+ const minterCross = helper.ethCrossAccount.fromAddress(minter);
+ expect(await helper.balance.getEthereum(minter)).to.equal(0n);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);
+
+ await collection.addToAllowList(alice, {Ethereum: minter});
+ await collection.addAdmin(alice, {Ethereum: owner});
+ const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
+ await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/')
+ .send();
+
+ let mintingResult;
+ let tokenId;
+ switch (testCase) {
+ case 'mintCross':
+ mintingResult = await contract.methods.mintCross(minterCross, []).send();
+ break;
+ case 'mintWithTokenURI':
+ mintingResult = await contract.methods.mintWithTokenURI(minter, 'Test URI').send();
+ tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+ expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+ break;
+ }
+
+ const events = helper.eth.normalizeEvents(mintingResult.events);
+ expect(events).to.deep.include({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: minter,
+ tokenId: '1',
+ },
+ });
+ }));
+
+ [
+ 'setCollectionSponsorCross',
+ 'setCollectionSponsor', // Soft-deprecated
+ ].map(testCase =>
+ itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
+
+ let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
+ const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, testCase === 'setCollectionSponsor');
+
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+ result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+
+ await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
+
+ const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
+ }));
+
+ [
+ 'setCollectionSponsorCross',
+ 'setCollectionSponsor', // Soft-deprecated
+ ].map(testCase =>
+ itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+
+ const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');
+
+ const collectionSub = helper.rft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
+
+ // Set collection sponsor:
+ await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});
+ let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+ expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+ // Account cannot confirm sponsorship if it is not set as a sponsor
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ // Sponsor can confirm sponsorship:
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+ sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+ expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+
+ // Create user with no balance:
+ const user = helper.eth.createAccount();
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+
+ // Set collection permissions:
+ const oldPermissions = (await collectionSub.getData())!.raw.permissions;
+ expect(oldPermissions.mintMode).to.be.false;
+ expect(oldPermissions.access).to.be.equal('Normal');
+
+ await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+ await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
+ await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+
+ const newPermissions = (await collectionSub.getData())!.raw.permissions;
+ expect(newPermissions.mintMode).to.be.true;
+ expect(newPermissions.access).to.be.equal('AllowList');
+
+ // Set token permissions
+ await collectionEvm.methods.setTokenPropertyPermissions([
+ ['URI', [
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true],
+ ],
+ ],
+ ]).send({from: owner});
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ // User can mint token without balance:
+ {
+ const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.deep.include({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: '1',
+ },
+ });
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+ expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+ }
+ }));
+
+ [
+ 'setCollectionSponsorCross',
+ 'setCollectionSponsor', // Soft-deprecated
+ ].map(testCase =>
+ itEth(`[${testCase}] Check that collection admin EVM transaction spend money from sponsor eth address`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+
+ const collectionSub = helper.rft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
+ // Set collection sponsor:
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
+ await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
+ let collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+ collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
+ const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ const sponsorSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.ethToSubstrate(sponsor));
+ const actualSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub)));
+ expect(actualSubAddress).to.be.equal(sponsorSubAddress);
+
+ const user = helper.eth.createAccount();
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+
+ const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+
+ const events = helper.eth.normalizeEvents(mintingResult.events);
+ const address = helper.ethAddress.fromCollectionId(collectionId);
+
+ expect(events).to.deep.include({
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: '1',
+ },
+ });
+ expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ }));
+
+ itEth('Check that collection admin EVM transaction spend money from sponsor sub address', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = alice;
+ const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+
+ const collectionSub = helper.rft.getCollectionObject(collectionId);
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
+ // Set collection sponsor:
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
+ let collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(sponsor.address);
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ await collectionSub.confirmSponsorship(sponsor);
+ collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(sponsor.address);
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
+ const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ expect(BigInt(sponsorStruct.sub)).to.be.equal(BigInt('0x' + Buffer.from(sponsor.addressRaw).toString('hex')));
+
+ const user = helper.eth.createAccount();
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
+
+ const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+
+ const events = helper.eth.normalizeEvents(mintingResult.events);
+
+ expect(events).to.deep.include({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: '1',
+ },
+ });
+ expect(await collectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ });
+
+ itEth('Sponsoring collection from substrate address via access list', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const user = helper.eth.createAccount();
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ const sponsor = alice;
+ const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
+
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});
+
+ const collectionSub = helper.rft.getCollectionObject(collectionId);
+ await collectionSub.confirmSponsorship(sponsor);
+
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+
+ await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+
+ await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
+ await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+
+ // Set token permissions
+ await collectionEvm.methods.setTokenPropertyPermissions([
+ ['URI', [
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true],
+ ],
+ ],
+ ]).send({from: owner});
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ {
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const mintingResult = await collectionEvm.methods.mintWithTokenURI(
+ user,
+ 'Test URI',
+ ).send({from: user});
+
+ const events = helper.eth.normalizeEvents(mintingResult.events);
+
+
+ expect(events).to.deep.include({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: nextTokenId,
+ },
+ });
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+ expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+ }
+ });
+
+ itEth('Can reassign collection sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+ const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
+ const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+ const collectionSub = helper.rft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ // Set and confirm sponsor:
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+
+ // Can reassign sponsor:
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
+ const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
+ expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
+ });
+
+ [
+ 'transfer',
+ 'transferCross',
+ 'transferFrom',
+ 'transferFromCross',
+ ].map(testCase =>
+ itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+
+ const user = await helper.eth.createAccountWithBalance(donor);
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+ const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ switch (testCase) {
+ case 'transfer':
+ await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});
+ break;
+ case 'transferCross':
+ await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
+ break;
+ case 'transferFrom':
+ await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});
+ break;
+ case 'transferFromCross':
+ await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
+ break;
+ }
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ }));
+});
+
+describe('evm RFT token sponsoring', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ 'transfer',
+ 'transferCross',
+ 'transferFrom',
+ 'transferFromCross',
+ ].map(testCase =>
+ itEth(`[${testCase}] Check that token piece transfer via EVM spend money from sponsor address`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+
+ const user = await helper.eth.createAccountWithBalance(donor);
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+ const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);
+ await tokenContract.methods.repartition(2).send();
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ switch (testCase) {
+ case 'transfer':
+ await tokenContract.methods.transfer(receiver, 1).send();
+ break;
+ case 'transferCross':
+ await tokenContract.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
+ break;
+ case 'transferFrom':
+ await tokenContract.methods.transferFrom(user, receiver, 1).send();
+ break;
+ case 'transferFromCross':
+ await tokenContract.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), 1).send();
+ break;
+ }
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ }));
+
+ [
+ 'approve',
+ 'approveCross',
+ ].map(testCase =>
+ itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+
+ const user = await helper.eth.createAccountWithBalance(donor);
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+ await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+ const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);
+ await tokenContract.methods.repartition(2).send();
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ switch (testCase) {
+ case 'approve':
+ await tokenContract.methods.approve(receiver, 1).send();
+ break;
+ case 'approveCross':
+ await tokenContract.methods.approveCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
+ break;
+ }
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ }));
+});
+
js-packages/tests/eth/contractSponsoring.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/contractSponsoring.test.ts
@@ -0,0 +1,579 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itEth, expect, SponsoringMode, usingEthPlaygrounds} from './util/index.js';
+import {usingPlaygrounds} from '../util/index.js';
+import type {CompiledContract} from './util/playgrounds/types.js';
+
+describe('Sponsoring EVM contracts', () => {
+ let donor: IKeyringPair;
+ let nominal: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ itEth('Self sponsoring can be set by the address that deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const flipper = await helper.eth.deployFlipper(owner);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+
+ // 1. owner can set selfSponsoring:
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send({from: owner});
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+
+ // 1.1 Can get sponsor using methods.sponsor:
+ const actualSponsorOpt = await helpers.methods.sponsor(flipper.options.address).call();
+ expect(actualSponsorOpt.status).to.be.true;
+ const actualSponsor = actualSponsorOpt.value;
+ expect(actualSponsor.eth).to.eq(flipper.options.address);
+ expect(actualSponsor.sub).to.eq('0');
+
+ // 2. Events should be:
+ const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events);
+ expect(ethEvents).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorSet',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: flipper.options.address,
+ },
+ },
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorshipConfirmed',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: flipper.options.address,
+ },
+ },
+ ]);
+ });
+
+ itEth('Self sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const notOwner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ });
+
+ itEth('Sponsoring can be set by the address that has deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
+ expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
+ });
+
+ itEth('Sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const notOwner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
+ await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
+ });
+
+ itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ // 1. owner can set a sponsor:
+ expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
+ const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;
+
+ // 2. Events should be:
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorSet',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: sponsor,
+ },
+ },
+ ]);
+ });
+
+ itEth('Sponsor cannot be set by the address that did not deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const notOwner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
+ await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
+ });
+
+ itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+
+ // 1. sponsor can confirm sponsorship:
+ const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+
+ // 1.1 Can get sponsor using methods.sponsor:
+ const actualSponsorOpt = await helpers.methods.sponsor(flipper.options.address).call();
+ expect(actualSponsorOpt.status).to.be.true;
+ const actualSponsor = actualSponsorOpt.value;
+ expect(actualSponsor.eth).to.eq(sponsor);
+ expect(actualSponsor.sub).to.eq('0');
+
+ // 2. Events should be:
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorshipConfirmed',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: sponsor,
+ },
+ },
+ ]);
+ });
+
+ itEth('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const notSponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
+ await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ });
+
+ itEth('Sponsorship can not be confirmed by the address that not set as sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const notSponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ });
+
+ itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ // 1. Can remove sponsor:
+ const result = await helpers.methods.removeSponsor(flipper.options.address).send();
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+
+ // 2. Events should be:
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorRemoved',
+ args: {
+ contractAddress: flipper.options.address,
+ },
+ },
+ ]);
+
+ // TODO: why call method reverts?
+ // const actualSponsor = await helpers.methods.sponsor(flipper.options.address).call();
+ // expect(actualSponsor.eth).to.eq(sponsor);
+ // expect(actualSponsor.sub).to.eq('0');
+ });
+
+ itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const notOwner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+
+ await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');
+ await expect(helpers.methods.removeSponsor(flipper.options.address).send({from: notOwner})).to.be.rejected;
+ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ });
+
+ itEth('In generous mode, non-allowlisted user transaction will be sponsored', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const callerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // Balance should be taken from sponsor instead of caller
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);
+ });
+
+ itEth('In generous mode, non-allowlisted user transaction will be self sponsored', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
+
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+
+ await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
+
+ const contractBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address));
+ const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // Balance should be taken from sponsor instead of caller
+ const contractBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address));
+ const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
+ expect(contractBalanceAfter < contractBalanceBefore).to.be.true;
+ expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);
+ });
+
+ [
+ {balance: 0n, label: '0'},
+ {balance: 10n, label: '10'},
+ ].map(testCase => {
+ itEth(`Allow-listed address that has ${testCase.label} UNQ can call a contract. Sponsor balance should decrease`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const caller = helper.eth.createAccount();
+ await helper.eth.transferBalanceFromSubstrate(donor, caller, testCase.balance);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
+ await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
+
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceBefore > 0n).to.be.true;
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // Balance should be taken from flipper instead of caller
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ // Caller's balance does not change:
+ const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
+ expect(callerBalanceAfter).to.eq(testCase.balance * nominal);
+ });
+ });
+
+ itEth('Non-allow-listed address can call a contract. Sponsor balance should not decrease', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = helper.eth.createAccount();
+ const contractHelpers = await helper.ethNativeContract.contractHelpers(owner);
+
+ // Deploy flipper and send some tokens:
+ const flipper = await helper.eth.deployFlipper(owner);
+ await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
+ expect(await flipper.methods.getValue().call()).to.be.false;
+ // flipper address has some tokens:
+ const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address);
+ expect(originalFlipperBalance > 0n).to.be.true;
+
+ // Set Allowlisted sponsoring mode. caller is not in allow list:
+ await contractHelpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
+ await contractHelpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
+ await contractHelpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+
+ // 1. Caller has no UNQ and is not in allow list. So he cannot flip:
+ await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/Returned error: insufficient funds for gas \* price \+ value/);
+ expect(await flipper.methods.getValue().call()).to.be.false;
+
+ // Flipper's balance does not change:
+ const balanceAfter = await helper.balance.getEthereum(flipper.options.address);
+ expect(balanceAfter).to.be.equal(originalFlipperBalance);
+ });
+
+ itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ const originalCallerBalance = await helper.balance.getEthereum(caller);
+ await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
+ await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
+
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});
+
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+
+ const originalFlipperBalance = await helper.balance.getEthereum(sponsor);
+ expect(originalFlipperBalance > 0n).to.be.true;
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+ expect(await helper.balance.getEthereum(caller)).to.be.equal(originalCallerBalance);
+
+ const newFlipperBalance = await helper.balance.getEthereum(sponsor);
+ expect(newFlipperBalance).to.be.not.equal(originalFlipperBalance);
+
+ await flipper.methods.flip().send({from: caller});
+ // todo:playgrounds fails rarely (expected 99893341659775672580n to equal 99912598679356033129n) (again, 99893341659775672580n)
+ expect(await helper.balance.getEthereum(sponsor)).to.be.equal(newFlipperBalance);
+ expect(await helper.balance.getEthereum(caller)).to.be.not.equal(originalCallerBalance);
+ });
+
+ // TODO: Find a way to calculate default rate limit
+ itEth('Default rate limit equal 7200', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.sponsoringRateLimit(flipper.options.address).call()).to.be.equal('7200');
+ });
+
+ itEth('Gas price boundaries', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+
+ let sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ let callerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
+
+ let expectValue = await flipper.methods.getValue().call();
+
+ const flip = async (gasPrice: bigint, shouldPass = true) => {
+ await flipper.methods.flip().send({from: caller, gasPrice: gasPrice});
+ expectValue = !expectValue;
+ expect(await flipper.methods.getValue().call()).to.be.eq(expectValue);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.eq(shouldPass);
+ expect(callerBalanceAfter === callerBalanceBefore).to.be.eq(shouldPass);
+ sponsorBalanceBefore = sponsorBalanceAfter;
+ callerBalanceBefore = callerBalanceAfter;
+ };
+
+ const gasPrice = BigInt((await helper.eth.getGasPrice())!);
+ await flip(gasPrice);
+ await flip(gasPrice * 2n);
+ await flip(gasPrice * 21n / 10n);
+ await flip(gasPrice * 22n / 10n, false);
+ });
+});
+
+describe('Sponsoring Fee Limit', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let testContract: CompiledContract;
+
+ async function compileTestContract(helper: EthUniqueHelper) {
+ if(!testContract) {
+ testContract = await helper.ethContract.compile(
+ 'TestContract',
+ `
+ // SPDX-License-Identifier: MIT
+ pragma solidity ^0.8.0;
+
+ contract TestContract {
+ event Result(bool);
+
+ function test(uint32 cycles) public {
+ uint256 counter = 0;
+ while(true) {
+ counter ++;
+ if (counter > cycles){
+ break;
+ }
+ }
+ emit Result(true);
+ }
+ }
+ `,
+ );
+ }
+ return testContract;
+ }
+
+ async function deployTestContract(helper: EthUniqueHelper, owner: string) {
+ const compiled = await compileTestContract(helper);
+ return await helper.ethContract.deployByAbi(owner, compiled.abi, compiled.object);
+ }
+
+ before(async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ itEth('Default fee limit', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equal('115792089237316195423570985008687907853269984665640564039457584007913129639935');
+ });
+
+ itEth('Set fee limit', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ await helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send();
+ expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equal('100');
+ });
+
+ itEth('Negative test - set fee limit by non-owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const stranger = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ await expect(helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send({from: stranger})).to.be.rejected;
+ });
+
+ itEth('Negative test - check that eth transactions exceeding fee limit are not executed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const user = await helper.eth.createAccountWithBalance(donor);
+ const helpers = helper.ethNativeContract.contractHelpers(owner);
+
+ const testContract = await deployTestContract(helper, owner);
+
+ await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});
+
+ await helpers.methods.setSponsor(testContract.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});
+
+ const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
+
+ await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();
+
+ const originalUserBalance = await helper.balance.getEthereum(user);
+ await testContract.methods.test(100).send({from: user, gas: 2_000_000, maxFeePerGas: gasPrice.toString()});
+ expect(await helper.balance.getEthereum(user)).to.be.equal(originalUserBalance);
+
+ await testContract.methods.test(100).send({from: user, gas: 2_100_000, maxFeePerGas: gasPrice.toString()});
+ expect(await helper.balance.getEthereum(user)).to.not.be.equal(originalUserBalance);
+ });
+
+ itEth('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+
+ const testContract = await deployTestContract(helper, owner);
+
+ await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});
+
+ await helpers.methods.setSponsor(testContract.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});
+
+ const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
+
+ await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();
+
+ const originalAliceBalance = await helper.balance.getSubstrate(alice.address);
+
+ await helper.eth.sendEVM(
+ alice,
+ testContract.options.address,
+ testContract.methods.test(100).encodeABI(),
+ '0',
+ 2_000_000,
+ );
+ // expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance);
+ expect(await helper.balance.getSubstrate(alice.address)).to.be.equal(originalAliceBalance);
+
+ await helper.eth.sendEVM(
+ alice,
+ testContract.options.address,
+ testContract.methods.test(100).encodeABI(),
+ '0',
+ 2_100_000,
+ );
+ expect(await helper.balance.getSubstrate(alice.address)).to.not.be.equal(originalAliceBalance);
+ });
+});
js-packages/tests/eth/createCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/createCollection.test.ts
@@ -0,0 +1,1449 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {evmToAddress} from '@polkadot/util-crypto';
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {CREATE_COLLECTION_DATA_DEFAULTS, CollectionLimitField, CollectionMode, CreateCollectionData, TokenPermissionField, emptyAddress} from './util/playgrounds/types.js';
+import {CollectionFlag} from '@unique/playgrounds/types.js';
+import type {IEthCrossAccountId, TCollectionMode} from '@unique/playgrounds/types.js';
+
+const DECIMALS = 18;
+const CREATE_COLLECTION_DATA_DEFAULTS_ARRAY = [
+ [], // properties
+ [], // tokenPropertyPermissions
+ [], // adminList
+ [false, false, []], // nestingSettings
+ [], // limits
+ emptyAddress, // pendingSponsor
+ [0], // flags
+];
+
+type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
+function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
+ if(args.length === 0) {
+ yield internalRest as any;
+ return;
+ }
+ for(const value of args[0]) {
+ yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
+ }
+}
+
+describe('Create collection from EVM', () => {
+ let donor: IKeyringPair;
+ let nominal: bigint;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ describe('Fungible collection', () => {
+ before(async function() {
+ await usingEthPlaygrounds((helper) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
+ return Promise.resolve();
+ });
+ });
+
+ itEth('Collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
+ .to.be.false;
+
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Exister', 'absolutely anything', 'WIWT', 'ft', DECIMALS)).send();
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddress).call())
+ .to.be.true;
+
+ // check collectionOwner:
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ const collectionOwner = await collectionEvm.methods.collectionOwner().call();
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
+ });
+
+ itEth('destroyCollection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Exister', 'absolutely anything', 'WIWT', 'ft', DECIMALS)).send();
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+
+ const result = await collectionHelper.methods
+ .destroyCollection(collectionAddress)
+ .send({from: owner});
+
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address: collectionHelper.options.address,
+ event: 'CollectionDestroyed',
+ args: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+
+ expect(await collectionHelper.methods
+ .isCollectionExist(collectionAddress)
+ .call()).to.be.false;
+ expect(await helper.collection.getData(collectionId)).to.be.null;
+ });
+
+ itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ {
+ const MAX_NAME_LENGTH = 64;
+ const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
+ const description = 'A';
+ const tokenPrefix = 'A';
+
+ await expect(collectionHelper.methods
+ .createCollection([
+ collectionName,
+ description,
+ tokenPrefix,
+ CollectionMode.Fungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
+ }
+ {
+ const MAX_DESCRIPTION_LENGTH = 256;
+ const collectionName = 'A';
+ const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
+ const tokenPrefix = 'A';
+ await expect(collectionHelper.methods
+ .createCollection([
+ collectionName,
+ description,
+ tokenPrefix,
+ CollectionMode.Fungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
+ }
+ {
+ const MAX_TOKEN_PREFIX_LENGTH = 16;
+ const collectionName = 'A';
+ const description = 'A';
+ const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
+ await expect(collectionHelper.methods
+ .createCollection([
+ collectionName,
+ description,
+ tokenPrefix,
+ CollectionMode.Fungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
+ }
+ });
+
+ itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ const expects = [0n, 1n, 30n].map(async value => {
+ await expect(collectionHelper.methods
+ .createCollection([
+ 'Peasantry',
+ 'absolutely anything',
+ 'TWIW',
+ CollectionMode.Fungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+ await Promise.all(expects);
+ });
+ });
+
+ describe('Nonfungible collection', () => {
+ before(async function() {
+ await usingEthPlaygrounds((helper) => {
+ requirePalletsOrSkip(this, helper, [Pallets.NFT]);
+ return Promise.resolve();
+ });
+ });
+
+ itEth('Create collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+
+ // todo:playgrounds this might fail when in async environment.
+ const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
+ const {collectionId, collectionAddress, events} = await helper.eth.createCollection(owner, new CreateCollectionData(name, description, prefix, 'nft')).send();
+
+ expect(events).to.be.deep.equal([
+ {
+ address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',
+ event: 'CollectionCreated',
+ args: {
+ owner: owner,
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+
+ const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
+
+ const collection = helper.nft.getCollectionObject(collectionId);
+ const data = (await collection.getData())!;
+
+ // Parallel test safety
+ expect(collectionCountAfter - collectionCountBefore).to.be.gte(1);
+ expect(collectionId).to.be.eq(collectionCountAfter);
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('NFT');
+
+ const options = await collection.getOptions();
+
+ expect(options.tokenPropertyPermissions).to.be.empty;
+ });
+
+ // this test will occasionally fail when in async environment.
+ itEth('Check collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
+ const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(expectedCollectionAddress)
+ .call()).to.be.false;
+
+ await collectionHelpers.methods
+ .createCollection([
+ 'A',
+ 'A',
+ 'A',
+ CollectionMode.Nonfungible,
+ 0,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .send({value: Number(2n * helper.balance.getOneTokenNominal())});
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(expectedCollectionAddress)
+ .call()).to.be.true;
+ });
+ });
+
+ describe('Create RFT collection from EVM', () => {
+ before(async function() {
+ await usingEthPlaygrounds((helper) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ return Promise.resolve();
+ });
+ });
+
+ itEth('Create collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+
+ const {collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData(name, description, prefix, 'rft')).send();
+ const data = (await helper.rft.getData(collectionId))!;
+ const collection = helper.rft.getCollectionObject(collectionId);
+
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('ReFungible');
+
+ const options = await collection.getOptions();
+
+ expect(options.tokenPropertyPermissions).to.be.empty;
+ });
+
+ itEth('Create collection with properties & get description', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+ const baseUri = 'BaseURI';
+
+ const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const collection = helper.rft.getCollectionObject(collectionId);
+ const data = (await collection.getData())!;
+
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('ReFungible');
+
+ expect(await contract.methods.description().call()).to.deep.equal(description);
+
+ const options = await collection.getOptions();
+ expect(options.tokenPropertyPermissions).to.be.deep.equal([
+ {
+ key: 'URI',
+ permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
+ },
+ {
+ key: 'URISuffix',
+ permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
+ },
+ ]);
+ });
+
+ itEth('Set sponsorship', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Sponsor', 'absolutely anything', 'ENVY', 'rft')).send();
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await collection.methods.setCollectionSponsorCross(sponsorCross).send();
+
+ let data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+ });
+
+ itEth('Collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
+ .to.be.false;
+
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Exister', 'absolutely anything', 'WIWT', 'rft')).send();
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddress).call())
+ .to.be.true;
+
+ // check collectionOwner:
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ const collectionOwner = await collectionEvm.methods.collectionOwner().call();
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
+ });
+
+ itEth('destroyCollection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'OLF', 'rft')).send();
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+
+ await expect(collectionHelper.methods
+ .destroyCollection(collectionAddress)
+ .send({from: owner})).to.be.fulfilled;
+
+ expect(await collectionHelper.methods
+ .isCollectionExist(collectionAddress)
+ .call()).to.be.false;
+ expect(await helper.collection.getData(collectionId)).to.be.null;
+ });
+
+ itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ {
+ const MAX_NAME_LENGTH = 64;
+ const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
+ const description = 'A';
+ const tokenPrefix = 'A';
+
+ await expect(collectionHelper.methods
+ .createCollection([
+ collectionName,
+ description,
+ tokenPrefix,
+ CollectionMode.Refungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
+ }
+ {
+ const MAX_DESCRIPTION_LENGTH = 256;
+ const collectionName = 'A';
+ const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
+ const tokenPrefix = 'A';
+ await expect(collectionHelper.methods
+ .createCollection([
+ collectionName,
+ description,
+ tokenPrefix,
+ CollectionMode.Refungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
+ }
+ {
+ const MAX_TOKEN_PREFIX_LENGTH = 16;
+ const collectionName = 'A';
+ const description = 'A';
+ const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
+ await expect(collectionHelper.methods
+ .createCollection([
+ collectionName,
+ description,
+ tokenPrefix,
+ CollectionMode.Refungible,
+ DECIMALS,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
+ }
+ });
+
+ itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ await expect(collectionHelper.methods
+ .createCollection([
+ 'Peasantry',
+ 'absolutely anything',
+ 'TWIW',
+ CollectionMode.Refungible,
+ 0,
+ ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
+ ])
+ .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+ });
+
+ describe('Sponsoring', () => {
+ itEth('Сan remove collection sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddr(sponsor);
+
+ const {collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Sponsor collection',
+ description: '1',
+ tokenPrefix: '1',
+ collectionMode: 'nft',
+ pendingSponsor: sponsorCross,
+ },
+ ).send();
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+ let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+
+ await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
+
+ sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
+ expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
+ });
+
+ itEth('Can sponsor from evm address via access list', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddr(sponsorEth);
+
+ const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Sponsor collection',
+ description: '1',
+ tokenPrefix: '1',
+ collectionMode: 'nft',
+ pendingSponsor: sponsorCross,
+ limits: [{field: CollectionLimitField.SponsoredDataRateLimit, value: 30n}],
+ tokenPropertyPermissions: [{key: 'key', permissions: [{code: TokenPermissionField.TokenOwner, value: true}]}],
+ },
+ '',
+ );
+
+ const collectionSub = helper.nft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+ expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+ // Account cannot confirm sponsorship if it is not set as a sponsor
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ // Sponsor can confirm sponsorship:
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+ sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+ expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+
+ // Create user with no balance:
+ const user = helper.ethCrossAccount.createAccount();
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+
+ // Set collection permissions:
+ const oldPermissions = (await collectionSub.getData())!.raw.permissions;
+ expect(oldPermissions.mintMode).to.be.false;
+ expect(oldPermissions.access).to.be.equal('Normal');
+
+ await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+ await collectionEvm.methods.addToCollectionAllowListCross(user).send({from: owner});
+ await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+
+ const newPermissions = (await collectionSub.getData())!.raw.permissions;
+ expect(newPermissions.mintMode).to.be.true;
+ expect(newPermissions.access).to.be.equal('AllowList');
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
+
+ // User can mint token without balance:
+ {
+ const result = await collectionEvm.methods.mintCross(user, [{key: 'key', value: Buffer.from('Value')}]).send({from: user.eth});
+ const event = helper.eth.normalizeEvents(result.events)
+ .find(event => event.event === 'Transfer');
+
+ expect(event).to.be.deep.equal({
+ address: collectionAddress,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user.eth,
+ tokenId: '1',
+ },
+ });
+
+ // await collectionEvm.methods.setProperties(1, [{key: 'key', value: Buffer.from('Value1')}]).send({from: user.eth});
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
+
+ expect(await collectionEvm.methods.properties(nextTokenId, []).call())
+ .to.be.like([
+ [
+ 'key',
+ '0x' + Buffer.from('Value').toString('hex'),
+ ],
+ ]);
+ expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+ }
+ });
+
+ itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddr(sponsor);
+ const user = helper.eth.createAccount();
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Sponsor collection',
+ description: '1',
+ tokenPrefix: '1',
+ collectionMode: 'nft',
+ pendingSponsor: sponsorCross,
+ adminList: [userCross],
+ },
+ '',
+ );
+
+ const collectionSub = helper.nft.getCollectionObject(collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ // Set collection sponsor:
+ let collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+ await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+ collectionData = (await collectionSub.getData())!;
+ expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+
+ const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+
+ const event = helper.eth.normalizeEvents(mintingResult.events)
+ .find(event => event.event === 'Transfer');
+ const address = helper.ethAddress.fromCollectionId(collectionId);
+
+ expect(event).to.be.deep.equal({
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: '1',
+ },
+ });
+ expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ });
+
+ itEth('Can reassign collection sponsor', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCrossEth = helper.ethCrossAccount.fromAddr(sponsorEth);
+ const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
+ const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
+
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Sponsor collection',
+ description: '1',
+ tokenPrefix: '1',
+ collectionMode: 'nft',
+ pendingSponsor: sponsorCrossEth,
+ },
+ '',
+ );
+ const collectionSub = helper.nft.getCollectionObject(collectionId);
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ // Set and confirm sponsor:
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+
+ // Can reassign sponsor:
+ await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
+ const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
+ expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
+ });
+
+ [
+ 'transfer',
+ 'transferCross',
+ 'transferFrom',
+ 'transferFromCross',
+ ].map(testCase =>
+ itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddr(sponsor);
+ const user = await helper.eth.createAccountWithBalance(donor);
+ const userCross = helper.ethCrossAccount.fromAddress(user);
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Sponsor collection',
+ description: '1',
+ tokenPrefix: '1',
+ collectionMode: 'rft',
+ pendingSponsor: sponsorCross,
+ adminList: [userCross],
+ },
+ '',
+ );
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+
+ const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+ switch (testCase) {
+ case 'transfer':
+ await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});
+ break;
+ case 'transferCross':
+ await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
+ break;
+ case 'transferFrom':
+ await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});
+ break;
+ case 'transferFromCross':
+ await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
+ break;
+ }
+
+ const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+ const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+ expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+ }));
+ });
+
+ describe('Collection admins', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`can add account admin by owner for ${testCase.mode}`, testCase.requiredPallets, async ({helper, privateKey}) => {
+ // arrange
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const adminSub = await privateKey('//admin2');
+ const adminEth = helper.eth.createAccount().toLowerCase();
+
+ const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Mint collection',
+ description: 'a',
+ tokenPrefix: 'b',
+ collectionMode: testCase.mode,
+ adminList: [adminCrossSub, adminCrossEth],
+ },
+ ).send();
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, true);
+
+ // 1. Expect api.rpc.unique.adminlist returns admins:
+ const adminListRpc = await helper.collection.getAdmins(collectionId);
+ expect(adminListRpc).to.has.length(2);
+ expect(adminListRpc).to.be.deep.contain.members([{Substrate: adminSub.address}, {Ethereum: adminEth}]);
+
+ // 2. Expect methods.collectionAdmins == api.rpc.unique.adminlist
+ let adminListEth = await collectionEvm.methods.collectionAdmins().call();
+ adminListEth = adminListEth.map((element: IEthCrossAccountId) => helper.address.convertCrossAccountFromEthCrossAccount(element));
+ expect(adminListRpc).to.be.like(adminListEth);
+
+ // 3. check isOwnerOrAdminCross returns true:
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.true;
+ expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.true;
+ });
+ });
+
+ itEth('cross account admin can mint', async ({helper}) => {
+ // arrange: create collection and accounts
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+ const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+ const [adminSub] = await helper.arrange.createAccounts([100n], donor);
+ const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Mint collection',
+ description: 'a',
+ tokenPrefix: 'b',
+ collectionMode: 'nft',
+ adminList: [adminCrossSub, adminCrossEth],
+ },
+ 'uri',
+ );
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+
+ // admin (sub and eth) can mint token:
+ await collectionEvm.methods.mint(owner).send({from: adminEth});
+ await helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}});
+
+ expect(await helper.collection.getLastTokenId(collectionId)).to.eq(2);
+ });
+
+ itEth('cannot add invalid cross account admin', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const [admin] = await helper.arrange.createAccounts([100n, 100n], donor);
+
+ const adminCross = {
+ eth: helper.address.substrateToEth(admin.address),
+ sub: admin.addressRaw,
+ };
+
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft',
+ adminList: [adminCross],
+ },
+ ).call()).to.be.rejected;
+ });
+
+ itEth('Remove [cross] admin by owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const [adminSub] = await helper.arrange.createAccounts([10n], donor);
+ const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+ const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+ const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft',
+ adminList: [adminCrossSub, adminCrossEth],
+ },
+ ).send();
+
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ {
+ const adminList = await helper.collection.getAdmins(collectionId);
+ expect(adminList).to.deep.include({Substrate: adminSub.address});
+ expect(adminList).to.deep.include({Ethereum: adminEth});
+ }
+
+ await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send();
+ await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send();
+ const adminList = await helper.collection.getAdmins(collectionId);
+ expect(adminList.length).to.be.eq(0);
+
+ // Non admin cannot mint:
+ await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
+ await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected;
+ });
+ });
+
+ describe('Collection limits', () => {
+ describe('Can set collection limits', () => {
+ [
+ {case: 'nft' as const},
+ {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {case: 'ft' as const},
+ ].map(testCase =>
+ itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const limits = {
+ accountTokenOwnershipLimit: 1000n,
+ sponsoredDataSize: 1024n,
+ sponsoredDataRateLimit: 30n,
+ tokenLimit: 1000000n,
+ sponsorTransferTimeout: 6n,
+ sponsorApproveTimeout: 6n,
+ ownerCanTransfer: 1n,
+ ownerCanDestroy: 0n,
+ transfersEnabled: 0n,
+ };
+
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Limits',
+ description: 'absolutely anything',
+ tokenPrefix: 'FLO',
+ collectionMode: testCase.case,
+ limits: [
+ {field: CollectionLimitField.AccountTokenOwnership, value: limits.accountTokenOwnershipLimit},
+ {field: CollectionLimitField.SponsoredDataSize, value: limits.sponsoredDataSize},
+ {field: CollectionLimitField.SponsoredDataRateLimit, value: limits.sponsoredDataRateLimit},
+ {field: CollectionLimitField.TokenLimit, value: limits.tokenLimit},
+ {field: CollectionLimitField.SponsorTransferTimeout, value: limits.sponsorTransferTimeout},
+ {field: CollectionLimitField.SponsorApproveTimeout, value: limits.sponsorApproveTimeout},
+ {field: CollectionLimitField.OwnerCanTransfer, value: limits.ownerCanTransfer},
+ {field: CollectionLimitField.OwnerCanDestroy, value: limits.ownerCanDestroy},
+ {field: CollectionLimitField.TransferEnabled, value: limits.transfersEnabled},
+ ],
+ },
+ ).send();
+
+ const expectedLimits = {
+ accountTokenOwnershipLimit: 1000,
+ sponsoredDataSize: 1024,
+ sponsoredDataRateLimit: {blocks: 30},
+ tokenLimit: 1000000,
+ sponsorTransferTimeout: 6,
+ sponsorApproveTimeout: 6,
+ ownerCanTransfer: true,
+ ownerCanDestroy: false,
+ transfersEnabled: false,
+ };
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
+
+ // Check limits from sub:
+ const data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.limits).to.deep.eq(expectedLimits);
+ expect(await helper.collection.getEffectiveLimits(collectionId)).to.deep.eq(expectedLimits);
+ // Check limits from eth:
+ const limitsEvm = await collectionEvm.methods.collectionLimits().call({from: owner});
+ expect(limitsEvm).to.have.length(9);
+ expect(limitsEvm[0]).to.deep.eq([CollectionLimitField.AccountTokenOwnership.toString(), [true, limits.accountTokenOwnershipLimit.toString()]]);
+ expect(limitsEvm[1]).to.deep.eq([CollectionLimitField.SponsoredDataSize.toString(), [true, limits.sponsoredDataSize.toString()]]);
+ expect(limitsEvm[2]).to.deep.eq([CollectionLimitField.SponsoredDataRateLimit.toString(), [true, limits.sponsoredDataRateLimit.toString()]]);
+ expect(limitsEvm[3]).to.deep.eq([CollectionLimitField.TokenLimit.toString(), [true, limits.tokenLimit.toString()]]);
+ expect(limitsEvm[4]).to.deep.eq([CollectionLimitField.SponsorTransferTimeout.toString(), [true, limits.sponsorTransferTimeout.toString()]]);
+ expect(limitsEvm[5]).to.deep.eq([CollectionLimitField.SponsorApproveTimeout.toString(), [true, limits.sponsorApproveTimeout.toString()]]);
+ expect(limitsEvm[6]).to.deep.eq([CollectionLimitField.OwnerCanTransfer.toString(), [true, limits.ownerCanTransfer.toString()]]);
+ expect(limitsEvm[7]).to.deep.eq([CollectionLimitField.OwnerCanDestroy.toString(), [true, limits.ownerCanDestroy.toString()]]);
+ expect(limitsEvm[8]).to.deep.eq([CollectionLimitField.TransferEnabled.toString(), [true, limits.transfersEnabled.toString()]]);
+ }));
+ });
+
+ describe('(!negative test!) Cannot set invalid collection limits', () => {
+ [
+ {case: 'nft' as const},
+ {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {case: 'ft' as const},
+ ].map(testCase =>
+ itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
+ const invalidLimits = {
+ accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),
+ transfersEnabled: 3,
+ };
+
+ const createCollectionData = {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'Limits',
+ description: 'absolutely anything',
+ tokenPrefix: 'ISNI',
+ collectionMode: testCase.case,
+ };
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ limits: [{field: 9 as CollectionLimitField, value: 1n}],
+ },
+ ).call()).to.be.rejectedWith('value not convertible into enum "CollectionLimitField"');
+
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ limits: [{field: CollectionLimitField.AccountTokenOwnership, value: invalidLimits.accountTokenOwnershipLimit}],
+ },
+ ).call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);
+
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ limits: [{field: CollectionLimitField.TransferEnabled, value: 3n}],
+ },
+ ).call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);
+
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ limits: [{field: CollectionLimitField.SponsoredDataSize, value: -1n}],
+ },
+ ).call()).to.be.rejectedWith('value out-of-bounds');
+ }));
+ });
+ });
+
+ describe('Collection properties', () => {
+
+ [
+ {mode: 'nft' as const, methodParams: [{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
+ {mode: 'rft' as const, methodParams: [{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
+ {mode: 'ft' as const, methodParams: [{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Collection properties can be set for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'name',
+ description: 'test',
+ tokenPrefix: 'test',
+ collectionMode: testCase.mode,
+ adminList: [callerCross],
+ properties: testCase.methodParams,
+ },
+ ).send();
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, caller);
+
+ const raw = (await helper[testCase.mode].getData(collectionId))?.raw;
+ expect(raw.properties).to.deep.equal(testCase.expectedProps);
+
+ // collectionProperties returns properties:
+ expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like(testCase.expectedProps.map(prop => helper.ethProperty.property(prop.key, prop.value)));
+ }));
+
+ [
+ {mode: 'nft' as const},
+ {mode: 'rft' as const},
+ {mode: 'ft' as const},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Collection properties can be deleted for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'name',
+ description: 'test',
+ tokenPrefix: 'test',
+ collectionMode: testCase.mode,
+ adminList: [callerCross],
+ properties:[
+ {key: 'testKey1', value: Buffer.from('testValue1')},
+ {key: 'testKey2', value: Buffer.from('testValue2')},
+ {key: 'testKey3', value: Buffer.from('testValue3')}],
+ },
+ ).send();
+
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, caller);
+
+ await collectionEvm.methods.deleteCollectionProperties(['testKey1', 'testKey2']).send({from: caller});
+
+ const raw = (await helper[testCase.mode].getData(collectionId))?.raw;
+
+ expect(raw.properties.length).to.equal(1);
+ expect(raw.properties).to.deep.equal([{key: 'testKey3', value: 'testValue3'}]);
+ }));
+
+ itEth('(!negative test!) Cannot set invalid properties', async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const createCollectionData = {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'name',
+ description: 'test',
+ tokenPrefix: 'test',
+ collectionMode: 'nft' as TCollectionMode,
+ adminList: [callerCross],
+ };
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ properties: [{key: '', value: Buffer.from('val1')}],
+ },
+ ).call()).to.be.rejected;
+
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ properties: [{key: 'déjà vu', value: Buffer.from('hmm...')}],
+ },
+ ).call()).to.be.rejected;
+
+ await expect(helper.eth.createCollection(
+ owner,
+ {
+ ...createCollectionData,
+ properties: [{key: 'a'.repeat(257), value: Buffer.from('val3')}],
+ },
+ ).call()).to.be.rejected;
+ });
+
+ itEth('(!negative test!) cannot delete properties of non-owned collections', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'name',
+ description: 'test',
+ tokenPrefix: 'test',
+ collectionMode: 'nft',
+ properties:[
+ {key: 'testKey1', value: Buffer.from('testValue1')},
+ {key: 'testKey2', value: Buffer.from('testValue2')}],
+ },
+ ).send();
+
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
+
+ await expect(collectionEvm.methods.deleteCollectionProperties(['testKey2']).send({from: caller})).to.be.rejected;
+ });
+ });
+
+ describe('Token property permissions', () => {
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can set all possible token property permissions`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: testCase.mode,
+ adminList: [caller],
+ tokenPropertyPermissions: [
+ {
+ key: 'testKey',
+ permissions: [
+ {code: TokenPermissionField.Mutable, value: mutable},
+ {code: TokenPermissionField.TokenOwner, value: tokenOwner},
+ {code: TokenPermissionField.CollectionAdmin, value: collectionAdmin},
+ ],
+ },
+ ],
+ },
+ ).send();
+ const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{
+ key: 'testKey',
+ permission: {mutable, collectionAdmin, tokenOwner},
+ }]);
+
+ expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([
+ ['testKey', [
+ [TokenPermissionField.Mutable.toString(), mutable],
+ [TokenPermissionField.TokenOwner.toString(), tokenOwner],
+ [TokenPermissionField.CollectionAdmin.toString(), collectionAdmin]],
+ ],
+ ]);
+ }
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: testCase.mode,
+ tokenPropertyPermissions: [
+ {
+ key: 'testKey_0',
+ permissions: [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.TokenOwner, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true}],
+ },
+ {
+ key: 'testKey_1',
+ permissions: [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.TokenOwner, value: false},
+ {code: TokenPermissionField.CollectionAdmin, value: true}],
+ },
+ {
+ key: 'testKey_2',
+ permissions: [
+ {code: TokenPermissionField.Mutable, value: false},
+ {code: TokenPermissionField.TokenOwner, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: false}],
+ },
+ ],
+ },
+ ).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([
+ {
+ key: 'testKey_0',
+ permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+ },
+ {
+ key: 'testKey_1',
+ permission: {mutable: true, tokenOwner: false, collectionAdmin: true},
+ },
+ {
+ key: 'testKey_2',
+ permission: {mutable: false, tokenOwner: true, collectionAdmin: false},
+ },
+ ]);
+
+ expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([
+ ['testKey_0', [
+ [TokenPermissionField.Mutable.toString(), true],
+ [TokenPermissionField.TokenOwner.toString(), true],
+ [TokenPermissionField.CollectionAdmin.toString(), true]],
+ ],
+ ['testKey_1', [
+ [TokenPermissionField.Mutable.toString(), true],
+ [TokenPermissionField.TokenOwner.toString(), false],
+ [TokenPermissionField.CollectionAdmin.toString(), true]],
+ ],
+ ['testKey_2', [
+ [TokenPermissionField.Mutable.toString(), false],
+ [TokenPermissionField.TokenOwner.toString(), true],
+ [TokenPermissionField.CollectionAdmin.toString(), false]],
+ ],
+ ]);
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Can be deleted for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(
+ caller,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: testCase.mode,
+ adminList: [receiver],
+ tokenPropertyPermissions: [
+ {
+ key: 'testKey',
+ permissions: [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true}],
+ },
+ {
+ key: 'testKey_1',
+ permissions: [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true}],
+ },
+ ],
+ },
+ ).send();
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, caller);
+ const tokenId = (await collection.methods.mintCross(receiver, [{key: 'testKey', value: Buffer.from('testValue')}, {key: 'testKey_1', value: Buffer.from('testValue_1')}]).send()).events.Transfer.returnValues.tokenId;
+ expect(await collection.methods.properties(tokenId, ['testKey', 'testKey_1']).call()).to.has.length(2);
+
+ await collection.methods.deleteProperties(tokenId, ['testKey', 'testKey_1']).send({from: caller});
+ expect(await collection.methods.properties(tokenId, ['testKey', 'testKey_1']).call()).to.has.length(0);
+ }));
+ });
+
+ describe('Nesting', () => {
+ itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft',
+ nestingSettings: {token_owner: true, collection_admin: false, restricted: []},
+ },
+ ).send();
+
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ // Create a token to be nested to
+ const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
+
+ // Create a nested token
+ const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});
+ const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;
+ expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Create a token to be nested and nest
+ const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Unnest token back
+ await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
+ });
+
+ itEth('NFT: collectionNesting()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress: unnestedCollectionAddress} = await helper.eth.createCollection(
+ owner,
+ new CreateCollectionData('A', 'B', 'C', 'nft'),
+ ).send();
+
+ const unnestedContract = helper.ethNativeContract.collection(unnestedCollectionAddress, 'nft', owner);
+ expect(await unnestedContract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
+
+ const {collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft',
+ nestingSettings: {token_owner: true, collection_admin: false, restricted: [unnestedCollectionAddress.toString()]},
+ },
+ ).send();
+
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([true, false, [unnestedCollectionAddress.toString()]]);
+ await contract.methods.setCollectionNesting([false, false, []]).send({from: owner});
+ expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
+ });
+
+ itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(
+ owner,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft',
+ nestingSettings: {token_owner: false, collection_admin: false, restricted: []},
+ },
+ ).send();
+
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ // Create a token to nest into
+ const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
+
+ // Create a token to nest
+ const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ // Try to nest
+ await expect(contract.methods
+ .transfer(targetNftTokenAddress, nftTokenId)
+ .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+ });
+
+ describe('Flags', () => {
+ const createCollectionData = {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft' as TCollectionMode,
+ };
+
+ itEth('NFT: use numbers for flags', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ {
+ const {collectionId} = await helper.eth.createCollection(owner, {...createCollectionData, flags: 0}).send();
+ expect((await helper.nft.getData(collectionId))?.raw.flags).to.be.deep.equal({foreign: false, erc721metadata: false});
+ }
+
+ {
+ const {collectionId} = await helper.eth.createCollection(owner, {...createCollectionData, flags: 64}).send();
+ expect((await helper.nft.getData(collectionId))?.raw.flags).to.be.deep.equal({foreign: false, erc721metadata: true});
+ }
+ });
+
+ itEth('NFT: can\'t set foreign flag number', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ {
+ await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: 128}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
+ }
+
+ {
+ await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: 192}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
+ }
+ });
+
+ itEth('NFT: use enum for flags', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ {
+ const {collectionId} = await helper.eth.createCollection(owner, {...createCollectionData, flags: [CollectionFlag.Erc721metadata]}).send();
+ expect((await helper.nft.getData(collectionId))?.raw.flags).to.be.deep.equal({foreign: false, erc721metadata: true});
+ }
+ });
+
+ itEth('NFT: foreign flag enum is ignored', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ {
+ await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: [CollectionFlag.Foreign]}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
+ }
+
+ {
+ await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: [CollectionFlag.Erc721metadata | CollectionFlag.Foreign]}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
+ }
+ });
+ });
+});
js-packages/tests/eth/createFTCollection.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/createFTCollection.seqtest.ts
@@ -0,0 +1,76 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+
+const DECIMALS = 18;
+
+describe('Create FT collection from EVM', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Create collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+
+ // todo:playgrounds this might fail when in async environment.
+ const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
+
+ const {collectionId} = await helper.eth.createFungibleCollection(owner, name, DECIMALS, description, prefix);
+
+ const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
+ const data = (await helper.ft.getData(collectionId))!;
+
+ expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
+ expect(collectionId).to.be.eq(collectionCountAfter);
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.deep.eq({Fungible: DECIMALS.toString()});
+ });
+
+ // todo:playgrounds this test will fail when in async environment.
+ itEth('Check collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
+ const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(expectedCollectionAddress)
+ .call()).to.be.false;
+
+
+ await helper.eth.createFungibleCollection(owner, 'A', DECIMALS, 'A', 'A');
+
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(expectedCollectionAddress)
+ .call()).to.be.true;
+ });
+});
js-packages/tests/eth/createFTCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/createFTCollection.test.ts
@@ -0,0 +1,237 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {evmToAddress} from '@polkadot/util-crypto';
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {CollectionLimitField} from './util/playgrounds/types.js';
+
+const DECIMALS = 18;
+
+describe('Create FT collection from EVM', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ // TODO move sponsorship tests to another file:
+ // Soft-deprecated
+ itEth('[eth] Set sponsorship', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const description = 'absolutely anything';
+
+ const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');
+
+ const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ await collection.methods.setCollectionSponsor(sponsor).send();
+
+ let data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+ });
+
+ itEth('[cross] Set sponsorship', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const description = 'absolutely anything';
+ const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await collection.methods.setCollectionSponsorCross(sponsorCross).send();
+
+ let data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+ expect(await collection.methods.description().call()).to.deep.equal(description);
+ });
+
+ itEth('Collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
+ .to.be.false;
+
+ const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddress).call())
+ .to.be.true;
+
+ // check collectionOwner:
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ const collectionOwner = await collectionEvm.methods.collectionOwner().call();
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
+ });
+
+ itEth('destroyCollection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+
+ const result = await collectionHelper.methods
+ .destroyCollection(collectionAddress)
+ .send({from: owner});
+
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address: collectionHelper.options.address,
+ event: 'CollectionDestroyed',
+ args: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+
+ expect(await collectionHelper.methods
+ .isCollectionExist(collectionAddress)
+ .call()).to.be.false;
+ expect(await helper.collection.getData(collectionId)).to.be.null;
+ });
+});
+
+describe('(!negative tests!) Create FT collection from EVM', () => {
+ let donor: IKeyringPair;
+ let nominal: bigint;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
+ donor = await privateKey({url: import.meta.url});
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ {
+ const MAX_NAME_LENGTH = 64;
+ const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
+ const description = 'A';
+ const tokenPrefix = 'A';
+
+ await expect(collectionHelper.methods
+ .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
+ }
+ {
+ const MAX_DESCRIPTION_LENGTH = 256;
+ const collectionName = 'A';
+ const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
+ const tokenPrefix = 'A';
+ await expect(collectionHelper.methods
+ .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
+ }
+ {
+ const MAX_TOKEN_PREFIX_LENGTH = 16;
+ const collectionName = 'A';
+ const description = 'A';
+ const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
+ await expect(collectionHelper.methods
+ .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
+ }
+ });
+
+ itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ const expects = [0n, 1n, 30n].map(async value => {
+ await expect(collectionHelper.methods
+ .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')
+ .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+ await Promise.all(expects);
+ });
+
+ // Soft-deprecated
+ itEth('(!negative test!) [eth] Check owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const peasant = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');
+ const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant, true);
+ const EXPECTED_ERROR = 'NoPermission';
+ {
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ await expect(peasantCollection.methods
+ .setCollectionSponsor(sponsor)
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor, true);
+ await expect(sponsorCollection.methods
+ .confirmCollectionSponsorship()
+ .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ }
+ {
+ await expect(peasantCollection.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+ }
+ });
+
+ itEth('(!negative test!) [cross] Check owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const peasant = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');
+ const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant);
+ const EXPECTED_ERROR = 'NoPermission';
+ {
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await expect(peasantCollection.methods
+ .setCollectionSponsorCross(sponsorCross)
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor);
+ await expect(sponsorCollection.methods
+ .confirmCollectionSponsorship()
+ .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ }
+ {
+ await expect(peasantCollection.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+ }
+ });
+});
js-packages/tests/eth/createNFTCollection.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/createNFTCollection.seqtest.ts
@@ -0,0 +1,89 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+
+
+describe('Create NFT collection from EVM', () => {
+ let donor: IKeyringPair;
+
+ before(async function () {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Create collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+
+ // todo:playgrounds this might fail when in async environment.
+ const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
+ const {collectionId, collectionAddress, events} = await helper.eth.createNFTCollection(owner, name, description, prefix);
+
+ expect(events).to.be.deep.equal([
+ {
+ address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',
+ event: 'CollectionCreated',
+ args: {
+ owner: owner,
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+
+ const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
+
+ const collection = helper.nft.getCollectionObject(collectionId);
+ const data = (await collection.getData())!;
+
+ expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
+ expect(collectionId).to.be.eq(collectionCountAfter);
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('NFT');
+
+ const options = await collection.getOptions();
+
+ expect(options.tokenPropertyPermissions).to.be.empty;
+ });
+
+ // this test will occasionally fail when in async environment.
+ itEth('Check collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
+ const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(expectedCollectionAddress)
+ .call()).to.be.false;
+
+ await collectionHelpers.methods
+ .createNFTCollection('A', 'A', 'A')
+ .send({value: Number(2n * helper.balance.getOneTokenNominal())});
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(expectedCollectionAddress)
+ .call()).to.be.true;
+ });
+});
js-packages/tests/eth/createNFTCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/createNFTCollection.test.ts
@@ -0,0 +1,275 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {evmToAddress} from '@polkadot/util-crypto';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {CollectionLimitField} from './util/playgrounds/types.js';
+
+
+describe('Create NFT collection from EVM', () => {
+ let donor: IKeyringPair;
+
+ before(async function () {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Create collection with properties & get desctription', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+ const baseUri = 'BaseURI';
+
+ const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ expect(events).to.be.deep.equal([
+ {
+ address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',
+ event: 'CollectionCreated',
+ args: {
+ owner: owner,
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+
+ const collection = helper.nft.getCollectionObject(collectionId);
+ const data = (await collection.getData())!;
+
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('NFT');
+
+ expect(await contract.methods.description().call()).to.deep.equal(description);
+
+ const options = await collection.getOptions();
+ expect(options.tokenPropertyPermissions).to.be.deep.equal([
+ {
+ key: 'URI',
+ permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
+ },
+ {
+ key: 'URISuffix',
+ permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
+ },
+ ]);
+ });
+
+ // Soft-deprecated
+ itEth('[eth] Set sponsorship', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+ await collection.methods.setCollectionSponsor(sponsor).send();
+
+ let data = (await helper.nft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.nft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+ });
+
+ itEth('[cross] Set sponsorship & get description', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const description = 'absolutely anything';
+ const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', description, 'ROC');
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await collection.methods.setCollectionSponsorCross(sponsorCross).send();
+
+ let data = (await helper.nft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.nft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ expect(await sponsorCollection.methods.description().call()).to.deep.equal(description);
+ });
+
+ itEth('Collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
+ .to.be.false;
+
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Exister', 'absolutely anything', 'EVC');
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddress).call())
+ .to.be.true;
+
+ // check collectionOwner:
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ const collectionOwner = await collectionEvm.methods.collectionOwner().call();
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
+ });
+});
+
+describe('(!negative tests!) Create NFT collection from EVM', () => {
+ let donor: IKeyringPair;
+ let nominal: bigint;
+
+ before(async function () {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ {
+ const MAX_NAME_LENGTH = 64;
+ const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
+ const description = 'A';
+ const tokenPrefix = 'A';
+
+ await expect(collectionHelper.methods
+ .createNFTCollection(collectionName, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
+
+ }
+ {
+ const MAX_DESCRIPTION_LENGTH = 256;
+ const collectionName = 'A';
+ const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
+ const tokenPrefix = 'A';
+ await expect(collectionHelper.methods
+ .createNFTCollection(collectionName, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
+ }
+ {
+ const MAX_TOKEN_PREFIX_LENGTH = 16;
+ const collectionName = 'A';
+ const description = 'A';
+ const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
+ await expect(collectionHelper.methods
+ .createNFTCollection(collectionName, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
+ }
+ });
+
+ itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ await expect(collectionHelper.methods
+ .createNFTCollection('Peasantry', 'absolutely anything', 'CVE')
+ .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+
+ // Soft-deprecated
+ itEth('(!negative test!) [eth] Check owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malfeasant = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR');
+ const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant, true);
+ const EXPECTED_ERROR = 'NoPermission';
+ {
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ await expect(malfeasantCollection.methods
+ .setCollectionSponsor(sponsor)
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);
+ await expect(sponsorCollection.methods
+ .confirmCollectionSponsorship()
+ .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ }
+ {
+ await expect(malfeasantCollection.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+ }
+ });
+
+ itEth('(!negative test!) [cross] Check owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malfeasant = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR');
+ const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant);
+ const EXPECTED_ERROR = 'NoPermission';
+ {
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await expect(malfeasantCollection.methods
+ .setCollectionSponsorCross(sponsorCross)
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
+ await expect(sponsorCollection.methods
+ .confirmCollectionSponsorship()
+ .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ }
+ {
+ await expect(malfeasantCollection.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+ }
+ });
+
+ itEth('destroyCollection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+
+
+ const result = await collectionHelper.methods
+ .destroyCollection(collectionAddress)
+ .send({from: owner});
+
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address: collectionHelper.options.address,
+ event: 'CollectionDestroyed',
+ args: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+
+ expect(await collectionHelper.methods
+ .isCollectionExist(collectionAddress)
+ .call()).to.be.false;
+ expect(await helper.collection.getData(collectionId)).to.be.null;
+ });
+});
js-packages/tests/eth/createRFTCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/createRFTCollection.test.ts
@@ -0,0 +1,273 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {evmToAddress} from '@polkadot/util-crypto';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {CollectionLimitField} from './util/playgrounds/types.js';
+
+
+describe('Create RFT collection from EVM', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Create collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+
+ const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix);
+ const data = (await helper.rft.getData(collectionId))!;
+ const collection = helper.rft.getCollectionObject(collectionId);
+
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('ReFungible');
+
+ const options = await collection.getOptions();
+
+ expect(options.tokenPropertyPermissions).to.be.empty;
+ });
+
+
+
+ itEth('Create collection with properties & get description', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const name = 'CollectionEVM';
+ const description = 'Some description';
+ const prefix = 'token prefix';
+ const baseUri = 'BaseURI';
+
+ const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const collection = helper.rft.getCollectionObject(collectionId);
+ const data = (await collection.getData())!;
+
+ expect(data.name).to.be.eq(name);
+ expect(data.description).to.be.eq(description);
+ expect(data.raw.tokenPrefix).to.be.eq(prefix);
+ expect(data.raw.mode).to.be.eq('ReFungible');
+
+ expect(await contract.methods.description().call()).to.deep.equal(description);
+
+ const options = await collection.getOptions();
+ expect(options.tokenPropertyPermissions).to.be.deep.equal([
+ {
+ key: 'URI',
+ permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
+ },
+ {
+ key: 'URISuffix',
+ permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
+ },
+ ]);
+ });
+
+ // Soft-deprecated
+ itEth('[eth] Set sponsorship', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);
+ await collection.methods.setCollectionSponsor(sponsor).send();
+
+ let data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+ });
+
+ itEth('[cross] Set sponsorship', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');
+
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await collection.methods.setCollectionSponsorCross(sponsorCross).send();
+
+ let data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+
+ await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
+ await sponsorCollection.methods.confirmCollectionSponsorship().send();
+
+ data = (await helper.rft.getData(collectionId))!;
+ expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
+ });
+
+ itEth('Collection address exist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
+ const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
+ .to.be.false;
+
+ const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT');
+ expect(await collectionHelpers
+ .methods.isCollectionExist(collectionAddress).call())
+ .to.be.true;
+
+ // check collectionOwner:
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ const collectionOwner = await collectionEvm.methods.collectionOwner().call();
+ expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
+ });
+});
+
+describe('(!negative tests!) Create RFT collection from EVM', () => {
+ let donor: IKeyringPair;
+ let nominal: bigint;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ {
+ const MAX_NAME_LENGTH = 64;
+ const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
+ const description = 'A';
+ const tokenPrefix = 'A';
+
+ await expect(collectionHelper.methods
+ .createRFTCollection(collectionName, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
+ }
+ {
+ const MAX_DESCRIPTION_LENGTH = 256;
+ const collectionName = 'A';
+ const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
+ const tokenPrefix = 'A';
+ await expect(collectionHelper.methods
+ .createRFTCollection(collectionName, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
+ }
+ {
+ const MAX_TOKEN_PREFIX_LENGTH = 16;
+ const collectionName = 'A';
+ const description = 'A';
+ const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
+ await expect(collectionHelper.methods
+ .createRFTCollection(collectionName, description, tokenPrefix)
+ .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
+ }
+ });
+
+ itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+ await expect(collectionHelper.methods
+ .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')
+ .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+
+ // Soft-deprecated
+ itEth('(!negative test!) [eth] Check owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const peasant = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');
+ const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true);
+ const EXPECTED_ERROR = 'NoPermission';
+ {
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ await expect(peasantCollection.methods
+ .setCollectionSponsor(sponsor)
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
+ await expect(sponsorCollection.methods
+ .confirmCollectionSponsorship()
+ .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ }
+ {
+ await expect(peasantCollection.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+ }
+ });
+
+ itEth('(!negative test!) [cross] Check owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const peasant = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');
+ const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant);
+ const EXPECTED_ERROR = 'NoPermission';
+ {
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+ await expect(peasantCollection.methods
+ .setCollectionSponsorCross(sponsorCross)
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+
+ const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
+ await expect(sponsorCollection.methods
+ .confirmCollectionSponsorship()
+ .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+ }
+ {
+ await expect(peasantCollection.methods
+ .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
+ .call()).to.be.rejectedWith(EXPECTED_ERROR);
+ }
+ });
+
+ itEth('destroyCollection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
+ const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
+
+ await expect(collectionHelper.methods
+ .destroyCollection(collectionAddress)
+ .send({from: owner})).to.be.fulfilled;
+
+ expect(await collectionHelper.methods
+ .isCollectionExist(collectionAddress)
+ .call()).to.be.false;
+ expect(await helper.collection.getData(collectionId)).to.be.null;
+ });
+});
js-packages/tests/eth/crossTransfer.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/crossTransfer.test.ts
@@ -0,0 +1,105 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itEth, usingEthPlaygrounds} from './util/index.js';
+import {CrossAccountId} from '@unique/playgrounds/unique.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+describe('Token transfer between substrate address and EVM address. Fungible', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => {
+ const bobCA = CrossAccountId.fromKeyring(bob).toICrossAccountId();
+ const charlieCA = CrossAccountId.fromKeyring(charlie).toICrossAccountId();
+ const charlieCAEth = CrossAccountId.fromKeyring(charlie).toEthereum().toICrossAccountId();
+
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+
+ await collection.mint(alice, 200n);
+ await collection.transfer(alice, charlieCAEth, 200n);
+ await collection.transferFrom(alice, charlieCAEth, charlieCA, 50n);
+ await collection.transfer(charlie, bobCA, 50n);
+ });
+
+ itEth('The private key X create a EVM address. Alice sends a token to the substrate address corresponding to this EVM address, and X can send it to Bob in the EVM', async ({helper}) => {
+ const aliceProxy = await helper.eth.createAccountWithBalance(donor);
+ const bobProxy = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'ft', aliceProxy);
+
+ await collection.mint(alice, 200n, {Ethereum: aliceProxy});
+ await contract.methods.transfer(bobProxy, 50).send({from: aliceProxy});
+ await collection.transferFrom(alice, {Ethereum: bobProxy}, CrossAccountId.fromKeyring(bob).toICrossAccountId(), 50n);
+ await collection.transfer(bob, CrossAccountId.fromKeyring(alice).toICrossAccountId(), 50n);
+ });
+});
+
+describe('Token transfer between substrate address and EVM address. NFT', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => {
+ const charlieEth = CrossAccountId.fromKeyring(charlie, 'Ethereum').toICrossAccountId();
+
+ const collection = await helper.nft.mintCollection(alice);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ const token = await collection.mintToken(alice);
+ await token.transfer(alice, charlieEth);
+ await token.transferFrom(alice, charlieEth, CrossAccountId.fromKeyring(charlie).toICrossAccountId());
+ await token.transfer(charlie, CrossAccountId.fromKeyring(bob).toICrossAccountId());
+ });
+
+ itEth('The private key X create a EVM address. Alice sends a token to the substrate address corresponding to this EVM address, and X can send it to Bob in the EVM', async ({helper}) => {
+ const aliceProxy = await helper.eth.createAccountWithBalance(donor);
+ const bobProxy = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.nft.mintCollection(alice);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', aliceProxy);
+
+ const token = await collection.mintToken(alice);
+ await token.transfer(alice, {Ethereum: aliceProxy});
+ await contract.methods.transfer(bobProxy, 1).send({from: aliceProxy});
+ await token.transferFrom(alice, {Ethereum: bobProxy}, {Substrate: bob.address});
+ await token.transfer(bob, {Substrate: charlie.address});
+ });
+});
js-packages/tests/eth/destroyCollection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/destroyCollection.test.ts
@@ -0,0 +1,63 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import type {TCollectionMode} from '@unique/playgrounds/types.js';
+import {CreateCollectionData} from './util/playgrounds/types.js';
+
+describe('Destroy Collection from EVM', function() {
+ let donor: IKeyringPair;
+ const testCases = [
+ {case: 'rft' as const, params: ['Limits', 'absolutely anything', 'OLF', 'rft'], requiredPallets: [Pallets.ReFungible]},
+ {case: 'nft' as const, params: ['Limits', 'absolutely anything', 'OLF', 'nft'], requiredPallets: [Pallets.NFT]},
+ {case: 'ft' as const, params: ['Limits', 'absolutely anything', 'OLF', 'ft', 18], requiredPallets: [Pallets.Fungible]},
+ ];
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ testCases.map((testCase) =>
+ itEth.ifWithPallets(`Cannot burn non-owned or non-existing collection ${testCase.case}`, testCase.requiredPallets, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const signer = await helper.eth.createAccountWithBalance(donor);
+
+ const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
+
+ const collectionHelpers = await helper.ethNativeContract.collectionHelpers(signer);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData(...testCase.params as [string, string, string, TCollectionMode, number?])).send();
+ // cannot burn collec
+ await expect(collectionHelpers.methods
+ .destroyCollection(collectionAddress)
+ .send({from: signer})).to.be.rejected;
+
+ await expect(collectionHelpers.methods
+ .destroyCollection(unexistedCollection)
+ .send({from: signer})).to.be.rejected;
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(unexistedCollection)
+ .call()).to.be.false;
+
+ expect(await collectionHelpers.methods
+ .isCollectionExist(collectionAddress)
+ .call()).to.be.true;
+ }));
+});
js-packages/tests/eth/ethFeesAreCorrect.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/ethFeesAreCorrect.test.ts
@@ -0,0 +1,66 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://witww.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+
+describe('Eth fees are correct', () => {
+ let donor: IKeyringPair;
+ let minter: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [minter, alice] = await helper.arrange.createAccounts([100n, 200n], donor);
+ });
+ });
+
+
+ itEth('web3 fees are the same as evm.call fees', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const aliceEth = helper.address.substrateToEth(alice.address);
+
+ const {tokenId: tokenA} = await collection.mintToken(minter, {Ethereum: owner});
+ const {tokenId: tokenB} = await collection.mintToken(minter, {Ethereum: aliceEth});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ const balanceBeforeWeb3Transfer = await helper.balance.getEthereum(owner);
+ await contract.methods.transfer(receiver, tokenA).send({from: owner, maxFeePerGas: ((await helper.eth.getGasPrice())!).toString()});
+ const balanceAfterWeb3Transfer = await helper.balance.getEthereum(owner);
+ const web3Diff = balanceBeforeWeb3Transfer - balanceAfterWeb3Transfer;
+
+ const encodedCall = contract.methods.transfer(receiver, tokenB)
+ .encodeABI();
+
+ const balanceBeforeEvmCall = await helper.balance.getSubstrate(alice.address);
+ await helper.eth.sendEVM(
+ alice,
+ collectionAddress,
+ encodedCall,
+ '0',
+ );
+ const balanceAfterEvmCall = await helper.balance.getSubstrate(alice.address);
+ const evmCallDiff = balanceBeforeEvmCall - balanceAfterEvmCall;
+
+ expect(web3Diff).to.be.equal(evmCallDiff);
+ });
+});
js-packages/tests/eth/events.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/events.test.ts
@@ -0,0 +1,548 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect} from 'chai';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import type {IEvent, TCollectionMode} from '@unique/playgrounds/types.js';
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {CollectionLimitField, TokenPermissionField, CreateCollectionData} from './util/playgrounds/types.js';
+import type {NormalizedEvent} from './util/playgrounds/types.js';
+
+let donor: IKeyringPair;
+
+before(async function () {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+});
+
+function clearEvents(ethEvents: NormalizedEvent[] | null, subEvents: IEvent[]) {
+ if(ethEvents !== null) {
+ ethEvents.splice(0);
+ }
+ subEvents.splice(0);
+}
+
+async function testCollectionCreatedAndDestroy(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionCreated', 'CollectionDestroyed']}]);
+ const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+
+ await helper.wait.newBlocks(1);
+ {
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionCreated',
+ args: {
+ owner: owner,
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionCreated'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner});
+ await helper.wait.newBlocks(1);
+ expect(result.events).to.containSubset({
+ CollectionDestroyed: {
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ });
+ expect(subEvents).to.containSubset([{method: 'CollectionDestroyed'}]);
+ }
+ unsubscribe();
+}
+
+async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPropertySet', 'CollectionPropertyDeleted']}]);
+ {
+ await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionPropertySet'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ await collection.methods.deleteCollectionProperties(['A']).send({from:owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionPropertyDeleted'}]);
+ }
+ unsubscribe();
+}
+
+async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);
+ await collection.methods.setTokenPropertyPermissions([
+ ['A', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'PropertyPermissionSet'}]);
+ unsubscribe();
+}
+
+async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const user = helper.ethCrossAccount.createAccount();
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any[] = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['AllowListAddressAdded', 'AllowListAddressRemoved']}]);
+ {
+ await collection.methods.addToCollectionAllowListCross(user).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'AllowListAddressAdded'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'AllowListAddressRemoved'}]);
+ }
+ unsubscribe();
+}
+
+async function testCollectionAdminAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const user = helper.ethCrossAccount.createAccount();
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionAdminAdded', 'CollectionAdminRemoved']}]);
+ {
+ await collection.methods.addCollectionAdminCross(user).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionAdminAdded'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ await collection.methods.removeCollectionAdminCross(user).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionAdminRemoved'}]);
+ }
+ unsubscribe();
+}
+
+async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionLimitSet']}]);
+ {
+ await collection.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: 0}}).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionLimitSet'}]);
+ }
+ unsubscribe();
+}
+
+async function testCollectionOwnerChanged(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const newOwner = helper.ethCrossAccount.createAccount();
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnerChanged']}]);
+ {
+ await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionOwnerChanged'}]);
+ }
+ unsubscribe();
+}
+
+async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPermissionSet']}]);
+ {
+ await collection.methods.setCollectionMintMode(true).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ await collection.methods.setCollectionAccess(1).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);
+ }
+ unsubscribe();
+}
+
+async function testCollectionSponsorSetAndConfirmedAndThenRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
+ const ethEvents: any = [];
+ collectionHelper.events.allEvents((_: any, event: any) => {
+ ethEvents.push(event);
+ });
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{
+ section: 'common', names: ['CollectionSponsorSet', 'SponsorshipConfirmed', 'CollectionSponsorRemoved',
+ ]}]);
+ {
+ await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([{
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ }]);
+ expect(subEvents).to.containSubset([{method: 'CollectionSponsorSet'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'SponsorshipConfirmed'}]);
+ clearEvents(ethEvents, subEvents);
+ }
+ {
+ await collection.methods.removeCollectionSponsor().send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(ethEvents).to.containSubset([
+ {
+ event: 'CollectionChanged',
+ returnValues: {
+ collectionId: collectionAddress,
+ },
+ },
+ ]);
+ expect(subEvents).to.containSubset([{method: 'CollectionSponsorRemoved'}]);
+ }
+ unsubscribe();
+}
+
+async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
+ const result = await collection.methods.mint(owner).send({from: owner});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ await collection.methods.setTokenPropertyPermissions([
+ ['A', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).send({from: owner});
+
+ const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]);
+ {
+ const result = await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(result.events.TokenChanged).to.be.like({
+ event: 'TokenChanged',
+ returnValues: {
+ tokenId: tokenId,
+ },
+ });
+ expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]);
+ clearEvents(null, subEvents);
+ }
+ {
+ const result = await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});
+ await helper.wait.newBlocks(1);
+ expect(result.events.TokenChanged).to.be.like({
+ event: 'TokenChanged',
+ returnValues: {
+ tokenId: tokenId,
+ },
+ });
+ expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]);
+ }
+ unsubscribe();
+}
+
+describe('[FT] Sync sub & eth events', () => {
+ const mode: TCollectionMode = 'ft';
+
+ itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
+ await testCollectionCreatedAndDestroy(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {
+ await testCollectionPropertySetAndDeleted(helper, mode);
+ });
+
+ itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {
+ await testAllowListAddressAddedAndRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {
+ await testCollectionAdminAddedAndRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {
+ await testCollectionLimitSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
+ await testCollectionOwnerChanged(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {
+ await testCollectionPermissionSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {
+ await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);
+ });
+});
+
+describe('[NFT] Sync sub & eth events', () => {
+ const mode: TCollectionMode = 'nft';
+
+ itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
+ await testCollectionCreatedAndDestroy(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {
+ await testCollectionPropertySetAndDeleted(helper, mode);
+ });
+
+ itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {
+ await testPropertyPermissionSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {
+ await testAllowListAddressAddedAndRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {
+ await testCollectionAdminAddedAndRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {
+ await testCollectionLimitSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
+ await testCollectionOwnerChanged(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {
+ await testCollectionPermissionSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {
+ await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {
+ await testTokenPropertySetAndDeleted(helper, mode);
+ });
+});
+
+describe('[RFT] Sync sub & eth events', () => {
+ const mode: TCollectionMode = 'rft';
+
+ before(async function() {
+ await usingEthPlaygrounds((helper) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ return Promise.resolve();
+ });
+ });
+
+ itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
+ await testCollectionCreatedAndDestroy(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {
+ await testCollectionPropertySetAndDeleted(helper, mode);
+ });
+
+ itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {
+ await testPropertyPermissionSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {
+ await testAllowListAddressAddedAndRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {
+ await testCollectionAdminAddedAndRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {
+ await testCollectionLimitSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
+ await testCollectionOwnerChanged(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {
+ await testCollectionPermissionSet(helper, mode);
+ });
+
+ itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {
+ await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);
+ });
+
+ itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {
+ await testTokenPropertySetAndDeleted(helper, mode);
+ });
+});
js-packages/tests/eth/evmCoder.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/evmCoder.test.ts
@@ -0,0 +1,88 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
+
+const getContractSource = (collectionAddress: string, contractAddress: string): string => `
+ // SPDX-License-Identifier: MIT
+ pragma solidity ^0.8.0;
+ interface ITest {
+ function ztestzzzzzzz() external returns (uint256 n);
+ }
+ contract Test {
+ event Result(bool, uint256);
+ function test1() public {
+ try
+ ITest(${collectionAddress}).ztestzzzzzzz()
+ returns (uint256 n) {
+ // enters
+ emit Result(true, n); // => [true, BigNumber { value: "43648854190028290368124427828690944273759144372138548774646036134290060795932" }]
+ } catch {
+ emit Result(false, 0);
+ }
+ }
+ function test2() public {
+ try
+ ITest(${contractAddress}).ztestzzzzzzz()
+ returns (uint256 n) {
+ emit Result(true, n);
+ } catch {
+ // enters
+ emit Result(false, 0); // => [ false, BigNumber { value: "0" } ]
+ }
+ }
+ function test3() public {
+ ITest(${collectionAddress}).ztestzzzzzzz();
+ }
+ }
+ `;
+
+
+describe('Evm Coder tests', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Call non-existing function', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.eth.createNFTCollection(owner, 'EVMCODER', '', 'TEST');
+ const contract = await helper.ethContract.deployByCode(owner, 'Test', getContractSource(collection.collectionAddress, '0x1bfed5D614b886b9Ab2eA4CBAc22A96B7EC29c9c'));
+ const testContract = await helper.ethContract.deployByCode(owner, 'Test', getContractSource(collection.collectionAddress, contract.options.address));
+ {
+ const result = await testContract.methods.test1().send();
+ expect(result.events.Result.returnValues).to.deep.equal({
+ '0': false,
+ '1': '0',
+ });
+ }
+ {
+ const result = await testContract.methods.test2().send();
+ expect(result.events.Result.returnValues).to.deep.equal({
+ '0': false,
+ '1': '0',
+ });
+ }
+ {
+ await expect(testContract.methods.test3().call())
+ .to.be.rejectedWith(/unrecognized selector: 0xd9f02b36$/g);
+ }
+ });
+});
js-packages/tests/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/fractionalizer/Fractionalizer.sol
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: Apache License
+pragma solidity >=0.8.0;
+import {CollectionHelpers} from "../api/CollectionHelpers.sol";
+import {ContractHelpers} from "../api/ContractHelpers.sol";
+import {UniqueRefungibleToken} from "../api/UniqueRefungibleToken.sol";
+import {UniqueRefungible, CrossAddress} from "../api/UniqueRefungible.sol";
+import {UniqueNFT} from "../api/UniqueNFT.sol";
+
+/// @dev Fractionalization contract. It stores mappings between NFT and RFT tokens,
+/// stores allowlist of NFT tokens available for fractionalization, has methods
+/// for fractionalization and defractionalization of NFT tokens.
+contract Fractionalizer {
+ struct Token {
+ address _collection;
+ uint256 _tokenId;
+ }
+ address rftCollection;
+ mapping(address => bool) nftCollectionAllowList;
+ mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;
+ mapping(address => Token) public rft2nftMapping;
+ //use constant to reduce gas cost
+ bytes32 constant refungibleCollectionType = keccak256(bytes("ReFungible"));
+
+ receive() external payable onlyOwner {}
+
+ /// @dev Method modifier to only allow contract owner to call it.
+ modifier onlyOwner() {
+ address contracthelpersAddress = 0x842899ECF380553E8a4de75bF534cdf6fBF64049;
+ ContractHelpers contractHelpers = ContractHelpers(contracthelpersAddress);
+ address contractOwner = contractHelpers.contractOwner(address(this));
+ require(msg.sender == contractOwner, "Only owner can");
+ _;
+ }
+
+ /// @dev This emits when RFT collection setting is changed.
+ event RFTCollectionSet(address _collection);
+
+ /// @dev This emits when NFT collection is allowed or disallowed.
+ event AllowListSet(address _collection, bool _status);
+
+ /// @dev This emits when NFT token is fractionalized by contract.
+ event Fractionalized(address _collection, uint256 _tokenId, address _rftToken, uint128 _amount);
+
+ /// @dev This emits when NFT token is defractionalized by contract.
+ event Defractionalized(address _rftToken, address _nftCollection, uint256 _nftTokenId);
+
+ /// Set RFT collection that contract will work with. RFT tokens for fractionalized NFT tokens
+ /// would be created in this collection.
+ /// @dev Throws if RFT collection is already configured for this contract.
+ /// Throws if collection of wrong type (NFT, Fungible) is provided instead
+ /// of RFT collection.
+ /// Throws if `msg.sender` is not owner or admin of provided RFT collection.
+ /// Can only be called by contract owner.
+ /// @param _collection address of RFT collection.
+ function setRFTCollection(address _collection) external onlyOwner {
+ require(rftCollection == address(0), "RFT collection is already set");
+ UniqueRefungible refungibleContract = UniqueRefungible(_collection);
+ string memory collectionType = refungibleContract.uniqueCollectionType();
+
+ // compare hashed to reduce gas cost
+ require(
+ keccak256(bytes(collectionType)) == refungibleCollectionType,
+ "Wrong collection type. Collection is not refungible."
+ );
+ require(
+ refungibleContract.isOwnerOrAdminCross(CrossAddress({eth: address(this), sub: uint256(0)})),
+ "Fractionalizer contract should be an admin of the collection"
+ );
+ rftCollection = _collection;
+ emit RFTCollectionSet(rftCollection);
+ }
+
+ /// Creates and sets RFT collection that contract will work with. RFT tokens for fractionalized NFT tokens
+ /// would be created in this collection.
+ /// @dev Throws if RFT collection is already configured for this contract.
+ /// Can only be called by contract owner.
+ /// @param _name name for created RFT collection.
+ /// @param _description description for created RFT collection.
+ /// @param _tokenPrefix token prefix for created RFT collection.
+ function createAndSetRFTCollection(
+ string calldata _name,
+ string calldata _description,
+ string calldata _tokenPrefix
+ ) external payable onlyOwner {
+ require(rftCollection == address(0), "RFT collection is already set");
+ address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
+ rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection{value: msg.value}(
+ _name,
+ _description,
+ _tokenPrefix
+ );
+ emit RFTCollectionSet(rftCollection);
+ }
+
+ /// Allow or disallow NFT collection tokens from being fractionalized by this contract.
+ /// @dev Can only be called by contract owner.
+ /// @param collection NFT token address.
+ /// @param status `true` to allow and `false` to disallow NFT token.
+ function setNftCollectionIsAllowed(address collection, bool status) external onlyOwner {
+ nftCollectionAllowList[collection] = status;
+ emit AllowListSet(collection, status);
+ }
+
+ /// Fractionilize NFT token.
+ /// @dev Takes NFT token from `msg.sender` and transfers RFT token to `msg.sender`
+ /// instead. Creates new RFT token if provided NFT token never was fractionalized
+ /// by this contract or existing RFT token if it was.
+ /// Throws if RFT collection isn't configured for this contract.
+ /// Throws if fractionalization of provided NFT token is not allowed
+ /// Throws if `msg.sender` is not owner of provided NFT token
+ /// @param _collection NFT collection address
+ /// @param _token id of NFT token to be fractionalized
+ /// @param _pieces number of pieces new RFT token would have
+ function nft2rft(
+ address _collection,
+ uint256 _token,
+ uint128 _pieces
+ ) external {
+ require(rftCollection != address(0), "RFT collection is not set");
+ UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
+ require(
+ nftCollectionAllowList[_collection] == true,
+ "Fractionalization of this collection is not allowed by admin"
+ );
+ require(UniqueNFT(_collection).ownerOf(_token) == msg.sender, "Only token owner could fractionalize it");
+ UniqueNFT(_collection).transferFrom(msg.sender, address(this), _token);
+ uint256 rftTokenId;
+ address rftTokenAddress;
+ UniqueRefungibleToken rftTokenContract;
+ if (nft2rftMapping[_collection][_token] == 0) {
+ rftTokenId = rftCollectionContract.mint(address(this));
+ rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);
+ nft2rftMapping[_collection][_token] = rftTokenId;
+ rft2nftMapping[rftTokenAddress] = Token(_collection, _token);
+
+ rftTokenContract = UniqueRefungibleToken(rftTokenAddress);
+ } else {
+ rftTokenId = nft2rftMapping[_collection][_token];
+ rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);
+ rftTokenContract = UniqueRefungibleToken(rftTokenAddress);
+ }
+ rftTokenContract.repartition(_pieces);
+ rftTokenContract.transfer(msg.sender, _pieces);
+ emit Fractionalized(_collection, _token, rftTokenAddress, _pieces);
+ }
+
+ /// Defrationalize NFT token.
+ /// @dev Takes RFT token from `msg.sender` and transfers corresponding NFT token
+ /// to `msg.sender` instead.
+ /// Throws if RFT collection isn't configured for this contract.
+ /// Throws if provided RFT token is no from configured RFT collection.
+ /// Throws if RFT token was not created by this contract.
+ /// Throws if `msg.sender` isn't owner of all RFT token pieces.
+ /// @param _collection RFT collection address
+ /// @param _token id of RFT token
+ function rft2nft(address _collection, uint256 _token) external {
+ require(rftCollection != address(0), "RFT collection is not set");
+ require(rftCollection == _collection, "Wrong RFT collection");
+ UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
+ address rftTokenAddress = rftCollectionContract.tokenContractAddress(_token);
+ Token memory nftToken = rft2nftMapping[rftTokenAddress];
+ require(nftToken._collection != address(0), "No corresponding NFT token found");
+ UniqueRefungibleToken rftTokenContract = UniqueRefungibleToken(rftTokenAddress);
+ require(
+ rftTokenContract.balanceOf(msg.sender) == rftTokenContract.totalSupply(),
+ "Not all pieces are owned by the caller"
+ );
+ rftCollectionContract.transferFrom(msg.sender, address(this), _token);
+ UniqueNFT(nftToken._collection).transferFrom(address(this), msg.sender, nftToken._tokenId);
+ emit Defractionalized(rftTokenAddress, nftToken._collection, nftToken._tokenId);
+ }
+}
js-packages/tests/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/fractionalizer/fractionalizer.test.ts
@@ -0,0 +1,453 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+
+import {readFile} from 'fs/promises';
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {evmToAddress} from '@polkadot/util-crypto';
+
+import {Contract} from 'web3-eth-contract';
+
+import {usingEthPlaygrounds, expect, itEth} from '../util/index.js';
+import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import type {CompiledContract} from '../util/playgrounds/types.js';
+import {requirePalletsOrSkip, Pallets, makeNames} from '../../util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+let compiledFractionalizer: CompiledContract;
+
+const compileContract = async (helper: EthUniqueHelper): Promise<CompiledContract> => {
+ if(!compiledFractionalizer) {
+ compiledFractionalizer = await helper.ethContract.compile('Fractionalizer', (await readFile(`${dirname}/Fractionalizer.sol`)).toString(), [
+ {solPath: 'api/CollectionHelpers.sol', fsPath: `${dirname}/../api/CollectionHelpers.sol`},
+ {solPath: 'api/ContractHelpers.sol', fsPath: `${dirname}/../api/ContractHelpers.sol`},
+ {solPath: 'api/UniqueRefungibleToken.sol', fsPath: `${dirname}/../api/UniqueRefungibleToken.sol`},
+ {solPath: 'api/UniqueRefungible.sol', fsPath: `${dirname}/../api/UniqueRefungible.sol`},
+ {solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`},
+ ]);
+ }
+ return compiledFractionalizer;
+};
+
+
+const deployContract = async (helper: EthUniqueHelper, owner: string): Promise<Contract> => {
+ const compiled = await compileContract(helper);
+ return await helper.ethContract.deployByAbi(owner, compiled.abi, compiled.object);
+};
+
+
+const initContract = async (helper: EthUniqueHelper, owner: string): Promise<{contract: Contract, rftCollectionAddress: string}> => {
+ const fractionalizer = await deployContract(helper, owner);
+ const amount = 10n * helper.balance.getOneTokenNominal();
+ const web3 = helper.getWeb3();
+ await web3.eth.sendTransaction({from: owner, to: fractionalizer.options.address, value: `${amount}`, gas: helper.eth.DEFAULT_GAS});
+ const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({value: Number(2n * helper.balance.getOneTokenNominal())});
+ const rftCollectionAddress = result.events.RFTCollectionSet.returnValues._collection;
+ return {contract: fractionalizer, rftCollectionAddress};
+};
+
+const mintRFTToken = async (helper: EthUniqueHelper, owner: string, fractionalizer: Contract, amount: bigint): Promise<{
+ nftCollectionAddress: string, nftTokenId: number, rftTokenAddress: string
+}> => {
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
+ await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
+ const result = await fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, amount).send({from: owner});
+ const {_collection, _tokenId, _rftToken} = result.events.Fractionalized.returnValues;
+ return {
+ nftCollectionAddress: _collection,
+ nftTokenId: _tokenId,
+ rftTokenAddress: _rftToken,
+ };
+};
+
+
+describe('Fractionalizer contract usage', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Set RFT collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const fractionalizer = await deployContract(helper, owner);
+ const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
+ const rftContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
+
+ const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
+ await rftContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
+ const result = await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});
+ expect(result.events).to.be.like({
+ RFTCollectionSet: {
+ returnValues: {
+ _collection: rftCollection.collectionAddress,
+ },
+ },
+ });
+ });
+
+ itEth('Mint RFT collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const fractionalizer = await deployContract(helper, owner);
+ await helper.balance.transferToSubstrate(donor, evmToAddress(fractionalizer.options.address), 10n * helper.balance.getOneTokenNominal());
+
+ const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({from: owner, value: Number(2n * helper.balance.getOneTokenNominal())});
+ expect(result.events).to.be.like({
+ RFTCollectionSet: {},
+ });
+ expect(result.events.RFTCollectionSet.returnValues._collection).to.be.ok;
+ });
+
+ itEth('Set Allowlist', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {contract: fractionalizer} = await initContract(helper, owner);
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+
+ const result1 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
+ expect(result1.events).to.be.like({
+ AllowListSet: {
+ returnValues: {
+ _collection: nftCollection.collectionAddress,
+ _status: true,
+ },
+ },
+ });
+ const result2 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, false).send({from: owner});
+ expect(result2.events).to.be.like({
+ AllowListSet: {
+ returnValues: {
+ _collection: nftCollection.collectionAddress,
+ _status: false,
+ },
+ },
+ });
+ });
+
+ itEth('NFT to RFT', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ const {contract: fractionalizer} = await initContract(helper, owner);
+
+ await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
+ await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
+ const result = await fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).send({from: owner});
+ expect(result.events).to.be.like({
+ Fractionalized: {
+ returnValues: {
+ _collection: nftCollection.collectionAddress,
+ _tokenId: nftTokenId,
+ _amount: '100',
+ },
+ },
+ });
+ const rftTokenAddress = result.events.Fractionalized.returnValues._rftToken;
+
+ // FIXME: should work without the caller
+ const rftTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress);
+ expect(await rftTokenContract.methods.balanceOf(owner).call()).to.equal('100');
+ });
+
+ itEth('RFT to NFT', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);
+ const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await mintRFTToken(helper, owner, fractionalizer, 100n);
+
+ const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);
+ const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId);
+ expect(rftCollectionAddress).to.be.equal(refungibleAddress);
+ const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner);
+ await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner});
+ const result = await fractionalizer.methods.rft2nft(refungibleAddress, tokenId).send({from: owner});
+ expect(result.events).to.be.like({
+ Defractionalized: {
+ returnValues: {
+ _rftToken: rftTokenAddress,
+ _nftCollection: nftCollectionAddress,
+ _nftTokenId: nftTokenId,
+ },
+ },
+ });
+ });
+
+ itEth('Test fractionalizer NFT <-> RFT mapping ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);
+ const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await mintRFTToken(helper, owner, fractionalizer, 100n);
+
+ const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);
+ const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId);
+ expect(rftCollectionAddress).to.be.equal(refungibleAddress);
+ const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner);
+ await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner});
+
+ const rft2nft = await fractionalizer.methods.rft2nftMapping(rftTokenAddress).call();
+ expect(rft2nft).to.be.like({
+ _collection: nftCollectionAddress,
+ _tokenId: nftTokenId,
+ });
+
+ const nft2rft = await fractionalizer.methods.nft2rftMapping(nftCollectionAddress, nftTokenId).call();
+ expect(nft2rft).to.be.eq(tokenId.toString());
+ });
+});
+
+
+
+describe('Negative Integration Tests for fractionalizer', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('call setRFTCollection twice', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
+ const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
+
+ const fractionalizer = await deployContract(helper, owner);
+ const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
+ await refungibleContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
+ await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});
+
+ await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call())
+ .to.be.rejectedWith(/RFT collection is already set$/g);
+ });
+
+ itEth('call setRFTCollection with NFT collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+
+ const fractionalizer = await deployContract(helper, owner);
+ const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
+ await nftContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
+
+ await expect(fractionalizer.methods.setRFTCollection(nftCollection.collectionAddress).call())
+ .to.be.rejectedWith(/Wrong collection type. Collection is not refungible.$/g);
+ });
+
+ itEth('call setRFTCollection while not collection admin', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const fractionalizer = await deployContract(helper, owner);
+ const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
+
+ await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call())
+ .to.be.rejectedWith(/Fractionalizer contract should be an admin of the collection$/g);
+ });
+
+ itEth('call setRFTCollection after createAndSetRFTCollection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const fractionalizer = await deployContract(helper, owner);
+ await helper.balance.transferToSubstrate(donor, evmToAddress(fractionalizer.options.address), 10n * helper.balance.getOneTokenNominal());
+
+ const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({from: owner, value: Number(2n * helper.balance.getOneTokenNominal())});
+ const collectionIdAddress = result.events.RFTCollectionSet.returnValues._collection;
+
+ await expect(fractionalizer.methods.setRFTCollection(collectionIdAddress).call())
+ .to.be.rejectedWith(/RFT collection is already set$/g);
+ });
+
+ itEth('call nft2rft without setting RFT collection for contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ const fractionalizer = await deployContract(helper, owner);
+
+ await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())
+ .to.be.rejectedWith(/RFT collection is not set$/g);
+ });
+
+ itEth('call nft2rft while not owner of NFT token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const nftOwner = await helper.eth.createAccountWithBalance(donor);
+
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+ await nftContract.methods.transfer(nftOwner, 1).send({from: owner});
+
+
+ const {contract: fractionalizer} = await initContract(helper, owner);
+ await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
+
+ await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call({from: owner}))
+ .to.be.rejectedWith(/Only token owner could fractionalize it$/g);
+ });
+
+ itEth('call nft2rft while not in list of allowed accounts', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ const {contract: fractionalizer} = await initContract(helper, owner);
+
+ await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
+ await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())
+ .to.be.rejectedWith(/Fractionalization of this collection is not allowed by admin$/g);
+ });
+
+ itEth('call nft2rft while fractionalizer doesnt have approval for nft token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ const {contract: fractionalizer} = await initContract(helper, owner);
+
+ await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
+ await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())
+ .to.be.rejectedWith(/ApprovedValueTooLow$/g);
+ });
+
+ itEth('call rft2nft without setting RFT collection for contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const fractionalizer = await deployContract(helper, owner);
+ const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
+ const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
+ const mintResult = await refungibleContract.methods.mint(owner).send({from: owner});
+ const rftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call({from: owner}))
+ .to.be.rejectedWith(/RFT collection is not set$/g);
+ });
+
+ itEth('call rft2nft for RFT token that is not from configured RFT collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {contract: fractionalizer} = await initContract(helper, owner);
+ const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
+ const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
+ const mintResult = await refungibleContract.methods.mint(owner).send({from: owner});
+ const rftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call())
+ .to.be.rejectedWith(/Wrong RFT collection$/g);
+ });
+
+ itEth('call rft2nft for RFT token that was not minted by fractionalizer contract', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
+ const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
+
+ const fractionalizer = await deployContract(helper, owner);
+
+ const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
+ await refungibleContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
+ await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});
+
+ const mintResult = await refungibleContract.methods.mint(owner).send({from: owner});
+ const rftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call())
+ .to.be.rejectedWith(/No corresponding NFT token found$/g);
+ });
+
+ itEth('call rft2nft without owning all RFT pieces', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+
+ const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);
+ const {rftTokenAddress} = await mintRFTToken(helper, owner, fractionalizer, 100n);
+
+ const {tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);
+ const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner);
+ await refungibleTokenContract.methods.transfer(receiver, 50).send({from: owner});
+ await refungibleTokenContract.methods.approve(fractionalizer.options.address, 50).send({from: receiver});
+ await expect(fractionalizer.methods.rft2nft(rftCollectionAddress, tokenId).call({from: receiver}))
+ .to.be.rejectedWith(/Not all pieces are owned by the caller$/g);
+ });
+
+ itEth('send QTZ/UNQ to contract from non owner', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const payer = await helper.eth.createAccountWithBalance(donor);
+
+ const fractionalizer = await deployContract(helper, owner);
+ const amount = 10n * helper.balance.getOneTokenNominal();
+ const web3 = helper.getWeb3();
+ await expect(web3.eth.sendTransaction({from: payer, to: fractionalizer.options.address, value: `${amount}`, gas: helper.eth.DEFAULT_GAS})).to.be.rejected;
+ });
+
+ itEth('fractionalize NFT with NFT transfers disallowed', async ({helper}) => {
+ const nftCollection = await helper.nft.mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const nftToken = await nftCollection.mintToken(donor, {Ethereum: owner});
+ await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [nftCollection.collectionId, false], true);
+ const nftCollectionAddress = helper.ethAddress.fromCollectionId(nftCollection.collectionId);
+ const {contract: fractionalizer} = await initContract(helper, owner);
+ await fractionalizer.methods.setNftCollectionIsAllowed(nftCollectionAddress, true).send({from: owner});
+
+ const nftContract = await helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);
+ await nftContract.methods.approve(fractionalizer.options.address, nftToken.tokenId).send({from: owner});
+ await expect(fractionalizer.methods.nft2rft(nftCollectionAddress, nftToken.tokenId, 100).call())
+ .to.be.rejectedWith(/TransferNotAllowed$/g);
+ });
+
+ itEth('fractionalize NFT with RFT transfers disallowed', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const rftCollection = await helper.rft.mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const rftCollectionAddress = helper.ethAddress.fromCollectionId(rftCollection.collectionId);
+ const fractionalizer = await deployContract(helper, owner);
+ await rftCollection.addAdmin(donor, {Ethereum: fractionalizer.options.address});
+
+ await fractionalizer.methods.setRFTCollection(rftCollectionAddress).send({from: owner});
+ await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [rftCollection.collectionId, false], true);
+
+ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
+ const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
+ const mintResult = await nftContract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
+
+ await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
+ await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
+
+ await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100n).call())
+ .to.be.rejectedWith(/TransferNotAllowed$/g);
+ });
+});
js-packages/tests/eth/fungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/fungible.test.ts
@@ -0,0 +1,643 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+describe('Fungible: Plain calls', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let owner: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, owner] = await helper.arrange.createAccounts([30n, 20n], donor);
+ });
+ });
+
+ [
+ 'substrate' as const,
+ 'ethereum' as const,
+ ].map(testCase => {
+ itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
+ // 1. Create receiver depending on the test case:
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverSub = owner;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(owner);
+
+ const ethOwner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.addAdmin(alice, {Ethereum: ethOwner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner);
+
+ // 2. Mint tokens:
+ const result = await collectionEvm.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, 100).send();
+
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(receiverSub.address));
+ expect(event.returnValues.value).to.equal('100');
+
+ // 3. Get balance depending on the test case:
+ let balance;
+ if(testCase === 'ethereum') balance = await collection.getBalance({Ethereum: receiverEth});
+ else if(testCase === 'substrate') balance = await collection.getBalance({Substrate: receiverSub.address});
+ // 3.1 Check balance:
+ expect(balance).to.eq(100n);
+ });
+ });
+
+ itEth('Can perform mintBulk()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const bulkSize = 3;
+ const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.addAdmin(alice, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (
+ [receivers[i], (i + 1) * 10]
+ ))).send();
+ const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);
+ for(let i = 0; i < bulkSize; i++) {
+ const event = events[i];
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receivers[i]);
+ expect(event.returnValues.value).to.equal(String(10 * (i + 1)));
+ }
+ });
+
+ // Soft-deprecated
+ itEth('Can perform burn()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.addAdmin(alice, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
+ await contract.methods.mint(receiver, 100).send();
+
+ const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});
+
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal(receiver);
+ expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.value).to.equal('49');
+
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(balance).to.equal('51');
+ });
+
+ itEth('Can perform approve()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ {
+ const result = await contract.methods.approve(spender, 100).send({from: owner});
+
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(spender);
+ expect(event.returnValues.value).to.be.equal('100');
+ }
+
+ {
+ const allowance = await contract.methods.allowance(owner, spender).call();
+ expect(+allowance).to.equal(100);
+ }
+ {
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const spenderCross = helper.ethCrossAccount.fromAddress(spender);
+ const allowance = await contract.methods.allowanceCross(ownerCross, spenderCross).call();
+ expect(+allowance).to.equal(100);
+ }
+ });
+
+ itEth('Can perform approveCross()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0];
+ const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);
+ const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub);
+
+
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ {
+ const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(spender);
+ expect(event.returnValues.value).to.be.equal('100');
+ }
+
+ {
+ const allowance = await contract.methods.allowance(owner, spender).call();
+ expect(+allowance).to.equal(100);
+ }
+
+
+ {
+ const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner});
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address));
+ expect(event.returnValues.value).to.be.equal('100');
+ }
+
+ {
+ const allowance = await collection.getApprovedTokens({Ethereum: owner}, {Substrate: spenderSub.address});
+ expect(allowance).to.equal(100n);
+ }
+
+ {
+ //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call()
+ }
+ });
+
+ itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {
+ const nonOwner = await helper.eth.createAccountWithBalance(donor);
+ const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ await collection.mint(alice, 100n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ await expect(collectionEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');
+ });
+
+
+ itEth('Can perform burnFromCross()', async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
+
+ await collection.mint(owner, 200n, {Substrate: owner.address});
+ await collection.approveTokens(owner, {Ethereum: sender}, 100n);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'ft');
+
+ const fromBalanceBefore = await collection.getBalance({Substrate: owner.address});
+
+ const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+ const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});
+ const events = result.events;
+
+ expect(events).to.be.like({
+ Transfer: {
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: '0x0000000000000000000000000000000000000000',
+ value: '49',
+ },
+ },
+ Approval: {
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ returnValues: {
+ owner: helper.address.substrateToEth(owner.address),
+ spender: sender,
+ value: '51',
+ },
+ event: 'Approval',
+ },
+ });
+
+ const fromBalanceAfter = await collection.getBalance({Substrate: owner.address});
+ expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);
+ });
+
+ itEth('Can perform transferFrom()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ await contract.methods.approve(spender, 100).send();
+
+ {
+ const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
+
+ let event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('49');
+
+ event = result.events.Approval;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(spender);
+ expect(event.returnValues.value).to.be.equal('51');
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(49);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(owner).call();
+ expect(+balance).to.equal(151);
+ }
+ });
+
+ itEth('Can perform transferCross()', async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+ const receiverEth = await helper.eth.createAccountWithBalance(donor);
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(donor);
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: sender});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
+
+ {
+ // Can transferCross to ethereum address:
+ const result = await collectionEvm.methods.transferCross(receiverCrossEth, 50).send({from: sender});
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(sender);
+ expect(event.returnValues.to).to.be.equal(receiverEth);
+ expect(event.returnValues.value).to.be.equal('50');
+ // Sender's balance decreased:
+ const ownerBalance = await collectionEvm.methods.balanceOf(sender).call();
+ expect(+ownerBalance).to.equal(150);
+ // Receiver's balance increased:
+ const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+ expect(+receiverBalance).to.equal(50);
+ }
+
+ {
+ // Can transferCross to substrate address:
+ const result = await collectionEvm.methods.transferCross(receiverCrossSub, 50).send({from: sender});
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(sender);
+ expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address));
+ expect(event.returnValues.value).to.be.equal('50');
+ // Sender's balance decreased:
+ const senderBalance = await collection.getBalance({Ethereum: sender});
+ expect(senderBalance).to.equal(100n);
+ // Receiver's balance increased:
+ const balance = await collection.getBalance({Substrate: donor.address});
+ expect(balance).to.equal(50n);
+ }
+ });
+
+ ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} incorrect amount`, async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+ const receiverEth = await helper.eth.createAccountWithBalance(donor);
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const BALANCE = 200n;
+ const BALANCE_TO_TRANSFER = BALANCE + 100n;
+
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, BALANCE, {Ethereum: sender});
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
+
+ // 1. Cannot transfer more than have
+ const receiver = testCase === 'transfer' ? receiverEth : receiverCrossEth;
+ await expect(collectionEvm.methods[testCase](receiver, BALANCE_TO_TRANSFER).send({from: sender})).to.be.rejected;
+ // 2. Zero transfer allowed (EIP-20):
+ await collectionEvm.methods[testCase](receiver, 0n).send({from: sender});
+ }));
+
+
+ itEth('Can perform transfer()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ {
+ const result = await contract.methods.transfer(receiver, 50).send({from: owner});
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('50');
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(owner).call();
+ expect(+balance).to.equal(150);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(50);
+ }
+ });
+
+ itEth('Can perform transferFromCross()', async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
+
+ const receiver = helper.eth.createAccount();
+
+ await collection.mint(owner, 200n, {Substrate: owner.address});
+ await collection.approveTokens(owner, {Ethereum: sender}, 100n);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'ft');
+
+ const from = helper.ethCrossAccount.fromKeyringPair(owner);
+ const to = helper.ethCrossAccount.fromAddress(receiver);
+
+ const fromBalanceBefore = await collection.getBalance({Substrate: owner.address});
+ const toBalanceBefore = await collection.getBalance({Ethereum: receiver});
+
+ const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});
+
+ expect(result.events).to.be.like({
+ Transfer: {
+ address,
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: receiver,
+ value: '51',
+ },
+ },
+ Approval: {
+ address,
+ event: 'Approval',
+ returnValues: {
+ owner: helper.address.substrateToEth(owner.address),
+ spender: sender,
+ value: '49',
+ },
+ }});
+
+ const fromBalanceAfter = await collection.getBalance({Substrate: owner.address});
+ expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);
+ const toBalanceAfter = await collection.getBalance({Ethereum: receiver});
+ expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);
+ });
+
+ itEth('Check balanceOfCross()', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {});
+ const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const other = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner.eth);
+
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
+ expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
+
+ await collection.mint(alice, 100n, {Ethereum: owner.eth});
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100');
+ expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
+
+ await collectionEvm.methods.transferCross(other, 50n).send({from: owner.eth});
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('50');
+ expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('50');
+
+ await collectionEvm.methods.transferCross(other, 50n).send({from: owner.eth});
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
+ expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('100');
+
+ await collectionEvm.methods.transferCross(owner, 100n).send({from: other.eth});
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100');
+ expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
+ });
+});
+
+describe('Fungible: Fees', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([20n], donor);
+ });
+ });
+
+ itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+
+ itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ await contract.methods.approve(spender, 100).send({from: owner});
+
+ const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+
+ itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+});
+
+describe('Fungible: Substrate calls', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let owner: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, owner] = await helper.arrange.createAccounts([20n, 20n], donor);
+ });
+ });
+
+ itEth('Events emitted for approve()', async ({helper}) => {
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await collection.approveTokens(alice, {Ethereum: receiver}, 100n);
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Approval');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.spender).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('100');
+ });
+
+ itEth('Events emitted for transferFrom()', async ({helper}) => {
+ const [bob] = await helper.arrange.createAccounts([10n], donor);
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n);
+ await collection.approveTokens(alice, {Substrate: bob.address}, 100n);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ let event = events[0];
+
+ expect(event.event).to.be.equal('Transfer');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('51');
+
+ event = events[1];
+ expect(event.event).to.be.equal('Approval');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
+ expect(event.returnValues.value).to.be.equal('49');
+ });
+
+ itEth('Events emitted for transfer()', async ({helper}) => {
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.mint(alice, 200n);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await collection.transfer(alice, {Ethereum:receiver}, 51n);
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Transfer');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('51');
+ });
+
+ itEth('Events emitted for transferFromCross()', async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
+
+ const receiver = helper.eth.createAccount();
+
+ await collection.mint(owner, 200n, {Substrate: owner.address});
+ await collection.approveTokens(owner, {Ethereum: sender}, 100n);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'ft');
+
+ const from = helper.ethCrossAccount.fromKeyringPair(owner);
+ const to = helper.ethCrossAccount.fromAddress(receiver);
+
+ const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});
+
+ expect(result.events).to.be.like({
+ Transfer: {
+ address,
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: receiver,
+ value: '51',
+ },
+ },
+ Approval: {
+ address,
+ event: 'Approval',
+ returnValues: {
+ owner: helper.address.substrateToEth(owner.address),
+ spender: sender,
+ value: '49',
+ },
+ }});
+ });
+});
js-packages/tests/eth/getCode.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/getCode.test.ts
@@ -0,0 +1,53 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {COLLECTION_HELPER, CONTRACT_HELPER} from '../util/index.js';
+
+describe('RPC eth_getCode', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {address: COLLECTION_HELPER},
+ {address: CONTRACT_HELPER},
+ ].map(testCase => {
+ itEth(`returns value for native contract: ${testCase.address}`, async ({helper}) => {
+ const contractCodeSub = (await helper.callRpc('api.rpc.eth.getCode', [testCase.address])).toJSON();
+ const contractCodeEth = (await helper.getWeb3().eth.getCode(testCase.address));
+
+ expect(contractCodeSub).to.has.length.greaterThan(4);
+ expect(contractCodeEth).to.has.length.greaterThan(4);
+ });
+ });
+
+ itEth('returns value for custom contract', async ({helper}) => {
+ const signer = await helper.eth.createAccountWithBalance(donor);
+ const flipper = await helper.eth.deployFlipper(signer);
+
+ const contractCodeSub = (await helper.callRpc('api.rpc.eth.getCode', [flipper.options.address])).toJSON();
+ const contractCodeEth = (await helper.getWeb3().eth.getCode(flipper.options.address));
+
+ expect(contractCodeSub).to.has.length.greaterThan(4);
+ expect(contractCodeEth).to.has.length.greaterThan(4);
+ });
+});
js-packages/tests/eth/helpersSmoke.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/helpersSmoke.test.ts
@@ -0,0 +1,46 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+describe('Helpers sanity check', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Contract owner is recorded', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await (await helper.ethNativeContract.contractHelpers(owner)).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner);
+ });
+
+ itEth('Flipper is working', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ expect(await flipper.methods.getValue().call()).to.be.false;
+ await flipper.methods.flip().send({from: owner});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+ });
+});
js-packages/tests/eth/marketplace-v2/Market.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace-v2/Market.sol
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.18;
+
+import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
+import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
+import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
+import "@openzeppelin/contracts/access/Ownable.sol";
+import { UniqueNFT, CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol";
+import { UniqueFungible, CrossAddress as CrossAddressF } from "@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol";
+import { CollectionHelpers } from "@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol";
+import "./royalty/UniqueRoyaltyHelper.sol";
+
+contract Market is Ownable, ReentrancyGuard {
+ using ERC165Checker for address;
+
+ struct Order {
+ uint32 id;
+ uint32 collectionId;
+ uint32 tokenId;
+ uint32 amount;
+ uint256 price;
+ CrossAddress seller;
+ }
+
+ uint32 public constant version = 0;
+ uint32 public constant buildVersion = 3;
+ bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd;
+ bytes4 private constant InterfaceId_ERC165 = 0x5755c3f2;
+ CollectionHelpers private constant collectionHelpers =
+ CollectionHelpers(0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F);
+
+ mapping(uint32 => mapping(uint32 => Order)) orders;
+ uint32 private idCount = 1;
+ uint32 public marketFee;
+ uint64 public ctime;
+ address public ownerAddress;
+ mapping(address => bool) public admins;
+
+ event TokenIsUpForSale(uint32 version, Order item);
+ event TokenRevoke(uint32 version, Order item, uint32 amount);
+ event TokenIsApproved(uint32 version, Order item);
+ event TokenIsPurchased(
+ uint32 version,
+ Order item,
+ uint32 salesAmount,
+ CrossAddress buyer,
+ RoyaltyAmount[] royalties
+ );
+ event Log(string message);
+
+ error InvalidArgument(string info);
+ error InvalidMarketFee();
+ error SellerIsNotOwner();
+ error TokenIsAlreadyOnSale();
+ error TokenIsNotApproved();
+ error CollectionNotFound();
+ error CollectionNotSupportedERC721();
+ error OrderNotFound();
+ error TooManyAmountRequested();
+ error NotEnoughMoneyError();
+ error InvalidRoyaltiesError(uint256 totalRoyalty);
+ error FailTransferToken(string reason);
+
+ modifier onlyAdmin() {
+ require(msg.sender == this.owner() || admins[msg.sender], "Only admin can");
+ _;
+ }
+
+ modifier validCrossAddress(address eth, uint256 sub) {
+ if (eth == address(0) && sub == 0) {
+ revert InvalidArgument("Ethereum and Substrate addresses cannot be null at the same time");
+ }
+
+ if (eth != address(0) && sub != 0) {
+ revert InvalidArgument("Ethereum and Substrate addresses cannot be not null at the same time");
+ }
+
+ _;
+ }
+
+ constructor(uint32 fee, uint64 timestamp) {
+ marketFee = fee;
+ ctime = timestamp;
+
+ if (marketFee >= 100) {
+ revert InvalidMarketFee();
+ }
+ }
+
+ /**
+ * Fallback that allows this contract to receive native token.
+ * We need this for self-sponsoring
+ */
+ fallback() external payable {}
+
+ /**
+ * Receive also allows this contract to receive native token.
+ * We need this for self-sponsoring
+ */
+ receive() external payable {}
+
+ function getErc721(uint32 collectionId) private view returns (IERC721) {
+ address collectionAddress = collectionHelpers.collectionAddress(
+ collectionId
+ );
+
+ uint size;
+ assembly {
+ size := extcodesize(collectionAddress)
+ }
+
+ if (size == 0) {
+ revert CollectionNotFound();
+ }
+
+ if (!collectionAddress.supportsInterface(InterfaceId_ERC721)) {
+ revert CollectionNotSupportedERC721();
+ }
+
+ return IERC721(collectionAddress);
+ }
+
+ /**
+ * Add new admin. Only owner or an existing admin can add admins.
+ *
+ * @param admin: Address of a new admin to add
+ */
+ function addAdmin(address admin) public onlyAdmin {
+ admins[admin] = true;
+ }
+
+ /**
+ * Remove an admin. Only owner or an existing admin can remove admins.
+ *
+ * @param admin: Address of a new admin to add
+ */
+ function removeAdmin(address admin) public onlyAdmin {
+ delete admins[admin];
+ }
+
+ /**
+ * Place an NFT or RFT token for sale. It must be pre-approved for transfers by this contract address.
+ *
+ * @param collectionId: ID of the token collection
+ * @param tokenId: ID of the token
+ * @param price: Price (with proper network currency decimals)
+ * @param amount: Number of token fractions to list (must always be 1 for NFT)
+ * @param seller: The seller cross-address (the beneficiary account to receive payment, may be different from transaction sender)
+ */
+ function put(
+ uint32 collectionId,
+ uint32 tokenId,
+ uint256 price,
+ uint32 amount,
+ CrossAddress memory seller
+ ) public validCrossAddress(seller.eth, seller.sub) {
+ if (price == 0) {
+ revert InvalidArgument("price must not be zero");
+ }
+ if (amount == 0) {
+ revert InvalidArgument("amount must not be zero");
+ }
+
+ if (orders[collectionId][tokenId].price > 0) {
+ revert TokenIsAlreadyOnSale();
+ }
+
+ IERC721 erc721 = getErc721(collectionId);
+
+ if (erc721.ownerOf(tokenId) != msg.sender) {
+ revert SellerIsNotOwner();
+ }
+
+ if (erc721.getApproved(tokenId) != address(this)) {
+ revert TokenIsNotApproved();
+ }
+
+ Order memory order = Order(
+ 0,
+ collectionId,
+ tokenId,
+ amount,
+ price,
+ seller
+ );
+
+ order.id = idCount++;
+ orders[collectionId][tokenId] = order;
+
+ emit TokenIsUpForSale(version, order);
+ }
+
+ /**
+ * Get information about the listed token order
+ *
+ * @param collectionId: ID of the token collection
+ * @param tokenId: ID of the token
+ * @return The order information
+ */
+ function getOrder(
+ uint32 collectionId,
+ uint32 tokenId
+ ) external view returns (Order memory) {
+ return orders[collectionId][tokenId];
+ }
+
+ /**
+ * Revoke the token from the sale. Only the original lister can use this method.
+ *
+ * @param collectionId: ID of the token collection
+ * @param tokenId: ID of the token
+ * @param amount: Number of token fractions to de-list (must always be 1 for NFT)
+ */
+ function revoke(
+ uint32 collectionId,
+ uint32 tokenId,
+ uint32 amount
+ ) external {
+ if (amount == 0) {
+ revert InvalidArgument("amount must not be zero");
+ }
+
+ Order memory order = orders[collectionId][tokenId];
+
+ if (order.price == 0) {
+ revert OrderNotFound();
+ }
+
+ if (amount > order.amount) {
+ revert TooManyAmountRequested();
+ }
+
+ IERC721 erc721 = getErc721(collectionId);
+
+ address ethAddress;
+ if (order.seller.eth != address(0)) {
+ ethAddress = order.seller.eth;
+ } else {
+ ethAddress = payable(address(uint160(order.seller.sub >> 96)));
+ }
+ if (erc721.ownerOf(tokenId) != ethAddress) {
+ revert SellerIsNotOwner();
+ }
+
+ order.amount -= amount;
+ if (order.amount == 0) {
+ delete orders[collectionId][tokenId];
+ } else {
+ orders[collectionId][tokenId] = order;
+ }
+
+ emit TokenRevoke(version, order, amount);
+ }
+
+ /**
+ * Test if the token is still approved to be transferred by this contract and delete the order if not.
+ *
+ * @param collectionId: ID of the token collection
+ * @param tokenId: ID of the token
+ */
+ function checkApproved(uint32 collectionId, uint32 tokenId) public onlyAdmin {
+ Order memory order = orders[collectionId][tokenId];
+ if (order.price == 0) {
+ revert OrderNotFound();
+ }
+
+ IERC721 erc721 = getErc721(collectionId);
+
+ if (erc721.getApproved(tokenId) != address(this) || erc721.ownerOf(tokenId) != getAddressFromCrossAccount(order.seller)) {
+ uint32 amount = order.amount;
+ order.amount = 0;
+ emit TokenRevoke(version, order, amount);
+
+ delete orders[collectionId][tokenId];
+ } else {
+ emit TokenIsApproved(version, order);
+ }
+ }
+
+ function getAddressFromCrossAccount(CrossAddress memory account) private pure returns (address) {
+ if (account.eth != address(0)) {
+ return account.eth;
+ } else {
+ return address(uint160(account.sub >> 96));
+ }
+ }
+
+ /**
+ * Revoke the token from the sale. Only the contract admin can use this method.
+ *
+ * @param collectionId: ID of the token collection
+ * @param tokenId: ID of the token
+ */
+ function revokeAdmin(uint32 collectionId, uint32 tokenId) public onlyAdmin {
+ Order memory order = orders[collectionId][tokenId];
+ if (order.price == 0) {
+ revert OrderNotFound();
+ }
+
+ uint32 amount = order.amount;
+ order.amount = 0;
+ emit TokenRevoke(version, order, amount);
+
+ delete orders[collectionId][tokenId];
+ }
+
+ /**
+ * Buy a token (partially for an RFT).
+ *
+ * @param collectionId: ID of the token collection
+ * @param tokenId: ID of the token
+ * @param amount: Number of token fractions to buy (must always be 1 for NFT)
+ * @param buyer: Cross-address of the buyer, eth part must be equal to the transaction signer address
+ */
+ function buy(
+ uint32 collectionId,
+ uint32 tokenId,
+ uint32 amount,
+ CrossAddress memory buyer
+ ) public payable validCrossAddress(buyer.eth, buyer.sub) nonReentrant {
+ if (msg.value == 0) {
+ revert InvalidArgument("msg.value must not be zero");
+ }
+ if (amount == 0) {
+ revert InvalidArgument("amount must not be zero");
+ }
+
+ Order memory order = orders[collectionId][tokenId];
+ if (order.price == 0) {
+ revert OrderNotFound();
+ }
+
+ if (amount > order.amount) {
+ revert TooManyAmountRequested();
+ }
+
+ uint256 totalValue = order.price * amount;
+ uint256 feeValue = (totalValue * marketFee) / 100;
+
+ if (msg.value < totalValue) {
+ revert NotEnoughMoneyError();
+ }
+
+ IERC721 erc721 = getErc721(order.collectionId);
+ if (erc721.getApproved(tokenId) != address(this)) {
+ revert TokenIsNotApproved();
+ }
+
+ order.amount -= amount;
+ if (order.amount == 0) {
+ delete orders[collectionId][tokenId];
+ } else {
+ orders[collectionId][tokenId] = order;
+ }
+
+ address collectionAddress = collectionHelpers.collectionAddress(collectionId);
+ UniqueNFT nft = UniqueNFT(collectionAddress);
+
+ nft.transferFromCross(
+ order.seller,
+ buyer,
+ order.tokenId
+ );
+
+ (uint256 totalRoyalty, RoyaltyAmount[] memory royalties) = sendRoyalties(collectionAddress, tokenId, totalValue - feeValue);
+
+ if (totalRoyalty >= totalValue - feeValue) {
+ revert InvalidRoyaltiesError(totalRoyalty);
+ }
+
+ sendMoney(order.seller, totalValue - feeValue - totalRoyalty);
+
+ if (msg.value > totalValue) {
+ sendMoney(buyer, msg.value - totalValue);
+ }
+
+ emit TokenIsPurchased(version, order, amount, buyer, royalties);
+ }
+
+ function sendMoney(CrossAddress memory to, uint256 money) private {
+ address collectionAddress = collectionHelpers.collectionAddress(0);
+
+ UniqueFungible fungible = UniqueFungible(collectionAddress);
+
+ CrossAddressF memory fromF = CrossAddressF(address(this), 0);
+ CrossAddressF memory toF = CrossAddressF(to.eth, to.sub);
+
+ fungible.transferFromCross(fromF, toF, money);
+ }
+
+ function sendRoyalties(address collection, uint tokenId, uint sellPrice) private returns (uint256, RoyaltyAmount[] memory) {
+ RoyaltyAmount[] memory royalties = UniqueRoyaltyHelper.calculate(collection, tokenId, sellPrice);
+
+ uint256 totalRoyalty = 0;
+
+ for (uint256 i=0; i<royalties.length; i++) {
+ RoyaltyAmount memory royalty = royalties[i];
+
+ totalRoyalty += royalty.amount;
+
+ sendMoney(royalty.crossAddress, royalty.amount);
+ }
+
+ return (totalRoyalty, royalties);
+ }
+
+ function withdraw(address transferTo) public onlyOwner {
+ uint256 balance = address(this).balance;
+
+ if (balance > 0) {
+ payable(transferTo).transfer(balance);
+ }
+ }
+}
js-packages/tests/eth/marketplace-v2/marketplace.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace-v2/marketplace.test.ts
@@ -0,0 +1,240 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import * as web3 from 'web3';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {readFile} from 'fs/promises';
+import {SponsoringMode, itEth, usingEthPlaygrounds} from '../util/index.js';
+import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {makeNames} from '../../util/index.js';
+import {expect} from 'chai';
+
+const {dirname} = makeNames(import.meta.url);
+
+const MARKET_FEE = 1;
+
+describe('Market V2 Contract', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+
+ const marketOwner = await helper.eth.createAccountWithBalance(donor, 600n);
+
+ await deployMarket(helper, marketOwner);
+ });
+ });
+
+ async function deployMarket(helper: EthUniqueHelper, marketOwner: string) {
+ return await helper.ethContract.deployByCode(
+ marketOwner,
+ 'Market',
+ (await readFile(`${dirname}/Market.sol`)).toString(),
+ [
+ {
+ solPath: '@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol',
+ fsPath: `${dirname}/../api/UniqueNFT.sol`,
+ },
+ {
+ solPath: '@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol',
+ fsPath: `${dirname}/../api/UniqueFungible.sol`,
+ },
+ {
+ solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
+ },
+ {
+ solPath: '@openzeppelin/contracts/access/Ownable.sol',
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/access/Ownable.sol`,
+ },
+ {
+ solPath: '@openzeppelin/contracts/utils/Context.sol',
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
+ },
+ {
+ solPath: '@openzeppelin/contracts/security/ReentrancyGuard.sol',
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol`,
+ },
+ {
+ solPath: '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol',
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol`,
+ },
+ {
+ solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
+ fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
+ },
+ {
+ solPath: '@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol',
+ fsPath: `${dirname}/../api/CollectionHelpers.sol`,
+ },
+ {
+ solPath: 'royalty/UniqueRoyaltyHelper.sol',
+ fsPath: `${dirname}/royalty/UniqueRoyaltyHelper.sol`,
+ },
+ {
+ solPath: 'royalty/UniqueRoyalty.sol',
+ fsPath: `${dirname}/royalty/UniqueRoyalty.sol`,
+ },
+ {
+ solPath: 'royalty/LibPart.sol',
+ fsPath: `${dirname}/royalty/LibPart.sol`,
+ },
+ ],
+ 15000000,
+ [MARKET_FEE, 0],
+ );
+ }
+
+ function substrateAddressToHex(sub: Uint8Array| string, web3: web3.default) {
+ if(typeof sub === 'string')
+ return web3.utils.padLeft(web3.utils.toHex(web3.utils.toBN(sub)), 64);
+ else if(sub instanceof Uint8Array)
+ return web3.utils.padLeft(web3.utils.bytesToHex(Array.from(sub)), 64);
+ throw Error('Infallible');
+ }
+
+ itEth('Put + Buy [eth]', async ({helper}) => {
+ const ONE_TOKEN = helper.balance.getOneTokenNominal();
+ const PRICE = 2n * ONE_TOKEN; // 2 UNQ
+ const marketOwner = await helper.eth.createAccountWithBalance(donor, 60000n);
+ const market = await deployMarket(helper, marketOwner);
+ const contractHelpers = helper.ethNativeContract.contractHelpers(marketOwner);
+
+ // Set external sponsoring
+ await contractHelpers.methods.setSponsor(market.options.address, marketOwner).send({from: marketOwner});
+ await contractHelpers.methods.confirmSponsorship(market.options.address).send({from: marketOwner});
+
+ // Configure sponsoring
+ await contractHelpers.methods.setSponsoringMode(market.options.address, SponsoringMode.Generous).send({from: marketOwner});
+ await contractHelpers.methods.setSponsoringRateLimit(market.options.address, 0).send({from: marketOwner});
+
+ const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(marketOwner, 'Sponsor', 'absolutely anything', 'ROC');
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', marketOwner, true);
+
+ // Set collection sponsoring
+ await collection.methods.setCollectionSponsor(marketOwner).send({from: marketOwner});
+ await collection.methods.confirmCollectionSponsorship().send({from: marketOwner});
+
+ const sellerCross = helper.ethCrossAccount.createAccount();
+ const result = await collection.methods.mintCross(sellerCross, []).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ await collection.methods.approve(market.options.address, tokenId).send({from: sellerCross.eth});
+
+ // Seller has no funds at all, his transactions are sponsored
+ const sellerBalance = await helper.balance.getEthereum(sellerCross.eth);
+ expect(sellerBalance).to.be.eq(0n);
+
+ const putResult = await market.methods.put(collectionId, tokenId, PRICE.toString(), 1, sellerCross).send({
+ from: sellerCross.eth, gasLimit: 1_000_000,
+ });
+ expect(putResult.events.TokenIsUpForSale).is.not.undefined;
+
+ // Seller balance are still 0
+ const sellerBalanceAfter = await helper.balance.getEthereum(sellerCross.eth);
+ expect(sellerBalanceAfter).to.be.eq(0n);
+
+ let ownerCross = await collection.methods.ownerOfCross(tokenId).call();
+ expect(ownerCross.eth).to.be.eq(sellerCross.eth);
+ expect(ownerCross.sub).to.be.eq(sellerCross.sub);
+
+ const buyerCross = await helper.ethCrossAccount.createAccountWithBalance(donor, 10n);
+
+ // Buyer has only 10 UNQ
+ const buyerBalance = await helper.balance.getEthereum(buyerCross.eth);
+ expect(buyerBalance).to.be.eq(10n * ONE_TOKEN);
+
+ const buyResult = await market.methods.buy(collectionId, tokenId, 1, buyerCross).send({from: buyerCross.eth, value: PRICE.toString(), gasLimit: 1_000_000});
+ expect(buyResult.events.TokenIsPurchased).is.not.undefined;
+
+ // Buyer pays only value, transaction use sponsoring
+ const buyerBalanceAfter = await helper.balance.getEthereum(buyerCross.eth);
+ expect(buyerBalanceAfter).to.be.eq(10n * ONE_TOKEN - PRICE);
+
+ ownerCross = await collection.methods.ownerOfCross(tokenId).call();
+ expect(ownerCross.eth).to.be.eq(buyerCross.eth);
+ expect(ownerCross.sub).to.be.eq(buyerCross.sub);
+ });
+
+ itEth('Put + Buy [sub]', async ({helper}) => {
+ const ONE_TOKEN = helper.balance.getOneTokenNominal();
+ const PRICE = 2n * ONE_TOKEN; // 2 UNQ
+ const web3 = helper.getWeb3();
+ const marketOwner = await helper.eth.createAccountWithBalance(donor, 600n);
+ const market = await deployMarket(helper, marketOwner);
+ const contractHelpers = helper.ethNativeContract.contractHelpers(marketOwner);
+
+ // Set self sponsoring from contract balance
+ await contractHelpers.methods.selfSponsoredEnable(market.options.address).send({from: marketOwner});
+ await helper.eth.transferBalanceFromSubstrate(donor, market.options.address, 10n);
+
+ // Configure sponsoring
+ await contractHelpers.methods.setSponsoringMode(market.options.address, SponsoringMode.Generous).send({from: marketOwner});
+ await contractHelpers.methods.setSponsoringRateLimit(market.options.address, 0).send({from: marketOwner});
+
+ const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(marketOwner, 'Sponsor', 'absolutely anything', 'ROC');
+ const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', marketOwner, true);
+
+ // Set collection sponsoring
+ await collection.methods.setCollectionSponsor(marketOwner).send({from: marketOwner});
+ await collection.methods.confirmCollectionSponsorship().send({from: marketOwner});
+
+ const seller = helper.util.fromSeed(`//Market-seller-${(new Date()).getTime()}`);
+ const sellerCross = helper.ethCrossAccount.fromKeyringPair(seller);
+
+ // Seller has no funds at all, his transactions are sponsored
+ {
+ const sellerBalance = await helper.balance.getSubstrate(seller.address);
+ expect(sellerBalance).to.be.eq(0n);
+ }
+
+ const result = await collection.methods.mintCross(sellerCross, []).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ await helper.nft.approveToken(seller, collectionId, tokenId, {Ethereum: market.options.address});
+
+ await helper.eth.sendEVM(seller, market.options.address, market.methods.put(collectionId, tokenId, PRICE, 1, sellerCross).encodeABI(), '0');
+ // Seller balance is still zero
+ {
+ const sellerBalance = await helper.balance.getSubstrate(seller.address);
+ expect(sellerBalance).to.be.eq(0n);
+ }
+ let ownerCross = await collection.methods.ownerOfCross(tokenId).call();
+ expect(ownerCross.eth).to.be.eq(sellerCross.eth);
+ expect(substrateAddressToHex(ownerCross.sub, web3)).to.be.eq(substrateAddressToHex(sellerCross.sub, web3));
+
+ const [buyer] = await helper.arrange.createAccounts([600n], donor);
+ // Buyer has only expected balance
+ {
+ const buyerBalance = await helper.balance.getSubstrate(buyer.address);
+ expect(buyerBalance).to.be.eq(600n * ONE_TOKEN);
+ }
+ const buyerCross = helper.ethCrossAccount.fromKeyringPair(buyer);
+
+ const buyerBalanceBefore = await helper.balance.getSubstrate(buyer.address);
+ await helper.eth.sendEVM(buyer, market.options.address, market.methods.buy(collectionId, tokenId, 1, buyerCross).encodeABI(), PRICE.toString());
+ const buyerBalanceAfter = await helper.balance.getSubstrate(buyer.address);
+ // Buyer balance not changed: transaction is sponsored
+ expect(buyerBalanceBefore).to.be.eq(buyerBalanceAfter + PRICE);
+
+ const sellerBalanceAfterBuy = BigInt(await helper.balance.getSubstrate(seller.address));
+ ownerCross = await collection.methods.ownerOfCross(tokenId).call();
+ expect(ownerCross.eth).to.be.eq(buyerCross.eth);
+ expect(substrateAddressToHex(ownerCross.sub, web3)).to.be.eq(substrateAddressToHex(buyerCross.sub, web3));
+
+ // Seller got only PRICE - MARKET_FEE
+ expect(sellerBalanceAfterBuy).to.be.eq(PRICE * BigInt(100 - MARKET_FEE) / 100n);
+ });
+});
js-packages/tests/eth/marketplace-v2/royalty/LibPart.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace-v2/royalty/LibPart.sol
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "./UniqueRoyalty.sol";
+
+library LibPart {
+ bytes32 public constant TYPE_HASH = keccak256("Part(address account,uint96 value)");
+
+ struct Part {
+ address payable account;
+ uint96 value;
+ }
+
+ function hash(Part memory part) internal pure returns (bytes32) {
+ return keccak256(abi.encode(TYPE_HASH, part.account, part.value));
+ }
+}
+
+library LibPartAdapter {
+ function encode(LibPart.Part[] memory parts) internal pure returns (bytes memory) {
+ if (parts.length == 0) return "";
+
+ uint256[] memory encoded = new uint256[](parts.length * 2);
+
+ for (uint i = 0; i < parts.length; i++) {
+ encoded[i * 2] = 0x0100000000000000000000000000000000000000000000040000000000000000 | uint256(parts[i].value);
+ encoded[i * 2 + 1] = uint256(uint160(address(parts[i].account)));
+ }
+
+ return abi.encodePacked(encoded);
+ }
+
+ function decode(bytes memory b) internal pure returns (LibPart.Part[] memory) {
+ if (b.length == 0) return new LibPart.Part[](0);
+
+ require((b.length % (32 * 2)) == 0, "Invalid bytes length, expected (32 * 2) * UniqueRoyaltyParts count");
+ uint partsCount = b.length / (32 * 2);
+ uint numbersCount = partsCount * 2;
+
+ LibPart.Part[] memory parts = new LibPart.Part[](partsCount);
+
+ // need this because numbers encoded via abi.encodePacked
+ bytes memory prefix = new bytes(64);
+
+ assembly {
+ mstore(add(prefix, 32), 32)
+ mstore(add(prefix, 64), numbersCount)
+ }
+
+ uint256[] memory encoded = abi.decode(bytes.concat(prefix, b), (uint256[]));
+
+ for (uint i = 0; i < partsCount; i++) {
+ uint96 value = uint96(encoded[i * 2] & 0xFFFFFFFFFFFFFFFF);
+ address account = address(uint160(encoded[i * 2 + 1]));
+
+ parts[i] = LibPart.Part({
+ account: payable(account),
+ value: value
+ });
+ }
+
+ return parts;
+ }
+}
+
+library LibPartAdapterComplex {
+ function decodeSafe(bytes memory data) internal pure returns (LibPart.Part[] memory) {
+ return fromUniqueRoyalties(UniqueRoyalty.decode(data));
+ }
+
+ function encodeSafe(LibPart.Part[] memory parts) internal pure returns (bytes memory) {
+ return UniqueRoyalty.encode(toUniqueRoyalties(parts));
+ }
+
+ function fromUniqueRoyalties(UniqueRoyaltyPart[] memory royalties) internal pure returns (LibPart.Part[] memory) {
+ LibPart.Part[] memory parts = new LibPart.Part[](royalties.length);
+
+ for (uint i = 0; i < royalties.length; i++) {
+ uint96 value = royalties[i].decimals >= 4
+ ? uint96(royalties[i].value * (10 ** (royalties[i].decimals - 4)))
+ : uint96(royalties[i].value / (10 ** (4 - royalties[i].decimals)));
+
+ parts[i] = LibPart.Part({
+ account: payable(CrossAddressLib.toAddress(royalties[i].crossAddress)),
+ value: value
+ });
+ }
+
+ return parts;
+ }
+
+ function toUniqueRoyalties(LibPart.Part[] memory parts) internal pure returns (UniqueRoyaltyPart[] memory) {
+ UniqueRoyaltyPart[] memory royalties = new UniqueRoyaltyPart[](parts.length);
+
+ for (uint i = 0; i < parts.length; i++) {
+ royalties[i] = UniqueRoyaltyPart({
+ version: 1,
+ value: uint64(parts[i].value),
+ decimals: 4,
+ crossAddress: CrossAddress({
+ sub: 0,
+ eth: parts[i].account
+ }),
+ isPrimarySaleOnly: false
+ });
+ }
+
+ return royalties;
+ }
+}
\ No newline at end of file
js-packages/tests/eth/marketplace-v2/royalty/UniqueRoyalty.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace-v2/royalty/UniqueRoyalty.sol
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity >=0.8.17;
+
+import { CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol";
+
+struct UniqueRoyaltyPart {
+ uint8 version;
+ uint8 decimals;
+ uint64 value;
+ bool isPrimarySaleOnly;
+ CrossAddress crossAddress;
+}
+
+library CrossAddressLib {
+ function toAddress(CrossAddress memory crossAddress) internal pure returns (address) {
+ return crossAddress.eth != address(0) ? crossAddress.eth : address(uint160(crossAddress.sub >> 96));
+ }
+}
+
+library UniqueRoyalty {
+ uint private constant DECIMALS_OFFSET = 4 * 16;
+ uint private constant ADDRESS_TYPE_OFFSET = 4 * (16 + 2); // 0 - eth, 1 - sub
+ uint private constant ROYALTY_TYPE_OFFSET = 4 * (16 + 2 + 1); // 0 - default, 1 - primary sale only
+ uint private constant VERSION_OFFSET = 4 * (16 + 2 + 1 + 1 + 42);
+
+ uint private constant PART_LENGTH = 32 * 2;
+
+ function decode(bytes memory b) internal pure returns (UniqueRoyaltyPart[] memory) {
+ if (b.length == 0) return new UniqueRoyaltyPart[](0);
+
+ require((b.length % PART_LENGTH) == 0, "Invalid bytes length, expected (32 * 2) * UniqueRoyaltyParts count");
+ uint partsCount = b.length / PART_LENGTH;
+ uint numbersCount = partsCount * 2;
+
+ UniqueRoyaltyPart[] memory parts = new UniqueRoyaltyPart[](partsCount);
+
+ // need this because numbers encoded via abi.encodePacked
+ bytes memory prefix = new bytes(64);
+
+ assembly {
+ mstore(add(prefix, 32), 32)
+ mstore(add(prefix, 64), numbersCount)
+ }
+
+ uint256[] memory encoded = abi.decode(bytes.concat(prefix, b), (uint256[]));
+
+ for (uint i = 0; i < partsCount; i++) {
+ parts[i] = decodePart(encoded[i * 2], encoded[i * 2 + 1]);
+ }
+
+ return parts;
+ }
+
+ function encode(UniqueRoyaltyPart[] memory parts) internal pure returns (bytes memory) {
+ if (parts.length == 0) return "";
+
+ uint256[] memory encoded = new uint256[](parts.length * 2);
+
+ for (uint i = 0; i < parts.length; i++) {
+ (uint256 encodedMeta, uint256 encodedAddress) = encodePart(parts[i]);
+
+ encoded[i * 2] = encodedMeta;
+ encoded[i * 2 + 1] = encodedAddress;
+ }
+
+ return abi.encodePacked(encoded);
+ }
+
+ function decodePart(bytes memory b) internal pure returns (UniqueRoyaltyPart memory) {
+ require(b.length == PART_LENGTH, "Invalid bytes length, expected 32 * 2");
+
+ uint256[2] memory encoded = abi.decode(b, (uint256[2]));
+
+ return decodePart(encoded[0], encoded[1]);
+ }
+
+ function decodePart(
+ uint256 _meta,
+ uint256 _address
+ ) internal pure returns (UniqueRoyaltyPart memory) {
+ uint256 version = _meta >> VERSION_OFFSET;
+ bool isPrimarySaleOnly = (_meta & (1 << ROYALTY_TYPE_OFFSET)) > 0;
+ bool isEthereumAddress = (_meta & (1 << ADDRESS_TYPE_OFFSET)) == 0;
+ uint256 decimals = (_meta >> 4 * 16) & 0xFF;
+ uint256 value = _meta & 0xFFFFFFFFFFFFFFFF;
+
+ CrossAddress memory crossAddress = isEthereumAddress
+ ? CrossAddress({ sub: 0, eth: address(uint160(_address)) })
+ : CrossAddress({ sub: _address, eth: address(0) });
+
+ UniqueRoyaltyPart memory royaltyPart = UniqueRoyaltyPart({
+ version: uint8(version),
+ decimals: uint8(decimals),
+ value: uint64(value),
+ isPrimarySaleOnly: isPrimarySaleOnly,
+ crossAddress: crossAddress
+ });
+
+ return royaltyPart;
+ }
+
+ function encodePart(UniqueRoyaltyPart memory royaltyPart) internal pure returns (uint256, uint256) {
+ uint256 encodedMeta = 0;
+ uint256 encodedAddress = 0;
+
+ encodedMeta |= uint256(royaltyPart.version) << VERSION_OFFSET;
+ if (royaltyPart.isPrimarySaleOnly) encodedMeta |= 1 << ROYALTY_TYPE_OFFSET;
+
+ if (royaltyPart.crossAddress.eth == address(0x0)) {
+ encodedMeta |= 1 << ADDRESS_TYPE_OFFSET;
+ encodedAddress = royaltyPart.crossAddress.sub;
+ } else {
+ encodedAddress = uint256(uint160(royaltyPart.crossAddress.eth));
+ }
+
+ encodedMeta |= uint256(royaltyPart.decimals) << DECIMALS_OFFSET;
+ encodedMeta |= uint256(royaltyPart.value);
+
+ return (encodedMeta, encodedAddress);
+ }
+}
\ No newline at end of file
js-packages/tests/eth/marketplace-v2/royalty/UniqueRoyaltyHelper.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace-v2/royalty/UniqueRoyaltyHelper.sol
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity >=0.8.17;
+
+import "./UniqueRoyalty.sol";
+import "./LibPart.sol";
+
+string constant ROYALTIES_PROPERTY = "royalties";
+
+interface ICollection {
+ function collectionProperty(string memory key) external view returns (bytes memory);
+ function property(uint256 tokenId, string memory key) external view returns (bytes memory);
+}
+
+struct RoyaltyAmount {
+ CrossAddress crossAddress;
+ uint amount;
+}
+
+library UniqueRoyaltyHelper {
+ function encodePart(UniqueRoyaltyPart memory part) internal pure returns (bytes memory) {
+ (uint256 encodedMeta, uint256 encodedAddress) = UniqueRoyalty.encodePart(part);
+
+ return abi.encodePacked(encodedMeta, encodedAddress);
+ }
+
+ function decodePart(bytes memory data) internal pure returns (UniqueRoyaltyPart memory) {
+ return UniqueRoyalty.decodePart(data);
+ }
+
+ // todo - implement smth better - check royalties sum is lte 100%
+ function validatePart(bytes memory b) internal pure returns (bool isValid) {
+ isValid = b.length == 64;
+ }
+
+ function encode(UniqueRoyaltyPart[] memory royalties) internal pure returns (bytes memory) {
+ return UniqueRoyalty.encode(royalties);
+ }
+
+ function decode(bytes memory data) internal pure returns (UniqueRoyaltyPart[] memory) {
+ return UniqueRoyalty.decode(data);
+ }
+
+ // todo - implement smth better - check royalties sum is lte 100%
+ function validate(bytes memory b) internal pure returns (bool) {
+ return b.length % 64 == 0;
+ }
+
+ function getTokenRoyalty(address collection, uint tokenId) internal view returns (UniqueRoyaltyPart[] memory) {
+ try ICollection(collection).property(tokenId, ROYALTIES_PROPERTY) returns (bytes memory encoded) {
+ return UniqueRoyalty.decode(encoded);
+ } catch {
+ return new UniqueRoyaltyPart[](0);
+ }
+ }
+
+ function getCollectionRoyalty(address collection) internal view returns (UniqueRoyaltyPart[] memory) {
+ try ICollection(collection).collectionProperty(ROYALTIES_PROPERTY) returns (bytes memory encoded) {
+ return UniqueRoyalty.decode(encoded);
+ } catch {
+ return new UniqueRoyaltyPart[](0);
+ }
+ }
+
+ function getRoyalty(address collection, uint tokenId) internal view returns (UniqueRoyaltyPart[] memory royalty) {
+ royalty = getTokenRoyalty(collection, tokenId);
+
+ if (royalty.length == 0) {
+ royalty = getCollectionRoyalty(collection);
+ }
+ }
+
+ function calculateRoyalties(UniqueRoyaltyPart[] memory royalties, bool isPrimarySale, uint sellPrice) internal pure returns (RoyaltyAmount[] memory) {
+ RoyaltyAmount[] memory royaltyAmounts = new RoyaltyAmount[](royalties.length);
+ uint amountsCount = 0;
+
+ for (uint i = 0; i < royalties.length; i++) {
+ if (isPrimarySale == royalties[i].isPrimarySaleOnly) {
+ uint amount = (sellPrice * royalties[i].value) / (10 ** (royalties[i].decimals));
+
+ royaltyAmounts[amountsCount] = RoyaltyAmount({
+ crossAddress: royalties[i].crossAddress,
+ amount: amount
+ });
+
+ amountsCount += 1;
+ }
+ }
+
+ // shrink royaltyAmounts to amountsCount length
+ assembly { mstore(royaltyAmounts, amountsCount) }
+
+ return royaltyAmounts;
+ }
+
+ function calculateForPrimarySale(address collection, uint tokenId, uint sellPrice) internal view returns (RoyaltyAmount[] memory) {
+ UniqueRoyaltyPart[] memory royalties = getRoyalty(collection, tokenId);
+
+ return calculateRoyalties(royalties, true, sellPrice);
+ }
+
+ function calculate(address collection, uint tokenId, uint sellPrice) internal view returns (RoyaltyAmount[] memory) {
+ UniqueRoyaltyPart[] memory royalties = getRoyalty(collection, tokenId);
+
+ return calculateRoyalties(royalties, false, sellPrice);
+ }
+}
\ No newline at end of file
js-packages/tests/eth/marketplace-v2/utils.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace-v2/utils.sol
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.17;
+
+contract Utils {
+ function toString(address account) public pure returns (string memory) {
+ return toString(abi.encodePacked(account));
+ }
+
+ function toString(bool value) public pure returns (string memory) {
+ return value ? "true" : "false";
+ }
+
+ function toString(uint256 value) public pure returns (string memory) {
+ return toString(abi.encodePacked(value));
+ }
+
+ function toString(bytes32 value) public pure returns (string memory) {
+ return toString(abi.encodePacked(value));
+ }
+
+ function toString(bytes memory data) public pure returns (string memory) {
+ bytes memory alphabet = "0123456789abcdef";
+
+ bytes memory str = new bytes(2 + data.length * 2);
+ str[0] = "0";
+ str[1] = "x";
+ for (uint i = 0; i < data.length; i++) {
+ str[2 + i * 2] = alphabet[uint(uint8(data[i] >> 4))];
+ str[3 + i * 2] = alphabet[uint(uint8(data[i] & 0x0f))];
+ }
+ return string(str);
+ }
+}
\ No newline at end of file
js-packages/tests/eth/marketplace/MarketPlace.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace/MarketPlace.sol
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: Apache License
+pragma solidity >=0.8.0;
+import {UniqueNFT, Dummy, ERC165} from "../api/UniqueNFT.sol";
+
+// Inline
+interface ERC20Events {
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(
+ address indexed owner,
+ address indexed spender,
+ uint256 value
+ );
+}
+
+interface ERC20 is Dummy, ERC165, ERC20Events {
+ // Selector: name() 06fdde03
+ function name() external view returns (string memory);
+
+ // Selector: symbol() 95d89b41
+ function symbol() external view returns (string memory);
+
+ // Selector: totalSupply() 18160ddd
+ function totalSupply() external view returns (uint256);
+
+ // Selector: decimals() 313ce567
+ function decimals() external view returns (uint8);
+
+ // Selector: balanceOf(address) 70a08231
+ function balanceOf(address owner) external view returns (uint256);
+
+ // Selector: transfer(address,uint256) a9059cbb
+ function transfer(address to, uint256 amount) external returns (bool);
+
+ // Selector: transferFrom(address,address,uint256) 23b872dd
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external returns (bool);
+
+ // Selector: approve(address,uint256) 095ea7b3
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ // Selector: allowance(address,address) dd62ed3e
+ function allowance(address owner, address spender)
+ external
+ view
+ returns (uint256);
+}
+
+interface UniqueFungible is Dummy, ERC165, ERC20 {}
+
+contract MarketPlace {
+ struct Order {
+
+ uint256 idNFT;
+ address currencyCode; // UNIQ tokens as address address (1); wKSM
+ uint256 price;
+ uint256 time;
+ address idCollection;
+ address ownerAddr;
+ uint8 flagActive;
+ string name;
+ string symbol;
+ string tokenURI;
+ }
+ Order[] public orders;
+ uint test;
+ mapping (address => uint256) public balanceKSM; // [ownerAddr][currency] => [KSMs]
+ mapping (address => mapping (uint256 => uint256)) public asks ; // [buyer][idCollection][idNFT] => idorder
+ mapping (address => mapping (uint => uint[])) public ordersbyNFT; // [addressCollection] =>idNFT =>idorder
+
+ mapping (address => uint[]) public asksbySeller; // [addressSeller] =>idorder
+
+ mapping (address =>bool) internal isEscrow;
+
+ //address escrow;
+ address owner;
+ address nativecoin;
+
+ // from abstract contract ReentrancyGuard
+ // Booleans are more expensive than uint256 or any type that takes up a full
+ // word because each write operation emits an extra SLOAD to first read the
+ // slot's contents, replace the bits taken up by the boolean, and then write
+ // back. This is the compiler's defense against contract upgrades and
+ // pointer aliasing, and it cannot be disabled.
+
+ // The values being non-zero value makes deployment a bit more expensive,
+ // but in exchange the refund on every call to nonReentrant will be lower in
+ // amount. Since refunds are capped to a percentage of the total
+ // transaction's gas, it is best to keep them low in cases like this one, to
+ // increase the likelihood of the full refund coming into effect.
+ uint8 private constant _NOT_ENTERED = 1;
+ uint8 private constant _ENTERED = 2;
+
+ uint8 private _status;
+
+ struct NFT {
+ address collection;
+ uint256 id;
+ }
+
+ //function initialize() public initializer {
+ constructor () { // call setEscrow directly
+ owner = msg.sender;
+
+ orders.push(Order(
+ 0,
+ address(0),
+ 0,
+ 0,
+ address(0),
+ address(0),
+ 0, "","",""));
+ _status = _NOT_ENTERED;
+
+ }
+
+ modifier nonReentrant() { // from abstract contract ReentrancyGuard
+ // On the first call to nonReentrant, _notEntered will be true
+ require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
+
+ // Any calls to nonReentrant after this point will fail
+ _status = _ENTERED;
+
+ _;
+
+ // By storing the original value once again, a refund is triggered (see
+ // https://eips.ethereum.org/EIPS/eip-2200)
+ _status = _NOT_ENTERED;
+ }
+
+ modifier onlyEscrow () {
+ require(isEscrow [msg.sender] , "Only escrow can");
+ _;
+ }
+
+ modifier onlyOwner () {
+ require(msg.sender == owner, "Only owner can");
+ _;
+ }
+
+ /**
+ * Make bids (orders) to sell NFTs
+ */
+
+
+ receive () external payable {
+ // revert ("Can't accept payment without collection and IDs, use dApp to send");
+ }
+ fallback () external payable {
+ revert ("No such function");
+ }
+
+ event AddedAsk (uint256 _price,
+ address _currencyCode,
+ address _idCollection,
+ uint256 _idNFT,
+ uint256 orderId
+ );
+ event EditedAsk (uint256 _price,
+ address _currencyCode,
+ address _idCollection,
+ uint256 _idNFT,
+ uint8 _active,
+ uint orderId);
+
+ event CanceledAsk (address _idCollection,
+ uint256 _idNFT,
+ uint orderId
+ );
+
+ event DepositedKSM (uint256 _amount, address _sender);
+
+ event BoughtNFT4KSM (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );
+
+ event BoughtNFT (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );
+
+ event WithdrawnAllKSM (address _sender, uint256 balance);
+
+ event WithdrawnKSM (address _sender, uint256 balance);
+
+ event Withdrawn (uint256 _amount, address _currencyCode, address _sender);
+
+
+ function setOwner (address _newOwner) public onlyOwner {
+ owner = _newOwner;
+ }
+
+ function setEscrow (address _escrow, bool _state) public onlyOwner returns (bool) {
+ if (isEscrow[_escrow] != _state) {
+ isEscrow[_escrow] = _state;
+ return true;
+ }
+ return false;
+ }
+
+ function setNativeCoin (address _coin) public onlyOwner {
+ nativecoin = _coin;
+ }
+
+
+ function addAsk (uint256 _price,
+ address _currencyCode,
+ address _idCollection,
+ uint256 _idNFT
+ ) public { //
+ address ownerNFT = UniqueNFT(_idCollection).ownerOf(_idNFT);
+ require (ownerNFT == msg.sender, "Only token owner can make ask");
+ string memory nameNFT;
+ string memory symbolNFT;
+ string memory uriNFT;
+ try UniqueNFT(_idCollection).name() returns (string memory name_) {
+ nameNFT = name_;
+ }
+ catch {
+ nameNFT="";
+ }
+ try UniqueNFT(_idCollection).symbol() returns (string memory symbol_) {
+ symbolNFT = symbol_;
+ }
+ catch {
+ symbolNFT="";
+ }
+ try UniqueNFT(_idCollection).tokenURI(_idNFT) returns (string memory uri_) {
+ uriNFT = uri_;
+ }
+ catch {
+ uriNFT="";
+ }
+ orders.push(Order(
+ _idNFT,
+ _currencyCode,
+ _price,
+ block.timestamp,
+ _idCollection,
+ msg.sender,
+ 1, // 1 = is active
+ nameNFT,
+ symbolNFT,
+ uriNFT
+ ));
+
+ uint orderId = orders.length-1;
+ asks[_idCollection][_idNFT] = orderId;
+ asksbySeller[msg.sender].push(orderId);
+ UniqueNFT(_idCollection).transferFrom(msg.sender, address(this), _idNFT);
+ emit AddedAsk(_price, _currencyCode, _idCollection, _idNFT, orderId);
+ }
+
+ function editAsk (uint256 _price,
+ address _currencyCode,
+ address _idCollection,
+ uint256 _idNFT,
+ uint8 _active) public {
+
+
+ uint orderID = asks[_idCollection][_idNFT];
+
+ require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");
+ require (orders[orderID].flagActive != 0, "This ask is closed");
+ if (_price> 0 ) {
+ orders[orderID].price = _price ;
+ }
+
+ if (_currencyCode != address(0) ) {
+ orders[orderID].currencyCode = _currencyCode ;
+ }
+
+ orders[orderID].time = block.timestamp;
+ orders[orderID].flagActive = _active;
+
+ emit EditedAsk(_price, _currencyCode, _idCollection, _idNFT, _active, orderID);
+ }
+
+
+ function cancelAsk (address _idCollection,
+ uint256 _idNFT
+ ) public {
+
+ uint orderID = asks[_idCollection][_idNFT];
+
+ require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");
+ require (orders[orderID].flagActive != 0, "This ask is closed");
+
+ orders[orderID].time = block.timestamp;
+ orders[orderID].flagActive = 0;
+ UniqueNFT(_idCollection).transferFrom(address(this),orders[orderID].ownerAddr, _idNFT);
+ emit CanceledAsk(_idCollection, _idNFT, orderID);
+ }
+
+
+ function depositKSM (uint256 _amount, address _sender) public onlyEscrow {
+ balanceKSM[_sender] = balanceKSM[_sender] + _amount;
+ emit DepositedKSM(_amount, _sender);
+ }
+
+ function buyKSM (address _idCollection, uint256 _idNFT, address _buyer, address _receiver ) public {
+
+ Order memory order = orders[ asks[_idCollection][_idNFT]];
+ require(isEscrow[msg.sender] || msg.sender == _buyer, "Only escrow or buyer can call buyKSM" );
+ //1. reduce balance
+
+ balanceKSM[_buyer] = balanceKSM[_buyer] - order.price;
+ balanceKSM[order.ownerAddr] = balanceKSM[order.ownerAddr] + order.price;
+ // 2. close order
+ orders[ asks[_idCollection][_idNFT]].flagActive = 0;
+ // 3. transfer NFT to buyer
+ UniqueNFT(_idCollection).transferFrom(address(this), _receiver, _idNFT);
+ emit BoughtNFT4KSM(_idCollection, _idNFT, asks[_idCollection][_idNFT], order.price);
+
+ }
+ function buy (address _idCollection, uint256 _idNFT ) public payable returns (bool result) { //buing for UNQ like as ethers
+
+ Order memory order = orders[asks[_idCollection][_idNFT]];
+ //1. check sent amount and send to seller
+ require (msg.value == order.price, "Not right amount sent, have to be equal price" );
+ // 2. close order
+ orders[ asks[_idCollection][_idNFT]].flagActive = 0;
+
+ // 3. transfer NFT to buyer
+ UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT);
+ //uint balance = address(this).balance;
+ result = payable(order.ownerAddr).send (order.price);
+ emit BoughtNFT(_idCollection, _idNFT, asks[_idCollection][_idNFT], order.price);
+
+ }
+
+/*
+ function buyOther (address _idCollection, uint256 _idNFT, address _currencyCode, uint _amount ) public { //buy for sny token if seller wants
+
+ Order memory order = orders[ asks[_idCollection][_idNFT]];
+ //1. check sent amount and transfer from buyer to seller
+ require (order.price == _amount && order.currencyCode == _currencyCode, "Not right amount or currency sent, have to be equal currency and price" );
+ // !!! transfer have to be approved to marketplace!
+ UniqueFungible(order.currencyCode).transferFrom(msg.sender, address(this), order.price); //to not disclojure buyer's address
+ UniqueFungible(order.currencyCode).transfer(order.ownerAddr, order.price);
+ // 2. close order
+ orders[ asks[_idCollection][_idNFT]].flagActive = 0;
+ // 3. transfer NFT to buyer
+ UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT);
+
+
+ }
+ */
+
+ function withdrawAllKSM (address _sender) public nonReentrant returns (uint lastBalance ){
+ require(isEscrow[msg.sender] || msg.sender == _sender, "Only escrow or balance owner can withdraw all KSM" );
+
+ lastBalance = balanceKSM[_sender];
+ balanceKSM[_sender] =0;
+ emit WithdrawnAllKSM(_sender, lastBalance);
+ }
+
+ function withdrawKSM (uint _amount, address _sender) onlyEscrow public {
+ balanceKSM[_sender] = balanceKSM[_sender] - _amount;
+ emit WithdrawnKSM(_sender, balanceKSM[_sender]);
+
+ }
+
+ function withdraw (uint256 _amount, address _currencyCode) public nonReentrant returns (bool result ){ //onlyOwner
+ address payable _sender = payable( msg.sender);
+ if (_currencyCode != nativecoin ) { //erc20 compat. tokens on UNIQUE chain
+ // uint balance = UniqueFungible(_currencyCode).balanceOf(address(this));
+ UniqueFungible(_currencyCode).transfer(_sender, _amount);
+ } else {
+ // uint balance = address(this).balance;
+
+ result = (_sender).send(_amount); // for UNQ like as ethers
+ }
+ emit Withdrawn(_amount, _currencyCode, _sender);
+ return result;
+
+ }
+
+
+ // event GettedOrder(uint , Order);
+ function getOrder (address _idCollection, uint256 _idNFT) public view returns (Order memory) {
+ uint orderId = asks[_idCollection][_idNFT];
+ Order memory order = orders[orderId];
+ // emit GettedOrder (orderId, order);
+ return order;
+ }
+
+ function getOrdersLen () public view returns (uint) {
+ return orders.length;
+ }
+
+ function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) public pure returns(bytes4) {
+ return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
+ }
+
+ //TODO make destructing function to return all
+ function terminate(address[] calldata tokens, NFT[] calldata nfts) public onlyOwner {
+ // Transfer tokens to owner (TODO: error handling)
+ for (uint i = 0; i < tokens.length; i++) {
+ address addr = tokens[i];
+ UniqueFungible token = UniqueFungible(addr);
+ uint256 balance = token.balanceOf(address(this));
+ token.transfer(owner, balance);
+ }
+ for (uint i = 0; i < nfts.length; i++) {
+ address addr = nfts[i].collection;
+ UniqueNFT token = UniqueNFT(addr);
+ token.transferFrom(address(this), owner, nfts[i].id);
+ }
+ // Transfer Eth to owner and terminate contract
+ address payable owner1 = payable (owner);
+ uint balance = address(this).balance;
+ owner1.transfer(balance);
+
+ }
+
+}
js-packages/tests/eth/marketplace/marketplace.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/marketplace/marketplace.test.ts
@@ -0,0 +1,208 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {readFile} from 'fs/promises';
+import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from '../util/index.js';
+import {makeNames} from '../../util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+describe('Matcher contract usage', () => {
+ const PRICE = 2000n;
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let aliceMirror: string;
+ let aliceDoubleMirror: string;
+ let seller: IKeyringPair;
+ let sellerMirror: string;
+
+ before(async () => {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ beforeEach(async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ [alice] = await helper.arrange.createAccounts([1000n], donor);
+ aliceMirror = helper.address.substrateToEth(alice.address).toLowerCase();
+ aliceDoubleMirror = helper.address.ethToSubstrate(aliceMirror);
+ seller = await privateKey(`//Seller/${Date.now()}`);
+ sellerMirror = helper.address.substrateToEth(seller.address).toLowerCase();
+
+ await helper.balance.transferToSubstrate(donor, aliceDoubleMirror, 10_000_000_000_000_000_000n);
+ });
+ });
+
+ itEth('With UNQ', async ({helper}) => {
+ const matcherOwner = await helper.eth.createAccountWithBalance(donor);
+ const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
+
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);
+ await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
+ await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
+
+ await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});
+ await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});
+
+ const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: {Substrate: alice.address}});
+ await collection.confirmSponsorship(alice);
+ await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});
+ const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+ await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);
+
+ await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});
+ await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});
+
+ const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
+
+ // Token is owned by seller initially
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
+
+ // Ask
+ {
+ await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
+ await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
+ }
+
+ // Token is transferred to matcher
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
+
+ // Buy
+ {
+ const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);
+ await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());
+ expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);
+ }
+
+ // Token is transferred to evm account of alice
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
+
+ // Transfer token to substrate side of alice
+ await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
+
+ // Token is transferred to substrate account of alice, seller received funds
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itEth('With escrow', async ({helper}) => {
+ const matcherOwner = await helper.eth.createAccountWithBalance(donor);
+ const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
+
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const escrow = await helper.eth.createAccountWithBalance(donor);
+ await matcher.methods.setEscrow(escrow, true).send({from: matcherOwner});
+ const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);
+ await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
+ await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
+
+ await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});
+ await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});
+
+ const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: {Substrate: alice.address}});
+ await collection.confirmSponsorship(alice);
+ await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});
+ const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+ await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);
+
+
+ await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});
+
+ await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});
+
+ const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
+
+ // Token is owned by seller initially
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
+
+ // Ask
+ {
+ await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
+ await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
+ }
+
+ // Token is transferred to matcher
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
+
+ // Give buyer KSM
+ await matcher.methods.depositKSM(PRICE, aliceMirror).send({from: escrow});
+
+ // Buy
+ {
+ expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal('0');
+ expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal(PRICE.toString());
+
+ await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buyKSM(evmCollection.options.address, token.tokenId, aliceMirror, aliceMirror).encodeABI(), '0');
+
+ // Price is removed from buyer balance, and added to seller
+ expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal('0');
+ expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal(PRICE.toString());
+ }
+
+ // Token is transferred to evm account of alice
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
+
+ // Transfer token to substrate side of alice
+ await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
+
+ // Token is transferred to substrate account of alice, seller received funds
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {
+ const matcherOwner = await helper.eth.createAccountWithBalance(donor);
+ const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
+
+ await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);
+
+ const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}});
+ const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+
+ await helper.balance.transferToSubstrate(donor, seller.address, 100_000_000_000_000_000_000n);
+
+ const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
+
+ // Token is owned by seller initially
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
+
+ // Ask
+ {
+ await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
+ await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
+ }
+
+ // Token is transferred to matcher
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
+
+ // Buy
+ {
+ const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);
+ await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());
+ expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);
+ }
+
+ // Token is transferred to evm account of alice
+ expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
+
+ // Transfer token to substrate side of alice
+ await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
+
+ // Token is transferred to substrate account of alice, seller received funds
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+});
js-packages/tests/eth/migration.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/migration.seqtest.ts
@@ -0,0 +1,209 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Struct} from '@polkadot/types';
+
+import type {IEvent} from '@unique/playgrounds/types.js';
+import type {InterfaceTypes} from '@polkadot/types/types/registry';
+import {ApiPromise} from '@polkadot/api';
+
+const encodeEvent = (api: ApiPromise, pallet: string, palletEvents: string, event: string, fields: any) => {
+ const palletIndex = api.runtimeMetadata.asV14.pallets.find(p => p.name.toString() == pallet)!.index.toNumber();
+ const eventMeta = api.events[palletEvents][event].meta;
+ const eventIndex = eventMeta.index.toNumber();
+ const data = [
+ palletIndex, eventIndex,
+ ];
+ const metaEvent = api.registry.findMetaEvent(new Uint8Array(data));
+ data.push(...new Struct(api.registry, {data: metaEvent}, {data: fields}).toU8a());
+
+ const typeName = api.registry.lookup.names.find(n => n.endsWith('RuntimeEvent'))!;
+ const obj = api.registry.createType(typeName, new Uint8Array(data)) as InterfaceTypes['RuntimeEvent'];
+ return obj.toHex();
+};
+
+describe('EVM Migrations', () => {
+ let superuser: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ superuser = await privateKey('//Alice');
+ charlie = await privateKey('//Charlie');
+ });
+ });
+
+ // todo:playgrounds requires sudo, look into later
+ itEth('Deploy contract saved state', async ({helper}) => {
+ /*
+ contract StatefulContract {
+ uint counter;
+ mapping (uint => uint) kv;
+
+ function inc() public {
+ counter = counter + 1;
+ }
+ function counterValue() public view returns (uint) {
+ return counter;
+ }
+
+ function set(uint key, uint value) public {
+ kv[key] = value;
+ }
+
+ function get(uint key) public view returns (uint) {
+ return kv[key];
+ }
+ }
+ */
+ const ADDRESS = '0x4956bf52ef9ed8789f21bc600e915e0d961079f6';
+ const CODE = '0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ab06ee514610051578063371303c01461006d5780637bfdec3b146100775780639507d39a14610095575b600080fd5b61006b60048036038101906100669190610160565b6100c5565b005b6100756100e1565b005b61007f6100f8565b60405161008c91906101af565b60405180910390f35b6100af60048036038101906100aa9190610133565b610101565b6040516100bc91906101af565b60405180910390f35b8060016000848152602001908152602001600020819055505050565b60016000546100f091906101ca565b600081905550565b60008054905090565b600060016000838152602001908152602001600020549050919050565b60008135905061012d8161025e565b92915050565b60006020828403121561014957610148610259565b5b60006101578482850161011e565b91505092915050565b6000806040838503121561017757610176610259565b5b60006101858582860161011e565b92505060206101968582860161011e565b9150509250929050565b6101a981610220565b82525050565b60006020820190506101c460008301846101a0565b92915050565b60006101d582610220565b91506101e083610220565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156102155761021461022a565b5b828201905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b61026781610220565b811461027257600080fd5b5056fea26469706673582212206a02d2fb5c244105ab884961479c1aee3b4c1011e4b5530ab483eb22344a865664736f6c63430008060033';
+ const DATA = [
+ // counter = 10
+ ['0x0000000000000000000000000000000000000000000000000000000000000000', '0x000000000000000000000000000000000000000000000000000000000000000a'],
+ // kv = {1: 1, 2: 2, 3: 3, 4: 4},
+ ['0xcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f', '0x0000000000000000000000000000000000000000000000000000000000000001'],
+ ['0xd9d16d34ffb15ba3a3d852f0d403e2ce1d691fb54de27ac87cd2f993f3ec330f', '0x0000000000000000000000000000000000000000000000000000000000000002'],
+ ['0x7dfe757ecd65cbd7922a9c0161e935dd7fdbcc0e999689c7d31633896b1fc60b', '0x0000000000000000000000000000000000000000000000000000000000000003'],
+ ['0xedc95719e9a3b28dd8e80877cb5880a9be7de1a13fc8b05e7999683b6b567643', '0x0000000000000000000000000000000000000000000000000000000000000004'],
+ ];
+
+ const caller = await helper.eth.createAccountWithBalance(superuser);
+
+ const txBegin = helper.constructApiCall('api.tx.evmMigration.begin', [ADDRESS]);
+ const txSetData = helper.constructApiCall('api.tx.evmMigration.setData', [ADDRESS, DATA]);
+ const txFinish = helper.constructApiCall('api.tx.evmMigration.finish', [ADDRESS, CODE]);
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txBegin])).to.be.fulfilled;
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txSetData])).to.be.fulfilled;
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txFinish])).to.be.fulfilled;
+
+ const web3 = helper.getWeb3();
+ const contract = new web3.eth.Contract([
+ {
+ inputs: [],
+ name: 'counterValue',
+ outputs: [{
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{
+ internalType: 'uint256',
+ name: 'key',
+ type: 'uint256',
+ }],
+ name: 'get',
+ outputs: [{
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ ], ADDRESS, {from: caller, gas: helper.eth.DEFAULT_GAS});
+
+ expect(await contract.methods.counterValue().call()).to.be.equal('10');
+ for(let i = 1; i <= 4; i++) {
+ expect(await contract.methods.get(i).call()).to.be.equal(i.toString());
+ }
+ });
+ itEth('Fake collection creation on substrate side', async ({helper}) => {
+ const txInsertEvents = helper.constructApiCall('api.tx.evmMigration.insertEvents', [[
+ encodeEvent(helper.getApi(), 'Common', 'common', 'CollectionCreated', [
+ // Collection Id
+ 9999,
+ // Collection mode: NFT
+ 1,
+ // Owner
+ charlie.address,
+ ]),
+ ]]);
+ await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEvents]);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contain('common.CollectionCreated');
+ });
+ itEth('Fake token creation on substrate side', async ({helper}) => {
+ const txInsertEvents = helper.constructApiCall('api.tx.evmMigration.insertEvents', [[
+ encodeEvent(helper.getApi(), 'Common', 'common', 'ItemCreated', [
+ // Collection Id
+ 9999,
+ // TokenId
+ 9999,
+ // Owner
+ {Substrate: charlie.address},
+ // Amount
+ 1,
+ ]),
+ ]]);
+ await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEvents]);
+ const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+ const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+ expect(eventStrings).to.contain('common.ItemCreated');
+ });
+ itEth('Fake token creation on ethereum side', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(superuser);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const caller = await helper.eth.createAccountWithBalance(superuser);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ {
+ const txInsertEthLogs = helper.constructApiCall('api.tx.evmMigration.insertEthLogs', [[
+ {
+ // Contract, which has emitted this log
+ address: collectionAddress,
+
+ topics: [
+ // First topic - event signature
+ helper.getWeb3().eth.abi.encodeEventSignature('Transfer(address,address,uint256)'),
+ // Rest of topics - indexed event fields in definition order
+ helper.getWeb3().eth.abi.encodeParameter('address', '0x' + '00'.repeat(20)),
+ helper.getWeb3().eth.abi.encodeParameter('address', caller),
+ helper.getWeb3().eth.abi.encodeParameter('uint256', 9999),
+ ],
+
+ // Every field coming from event, which is not marked as indexed, should be encoded here
+ // NFT transfer has no such fields, but here is an example for some other possible event:
+ // data: helper.getWeb3().eth.abi.encodeParameters(['uint256', 'address'], [22, collectionAddress])
+ data: [],
+ },
+ ]]);
+ await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEthLogs]);
+ }
+
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x' + '00'.repeat(20));
+ expect(event.returnValues.to).to.be.equal(caller);
+ expect(event.returnValues.tokenId).to.be.equal('9999');
+ });
+});
js-packages/tests/eth/nativeFungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/nativeFungible.test.ts
@@ -0,0 +1,173 @@
+// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+
+describe('NativeFungible: ERC20 calls', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('approve()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ await expect(contract.methods.approve(spender, 100).call({from: owner})).to.be.rejectedWith('approve not supported');
+ });
+
+ itEth('balanceOf()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor, 123n);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const balance = await contract.methods.balanceOf(owner).call({from: owner});
+ expect(balance).to.be.eq('123000000000000000000');
+ });
+
+ itEth('decimals()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const realDecimals = (await helper.chain.getChainProperties().tokenDecimals)[0].toString();
+ const decimals = await contract.methods.decimals().call({from: owner});
+ expect(decimals).to.be.eq(realDecimals);
+ });
+
+ itEth('name()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const realName = await UniqueHelper.detectNetwork(helper.getApi());
+ const name = await contract.methods.name().call({from: owner});
+ expect(name).to.be.eq(realName);
+ });
+
+ itEth('symbol()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const realName = (await helper.chain.getChainProperties().tokenSymbol)[0];
+ const name = await contract.methods.symbol().call({from: owner});
+ expect(name).to.be.eq(realName);
+ });
+
+ itEth('totalSupply()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const totalSupplyEth = BigInt(await contract.methods.totalSupply().call({from: owner}));
+ const totalSupplySub = await helper.balance.getTotalIssuance();
+ expect(totalSupplyEth).to.be.eq(totalSupplySub);
+ });
+
+ itEth('transfer()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const balanceOwnerBefore = await helper.balance.getEthereum(owner);
+ const balanceReceiverBefore = await helper.balance.getEthereum(receiver);
+
+ await contract.methods.transfer(receiver, 50).send({from: owner});
+
+ const balanceOwnerAfter = await helper.balance.getEthereum(owner);
+ const balanceReceiverAfter = await helper.balance.getEthereum(receiver);
+
+ expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
+ expect(balanceReceiverBefore + 50n).to.be.equal(balanceReceiverAfter);
+ });
+
+ itEth('transferFrom()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const balanceOwnerBefore = await helper.balance.getEthereum(owner);
+ const balanceReceiverBefore = await helper.balance.getEthereum(receiver);
+
+ await contract.methods.transferFrom(owner, receiver, 50).send({from: owner});
+
+ const balanceOwnerAfter = await helper.balance.getEthereum(owner);
+ const balanceReceiverAfter = await helper.balance.getEthereum(receiver);
+
+ expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
+ expect(balanceReceiverBefore === balanceReceiverAfter - 50n).to.be.true;
+
+ await expect(contract.methods.transferFrom(receiver, receiver, 50).call({from: owner})).to.be.rejectedWith('ApprovedValueTooLow');
+ });
+});
+
+describe('NativeFungible: ERC20UniqueExtensions calls', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('transferCross()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+
+ const balanceOwnerBefore = await helper.balance.getEthereum(owner);
+ const balanceReceiverBefore = await helper.balance.getEthereum(receiver.eth);
+
+ await contract.methods.transferCross(receiver, 50).send({from: owner});
+
+ const balanceOwnerAfter = await helper.balance.getEthereum(owner);
+ const balanceReceiverAfter = await helper.balance.getEthereum(receiver.eth);
+
+ expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
+ expect(balanceReceiverBefore === balanceReceiverAfter - 50n).to.be.true;
+ });
+
+ itEth('transferFromCross()', async ({helper}) => {
+ const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const receiver = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner.eth);
+
+ const balanceOwnerBefore = await helper.balance.getEthereum(owner.eth);
+ const balanceReceiverBefore = await helper.balance.getEthereum(receiver.eth);
+
+ await contract.methods.transferFromCross(owner, receiver, 50).send({from: owner.eth});
+
+ const balanceOwnerAfter = await helper.balance.getEthereum(owner.eth);
+ const balanceReceiverAfter = await helper.balance.getEthereum(receiver.eth);
+
+ expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
+ expect(balanceReceiverBefore === balanceReceiverAfter - 50n).to.be.true;
+
+ await expect(contract.methods.transferFromCross(receiver, receiver, 50).call({from: owner.eth})).to.be.rejectedWith('no permission');
+ });
+});
js-packages/tests/eth/nativeRpc/estimateGas.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/nativeRpc/estimateGas.test.ts
@@ -0,0 +1,62 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+
+describe('Ethereum native RPC calls', () => {
+ let donor: IKeyringPair;
+ const NATIVE_TOKEN_ADDRESS = '0x17c4e6453cc49aaaaeaca894e6d9683e00000000';
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('estimate gas', async ({helper}) => {
+ const BALANCE = 100n;
+ const BALANCE_TO_TRANSFER = 90n;
+
+ const owner = await helper.eth.createAccountWithBalance(donor, BALANCE);
+ const recepient = helper.eth.createAccount();
+
+ const web3 = helper.getWeb3();
+ // data: transfer(recepient, 90);
+ const data = web3.eth.abi.encodeFunctionCall({
+ name: 'transfer',
+ type: 'function',
+ inputs: [{
+ type: 'address',
+ name: 'to',
+ },{
+ type: 'uint256',
+ name: 'amount',
+ }],
+ }, [recepient, (BALANCE_TO_TRANSFER * (10n ** 18n)).toString()]);
+
+ const estimateGas = await web3.eth.estimateGas({
+ to: NATIVE_TOKEN_ADDRESS,
+ value: '0x0',
+ data,
+ from: owner,
+ maxFeePerGas: '0x14c9338c61d',
+ });
+
+ expect(estimateGas).to.be.greaterThan(35000).and.to.be.lessThan(50000);
+ });
+});
js-packages/tests/eth/nesting/nest.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/nesting/nest.test.ts
@@ -0,0 +1,289 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
+
+import {itEth, usingEthPlaygrounds, expect} from '../util/index.js';
+import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+
+const createNestingCollection = async (
+ helper: EthUniqueHelper,
+ owner: string,
+ mergeDeprecated = false,
+): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
+ const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, mergeDeprecated);
+ await contract.methods.setCollectionNesting([true, false, []]).send({from: owner});
+
+ return {collectionId, collectionAddress, contract};
+};
+
+
+describe('EVM nesting tests group', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ describe('Integration Test: EVM Nesting', () => {
+ itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Create a token to be nested to
+ const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
+
+ // Create a nested token
+ const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});
+ const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;
+ expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Create a token to be nested and nest
+ const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Unnest token back
+ await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
+ });
+
+ itEth('NFT: collectionNesting()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress: unnestedCollectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const unnestedContract = await helper.ethNativeContract.collection(unnestedCollectionAddress, 'nft', owner);
+ expect(await unnestedContract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
+
+ const {contract} = await createNestingCollection(helper, owner);
+ expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([true, false, []]);
+ await contract.methods.setCollectionNesting([true, false, [unnestedCollectionAddress]]).send({from: owner});
+ expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([true, false, [unnestedCollectionAddress]]);
+ await contract.methods.setCollectionNesting([false, true, [unnestedCollectionAddress]]).send({from: owner});
+ expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([false, true, [unnestedCollectionAddress]]);
+ await contract.methods.setCollectionNesting([false, false, []]).send({from: owner});
+ expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
+ });
+
+ // Sof-deprecated
+ itEth('NFT: collectionNestingRestrictedCollectionIds() & collectionNestingPermissions', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId: unnestedCollsectionId, collectionAddress: unnsetedCollectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+ const unnestedContract = await helper.ethNativeContract.collection(unnsetedCollectionAddress, 'nft', owner, true);
+ expect(await unnestedContract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([false, []]);
+
+ const {contract} = await createNestingCollection(helper, owner, true);
+ expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, []]);
+ await contract.methods['setCollectionNesting(bool,address[])'](true, [unnsetedCollectionAddress]).send({from: owner});
+ expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, [unnestedCollsectionId.toString()]]);
+ expect(await contract.methods.collectionNestingPermissions().call({from: owner})).to.be.like([['1', false], ['0', true]]);
+ await contract.methods['setCollectionNesting(bool)'](false).send({from: owner});
+ expect(await contract.methods.collectionNestingPermissions().call({from: owner})).to.be.like([['1', false], ['0', false]]);
+ });
+
+ itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {contract: contractB} = await createNestingCollection(helper, owner);
+ await contractA.methods.setCollectionNesting([true, false, [contractA.options.address, contractB.options.address]]).send({from: owner});
+
+ // Create a token to nest into
+ const mintingtargetNftTokenIdResult = await contractA.methods.mint(owner).send({from: owner});
+ const targetNftTokenId = mintingtargetNftTokenIdResult.events.Transfer.returnValues.tokenId;
+ const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);
+
+ // Create a token for nesting in the same collection as the target
+ const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
+ const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
+
+ // Create a token for nesting in a different collection
+ const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});
+ const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
+
+ // Nest
+ await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
+ expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
+
+ await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
+ expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
+ });
+ });
+
+ describe('Negative Test: EVM Nesting', () => {
+ itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+ await contract.methods.setCollectionNesting([false, false, []]).send({from: owner});
+
+ // Create a token to nest into
+ const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
+
+ // Create a token to nest
+ const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ // Try to nest
+ await expect(contract.methods
+ .transfer(targetNftTokenAddress, nftTokenId)
+ .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malignant = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Mint a token
+ const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
+ const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
+
+ // Mint a token belonging to a different account
+ const mintingTokenIdResult = await contract.methods.mint(malignant).send({from: owner});
+ const tokenId = mintingTokenIdResult.events.Transfer.returnValues.tokenId;
+
+ // Try to nest one token in another as a non-owner account
+ await expect(contract.methods
+ .transfer(targetTokenAddress, tokenId)
+ .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malignant = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {contract: contractB} = await createNestingCollection(helper, owner);
+
+ await contractA.methods.setCollectionNesting([true, false, [contractA.options.address, contractB.options.address]]).send({from: owner});
+
+ // Create a token in one collection
+ const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
+ const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
+ const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
+
+ // Create a token in another collection
+ const mintingTokenIdBResult = await contractB.methods.mint(malignant).send({from: owner});
+ const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
+
+ // Try to drag someone else's token into the other collection and nest
+ await expect(contractB.methods
+ .transfer(nftTokenAddressA, nftTokenIdB)
+ .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {contract: contractB} = await createNestingCollection(helper, owner);
+
+ await contractA.methods.setCollectionNesting([true, false, [contractA.options.address]]).send({from: owner});
+
+ // Create a token in one collection
+ const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
+ const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
+ const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
+
+ // Create a token in another collection
+ const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});
+ const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
+
+
+ // Try to nest into a token in the other collection, disallowed in the first
+ await expect(contractB.methods
+ .transfer(nftTokenAddressA, nftTokenIdB)
+ .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
+ });
+ });
+
+ describe('Fungible', () => {
+ async function createFungibleCollection(helper: EthUniqueHelper, owner: string, mode: 'ft' | 'native ft') {
+ if(mode === 'ft') {
+ const {collectionAddress} = await helper.eth.createFungibleCollection(owner, '', 18, '', '');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+ await contract.methods.mint(owner, 100n).send({from: owner});
+ return {collectionAddress, contract};
+ }
+
+ // native ft
+ const collectionAddress = helper.ethAddress.fromCollectionId(0);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+ return {collectionAddress, contract};
+ }
+
+ [
+ {mode: 'ft' as const},
+ {mode: 'native ft' as const},
+ ].map(testCase => {
+ itEth(`Allow nest [${testCase.mode}]`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
+ const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
+
+ const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
+ const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
+
+ await ftContract.methods.transfer(targetTokenAddress, 10n).send({from: owner});
+ expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('10');
+ });
+ });
+
+ [
+ {mode: 'ft' as const},
+ {mode: 'native ft' as const},
+ ].map(testCase => {
+ itEth(`Allow partial/full unnest [${testCase.mode}]`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
+ const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
+
+ const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
+ const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
+
+ await ftContract.methods.transfer(targetTokenAddress, 10n).send({from: owner});
+
+ await ftContract.methods.transferFrom(targetTokenAddress, owner, 5n).send({from: owner});
+ expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('5');
+
+ await ftContract.methods.transferFrom(targetTokenAddress, owner, 5n).send({from: owner});
+ expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('0');
+ });
+ });
+
+ [
+ {mode: 'ft' as const},
+ {mode: 'native ft' as const},
+ ].map(testCase => {
+ itEth(`Disallow nest into collection without nesting permission [${testCase.mode}] (except for native fungible collection)`, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
+ await targetContract.methods.setCollectionNesting([false, false, []]).send({from: owner});
+
+ const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
+
+ const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
+ const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
+ const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
+
+ if(testCase.mode === 'ft') {
+ await expect(ftContract.methods.transfer(targetTokenAddress, 10n).call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ } else {
+ await expect(ftContract.methods.transfer(targetTokenAddress, 10n).call({from: owner})).to.be.not.rejected;
+ }
+ });
+ });
+ });
+});
js-packages/tests/eth/nonFungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/nonFungible.test.ts
@@ -0,0 +1,1127 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
+import type {ITokenPropertyPermission} from '@unique/playgrounds/types.js';
+import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from './util/playgrounds/types.js';
+
+describe('Check ERC721 token URI for NFT', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ async function setup(helper: EthUniqueHelper, baseUri: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ const result = await contract.methods.mint(receiver).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+
+ if(propertyKey && propertyValue) {
+ // Set URL or suffix
+ await contract.methods.setProperties(tokenId, [{key: propertyKey, value: Buffer.from(propertyValue)}]).send();
+ }
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(tokenId);
+
+ return {contract, nextTokenId: tokenId};
+ }
+
+ itEth('Empty tokenURI', async ({helper}) => {
+ const {contract, nextTokenId} = await setup(helper, '');
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
+ });
+
+ itEth('TokenURI from url', async ({helper}) => {
+ const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URI', 'Token URI');
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
+ });
+
+ itEth('TokenURI from baseURI', async ({helper}) => {
+ const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_');
+ });
+
+ itEth('TokenURI from baseURI + suffix', async ({helper}) => {
+ const suffix = '/some/suffix';
+ const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URISuffix', suffix);
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
+ });
+});
+
+describe('NFT: Plain calls', () => {
+ let donor: IKeyringPair;
+ let minter: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ // TODO combine all minting tests in one place
+ [
+ 'substrate' as const,
+ 'ethereum' as const,
+ ].map(testCase => {
+ itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
+ const collectionAdmin = await helper.eth.createAccountWithBalance(donor);
+
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverSub = bob;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+
+ // const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);
+ const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
+ const permissions: ITokenPropertyPermission[] = properties
+ .map(p => ({
+ key: p.key, permission: {
+ tokenOwner: false,
+ collectionAdmin: true,
+ mutable: false,
+ },
+ }));
+
+ const collection = await helper.nft.mintCollection(minter, {
+ tokenPrefix: 'ethp',
+ tokenPropertyPermissions: permissions,
+ });
+ await collection.addAdmin(minter, {Ethereum: collectionAdmin});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', collectionAdmin, true);
+ let expectedTokenId = await contract.methods.nextTokenId().call();
+ let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();
+ let tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal(expectedTokenId);
+
+ let event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+
+ expectedTokenId = await contract.methods.nextTokenId().call();
+ result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();
+ event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+
+ tokenId = result.events.Transfer.returnValues.tokenId;
+
+ expect(tokenId).to.be.equal(expectedTokenId);
+
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
+ .map(p => helper.ethProperty.property(p.key, p.value.toString())));
+
+ expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))
+ .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});
+ });
+ });
+
+ itEth('Non-owner and non admin cannot mintCross', async ({helper}) => {
+ const nonOwner = await helper.eth.createAccountWithBalance(donor);
+ const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
+
+ const collection = await helper.nft.mintCollection(minter);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ await expect(collectionEvm.methods.mintCross(nonOwnerCross, []).call({from: nonOwner}))
+ .to.be.rejectedWith('PublicMintingNotAllowed');
+ });
+
+ //TODO: CORE-302 add eth methods
+ itEth.skip('Can perform mintBulk()', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(minter);
+ await collection.addAdmin(minter, {Ethereum: caller});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
+ {
+ const bulkSize = 3;
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const result = await contract.methods.mintBulkWithTokenURI(
+ receiver,
+ Array.from({length: bulkSize}, (_, i) => (
+ [+nextTokenId + i, `Test URI ${i}`]
+ )),
+ ).send({from: caller});
+
+ const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);
+ for(let i = 0; i < bulkSize; i++) {
+ const event = events[i];
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);
+
+ expect(await contract.methods.tokenURI(+nextTokenId + i).call()).to.be.equal(`Test URI ${i}`);
+ }
+ }
+ });
+
+ itEth('Can perform mintBulkCross()', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const receiver = helper.eth.createAccount();
+ const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
+
+ const permissions = [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.TokenOwner, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true},
+ ];
+ const {collectionAddress} = await helper.eth.createCollection(
+ caller,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'nft',
+ adminList: [callerCross],
+ tokenPropertyPermissions: [
+ {key: 'key_0_0', permissions},
+ {key: 'key_1_0', permissions},
+ {key: 'key_1_1', permissions},
+ {key: 'key_2_0', permissions},
+ {key: 'key_2_1', permissions},
+ {key: 'key_2_2', permissions},
+ ],
+ },
+ ).send();
+
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
+ {
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const result = await contract.methods.mintBulkCross([
+ {
+ owner: receiverCross,
+ properties: [
+ {key: 'key_0_0', value: Buffer.from('value_0_0')},
+ ],
+ },
+ {
+ owner: receiverCross,
+ properties: [
+ {key: 'key_1_0', value: Buffer.from('value_1_0')},
+ {key: 'key_1_1', value: Buffer.from('value_1_1')},
+ ],
+ },
+ {
+ owner: receiverCross,
+ properties: [
+ {key: 'key_2_0', value: Buffer.from('value_2_0')},
+ {key: 'key_2_1', value: Buffer.from('value_2_1')},
+ {key: 'key_2_2', value: Buffer.from('value_2_2')},
+ ],
+ },
+ ]).send({from: caller});
+ const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);
+ const bulkSize = 3;
+ for(let i = 0; i < bulkSize; i++) {
+ const event = events[i];
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);
+ }
+
+ const properties = [
+ await contract.methods.properties(+nextTokenId, []).call(),
+ await contract.methods.properties(+nextTokenId + 1, []).call(),
+ await contract.methods.properties(+nextTokenId + 2, []).call(),
+ ];
+ expect(properties).to.be.deep.equal([
+ [
+ ['key_0_0', helper.getWeb3().utils.toHex('value_0_0')],
+ ],
+ [
+ ['key_1_0', helper.getWeb3().utils.toHex('value_1_0')],
+ ['key_1_1', helper.getWeb3().utils.toHex('value_1_1')],
+ ],
+ [
+ ['key_2_0', helper.getWeb3().utils.toHex('value_2_0')],
+ ['key_2_1', helper.getWeb3().utils.toHex('value_2_1')],
+ ['key_2_2', helper.getWeb3().utils.toHex('value_2_2')],
+ ],
+ ]);
+ }
+ });
+
+ itEth('Can perform burn()', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.nft.mintCollection(minter, {});
+ const {tokenId} = await collection.mintToken(minter, {Ethereum: caller});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
+
+ {
+ const result = await contract.methods.burn(tokenId).send({from: caller});
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(caller);
+ expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+ }
+ });
+
+ itEth('Can perform approve()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(minter, {});
+ const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ {
+ const badTokenId = await contract.methods.nextTokenId().call() + 1;
+ await expect(contract.methods.getApproved(badTokenId).call()).to.be.rejectedWith('revert TokenNotFound');
+ }
+ {
+ const approved = await contract.methods.getApproved(tokenId).call();
+ expect(approved).to.be.equal('0x0000000000000000000000000000000000000000');
+ }
+ {
+ const result = await contract.methods.approve(spender, tokenId).send({from: owner});
+
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.approved).to.be.equal(spender);
+ expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+ }
+ {
+ const approved = await contract.methods.getApproved(tokenId).call();
+ expect(approved).to.be.equal(spender);
+ }
+ });
+
+ itEth('Can perform setApprovalForAll()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(minter, {});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
+ expect(approvedBefore).to.be.equal(false);
+
+ {
+ const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+
+ expect(result.events.ApprovalForAll).to.be.like({
+ address: collectionAddress,
+ event: 'ApprovalForAll',
+ returnValues: {
+ owner,
+ operator,
+ approved: true,
+ },
+ });
+
+ const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+ expect(approvedAfter).to.be.equal(true);
+ }
+
+ {
+ const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
+
+ expect(result.events.ApprovalForAll).to.be.like({
+ address: collectionAddress,
+ event: 'ApprovalForAll',
+ returnValues: {
+ owner,
+ operator,
+ approved: false,
+ },
+ });
+
+ const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+ expect(approvedAfter).to.be.equal(false);
+ }
+ });
+
+ itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft');
+
+ {
+ await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
+ const events = result.events.Transfer;
+
+ expect(events).to.be.like({
+ address,
+ event: 'Transfer',
+ returnValues: {
+ from: owner,
+ to: '0x0000000000000000000000000000000000000000',
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await helper.nft.doesTokenExist(collection.collectionId, token.tokenId)).to.be.false;
+ });
+
+ itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = await helper.eth.createAccountWithBalance(donor);
+ const receiver = charlie;
+
+ const token = await collection.mintToken(minter, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft');
+
+ {
+ await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+ const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: owner,
+ to: helper.address.substrateToEth(receiver.address),
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
+ });
+
+ itEth('Can perform burnFromCross()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const ownerSub = bob;
+ const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
+ const ownerEth = await helper.eth.createAccountWithBalance(donor);
+ const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
+
+ const burnerEth = await helper.eth.createAccountWithBalance(donor);
+ const burnerCrossEth = helper.ethCrossAccount.fromAddress(burnerEth);
+
+ const token1 = await collection.mintToken(minter, {Substrate: ownerSub.address});
+ const token2 = await collection.mintToken(minter, {Ethereum: ownerEth});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ // Approve tokens from substrate and ethereum:
+ await token1.approve(ownerSub, {Ethereum: burnerEth});
+ await collectionEvm.methods.approveCross(burnerCrossEth, token2.tokenId).send({from: ownerEth});
+
+ // can burnFromCross:
+ const result1 = await collectionEvm.methods.burnFromCross(ownerCrossSub, token1.tokenId).send({from: burnerEth});
+ const result2 = await collectionEvm.methods.burnFromCross(ownerCrossEth, token2.tokenId).send({from: burnerEth});
+ const events1 = result1.events.Transfer;
+ const events2 = result2.events.Transfer;
+
+ // Check events for burnFromCross (substrate and ethereum):
+ [
+ [events1, token1, helper.address.substrateToEth(ownerSub.address)],
+ [events2, token2, ownerEth],
+ ].map(burnData => {
+ expect(burnData[0]).to.be.like({
+ address: collectionAddress,
+ event: 'Transfer',
+ returnValues: {
+ from: burnData[2],
+ to: '0x0000000000000000000000000000000000000000',
+ tokenId: burnData[1].tokenId.toString(),
+ },
+ });
+ });
+
+ expect(await token1.doesExist()).to.be.false;
+ expect(await token2.doesExist()).to.be.false;
+ });
+
+ // TODO combine all approve tests in one place
+ itEth('Can perform approveCross()', async ({helper}) => {
+ // arrange: create accounts
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const receiverSub = charlie;
+ const recieverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+ const receiverEth = await helper.eth.createAccountWithBalance(donor);
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+
+ // arrange: create collection and tokens:
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const token1 = await collection.mintToken(minter, {Ethereum: owner});
+ const token2 = await collection.mintToken(minter, {Ethereum: owner});
+
+ const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+
+ // Can approveCross substrate and ethereum address:
+ const resultSub = await collectionEvm.methods.approveCross(recieverCrossSub, token1.tokenId).send({from: owner});
+ const resultEth = await collectionEvm.methods.approveCross(receiverCrossEth, token2.tokenId).send({from: owner});
+ const eventSub = resultSub.events.Approval;
+ const eventEth = resultEth.events.Approval;
+ expect(eventSub).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Approval',
+ returnValues: {
+ owner,
+ approved: helper.address.substrateToEth(receiverSub.address),
+ tokenId: token1.tokenId.toString(),
+ },
+ });
+ expect(eventEth).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Approval',
+ returnValues: {
+ owner,
+ approved: receiverEth,
+ tokenId: token2.tokenId.toString(),
+ },
+ });
+
+ // Substrate address can transferFrom approved tokens:
+ await helper.nft.transferTokenFrom(receiverSub, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiverSub.address});
+ expect(await helper.nft.getTokenOwner(collection.collectionId, token1.tokenId)).to.deep.eq({Substrate: receiverSub.address});
+ // Ethereum address can transferFromCross approved tokens:
+ await collectionEvm.methods.transferFromCross(ownerCross, receiverCrossEth, token2.tokenId).send({from: receiverEth});
+ expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
+ });
+
+ itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {
+ const nonOwner = await helper.eth.createAccountWithBalance(donor);
+ const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+ const token = await collection.mintToken(minter, {Ethereum: owner});
+
+ await expect(collectionEvm.methods.approveCross(nonOwnerCross, token.tokenId).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');
+ });
+
+ itEth('Can reaffirm approved address', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
+ const [receiver1, receiver2] = await helper.arrange.createAccounts([100n, 100n], donor);
+ const receiver1Cross = helper.ethCrossAccount.fromKeyringPair(receiver1);
+ const receiver2Cross = helper.ethCrossAccount.fromKeyringPair(receiver2);
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const token1 = await collection.mintToken(minter, {Ethereum: owner});
+ const token2 = await collection.mintToken(minter, {Ethereum: owner});
+ const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+
+ // Can approve and reaffirm approved address:
+ await collectionEvm.methods.approveCross(receiver1Cross, token1.tokenId).send({from: owner});
+ await collectionEvm.methods.approveCross(receiver2Cross, token1.tokenId).send({from: owner});
+
+ // receiver1 cannot transferFrom:
+ await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
+ // receiver2 can transferFrom:
+ await helper.nft.transferTokenFrom(receiver2, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver2.address});
+
+ // can set approved address to self address to remove approval:
+ await collectionEvm.methods.approveCross(receiver1Cross, token2.tokenId).send({from: owner});
+ await collectionEvm.methods.approveCross(ownerCrossEth, token2.tokenId).send({from: owner});
+
+ // receiver1 cannot transfer token anymore:
+ await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token2.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
+ });
+
+ itEth('Can perform transferFrom()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(minter, {});
+ const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ await contract.methods.approve(spender, tokenId).send({from: owner});
+
+ {
+ const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(1);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(owner).call();
+ expect(+balance).to.equal(0);
+ }
+ });
+
+ itEth('Can perform transferFromCross()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const [owner, receiver] = await helper.arrange.createAccounts([100n, 100n], donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, {Substrate: owner.address});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft');
+
+ await token.approve(owner, {Ethereum: spender});
+
+ {
+ const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+ const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: helper.address.substrateToEth(receiver.address),
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
+ });
+
+ itEth('Can perform transfer()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {});
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ {
+ const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(owner).call();
+ expect(+balance).to.equal(0);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(1);
+ }
+ });
+
+ itEth('Can perform transferCross()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {});
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiverEth = await helper.eth.createAccountWithBalance(donor);
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
+
+ const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+ {
+ // Can transferCross to ethereum address:
+ const result = await collectionEvm.methods.transferCross(receiverCrossEth, tokenId).send({from: owner});
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal(receiverEth);
+ expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+
+ // owner has balance = 0:
+ const ownerBalance = await collectionEvm.methods.balanceOf(owner).call();
+ expect(+ownerBalance).to.equal(0);
+ // receiver owns token:
+ const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+ expect(+receiverBalance).to.equal(1);
+ expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
+ }
+
+ {
+ // Can transferCross to substrate address:
+ const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, tokenId).send({from: receiverEth});
+ // Check events:
+ const event = substrateResult.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(receiverEth);
+ expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
+ expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+
+ // owner has balance = 0:
+ const ownerBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+ expect(+ownerBalance).to.equal(0);
+ // receiver owns token:
+ const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
+ expect(receiverBalance).to.contain(tokenId);
+ }
+ });
+
+ ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+ const tokenOwner = await helper.eth.createAccountWithBalance(donor);
+ const receiverSub = minter;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
+
+ const collection = await helper.nft.mintCollection(minter, {});
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', sender);
+
+ await collection.mintToken(minter, {Ethereum: sender});
+ const nonSendersToken = await collection.mintToken(minter, {Ethereum: tokenOwner});
+
+ // Cannot transferCross someone else's token:
+ const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;
+ await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;
+ // Cannot transfer token if it does not exist:
+ await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;
+ }));
+
+ itEth('Check balanceOfCross()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {});
+ const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
+
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
+
+ for(let i = 1; i < 10; i++) {
+ await collection.mintToken(minter, {Ethereum: owner.eth});
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq(i.toString());
+ }
+ });
+
+ itEth('Check ownerOfCross()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {});
+ let owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
+ const {tokenId} = await collection.mintToken(minter, {Ethereum: owner.eth});
+
+ for(let i = 1n; i < 10n; i++) {
+ const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth});
+ expect(ownerCross.eth).to.be.eq(owner.eth);
+ expect(ownerCross.sub).to.be.eq(owner.sub);
+
+ const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ await collectionEvm.methods.transferCross(newOwner, tokenId).send({from: owner.eth});
+ owner = newOwner;
+ }
+ });
+});
+
+describe('NFT: Fees', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
+
+ const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
+
+ const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+
+ itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
+
+ const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
+
+ await contract.methods.approve(spender, tokenId).send({from: owner});
+
+ const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+
+ itEth('Can perform transferFromCross()', async ({helper}) => {
+ const collectionMinter = alice;
+ const owner = bob;
+ const receiver = charlie;
+ const collection = await helper.nft.mintCollection(collectionMinter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(collectionMinter, {Substrate: owner.address});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft');
+
+ await token.approve(owner, {Ethereum: spender});
+
+ {
+ const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+ const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: helper.address.substrateToEth(receiver.address),
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
+ });
+
+ itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
+
+ const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
+
+ const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+});
+
+describe('NFT: Substrate calls', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([20n], donor);
+ });
+ });
+
+ itEth('Events emitted for mint()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ const {tokenId} = await collection.mintToken(alice);
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Transfer');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.tokenId).to.be.equal(tokenId.toString());
+ });
+
+ itEth('Events emitted for burn()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await token.burn(alice);
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Transfer');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
+ });
+
+ itEth('Events emitted for approve()', async ({helper}) => {
+ const receiver = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await token.approve(alice, {Ethereum: receiver});
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Approval');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.approved).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
+ });
+
+ itEth('Events emitted for transferFrom()', async ({helper}) => {
+ const [bob] = await helper.arrange.createAccounts([10n], donor);
+ const receiver = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice);
+ await token.approve(alice, {Substrate: bob.address});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver});
+
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
+ });
+
+ itEth('Events emitted for transfer()', async ({helper}) => {
+ const receiver = helper.eth.createAccount();
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice);
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await token.transfer(alice, {Ethereum: receiver});
+
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
+ });
+});
+
+describe('Common metadata', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([20n], donor);
+ });
+ });
+
+ itEth('Returns collection name', async ({helper}) => {
+ const caller = helper.eth.createAccount();
+ const tokenPropertyPermissions = [{
+ key: 'URI',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: false,
+ },
+ }];
+ const collection = await helper.nft.mintCollection(
+ alice,
+ {
+ name: 'oh River',
+ tokenPrefix: 'CHANGE',
+ properties: [{key: 'ERC721Metadata', value: '1'}],
+ tokenPropertyPermissions,
+ },
+ );
+
+ const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
+ const name = await contract.methods.name().call();
+ expect(name).to.equal('oh River');
+ });
+
+ itEth('Returns symbol name', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const tokenPropertyPermissions = [{
+ key: 'URI',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: false,
+ },
+ }];
+ const collection = await helper.nft.mintCollection(
+ alice,
+ {
+ name: 'oh River',
+ tokenPrefix: 'CHANGE',
+ properties: [{key: 'ERC721Metadata', value: '1'}],
+ tokenPropertyPermissions,
+ },
+ );
+
+ const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
+ const symbol = await contract.methods.symbol().call();
+ expect(symbol).to.equal('CHANGE');
+ });
+});
+
+describe('Negative tests', () => {
+ let donor: IKeyringPair;
+ let minter: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itEth('[negative] Cant perform burn without approval', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft');
+
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
+
+ await contract.methods.setApprovalForAll(spender, true).send({from: owner});
+ await contract.methods.setApprovalForAll(spender, false).send({from: owner});
+
+ await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
+ });
+
+ itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const receiver = alice;
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft');
+
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+
+ await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
+
+ await contract.methods.setApprovalForAll(spender, true).send({from: owner});
+ await contract.methods.setApprovalForAll(spender, false).send({from: owner});
+
+ await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
+ });
+});
js-packages/tests/eth/payable.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/payable.test.ts
@@ -0,0 +1,273 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {makeNames} from '../util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+describe('EVM payable contracts', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Evm contract can receive wei from eth account', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+
+ const web3 = helper.getWeb3();
+
+ await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', gas: helper.eth.DEFAULT_GAS});
+
+ expect(await contract.methods.getCollected().call()).to.be.equal('10000');
+ });
+
+ itEth('Evm contract can receive wei from substrate account', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([40n], donor);
+
+ const weiCount = '10000';
+
+ // Transaction fee/value will be payed from subToEth(sender) evm balance,
+ // which is backed by evmToAddress(subToEth(sender)) substrate balance
+ await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address), 5n);
+
+
+ await helper.eth.sendEVM(alice, contract.options.address, contract.methods.giveMoney().encodeABI(), weiCount);
+
+ expect(await contract.methods.getCollected().call()).to.be.equal(weiCount);
+ });
+
+ // We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible
+ itEth('Wei sent directly to backing storage of evm contract balance is unaccounted', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+
+ const weiCount = 10_000n;
+
+ await helper.eth.transferBalanceFromSubstrate(alice, contract.options.address, weiCount, false);
+
+ expect(await contract.methods.getUnaccounted().call()).to.be.equal(weiCount.toString());
+ });
+
+ itEth('Balance can be retrieved from evm contract', async({helper}) => {
+ const FEE_BALANCE = 10n * helper.balance.getOneTokenNominal();
+ const CONTRACT_BALANCE = 1n * helper.balance.getOneTokenNominal();
+
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([20n], donor);
+
+ const web3 = helper.getWeb3();
+
+ await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
+
+ const [receiver] = await helper.arrange.createAccounts([0n], donor);
+
+ // First receive balance on eth balance of bob
+ {
+ const ethReceiver = helper.address.substrateToEth(receiver.address);
+ expect(await web3.eth.getBalance(ethReceiver)).to.be.equal('0');
+ await contract.methods.withdraw(ethReceiver).send({from: deployer});
+ expect(await web3.eth.getBalance(ethReceiver)).to.be.equal(CONTRACT_BALANCE.toString());
+ }
+
+ // Some balance is required to pay fee for evm.withdraw call
+ await helper.balance.transferToSubstrate(alice, receiver.address, FEE_BALANCE);
+ // await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString());
+
+ // Withdraw balance from eth to substrate
+ {
+ const initialReceiverBalance = await helper.balance.getSubstrate(receiver.address);
+ await helper.executeExtrinsic(receiver, 'api.tx.evm.withdraw', [helper.address.substrateToEth(receiver.address), CONTRACT_BALANCE.toString()], true);
+ const finalReceiverBalance = await helper.balance.getSubstrate(receiver.address);
+
+ expect(finalReceiverBalance > initialReceiverBalance).to.be.true;
+ }
+ });
+});
+
+describe('EVM transaction fees', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Fee is withdrawn from the user', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployFlipper(deployer);
+
+ const initialCallerBalance = await helper.balance.getEthereum(caller);
+ await contract.methods.flip().send({from: caller});
+ const finalCallerBalance = await helper.balance.getEthereum(caller);
+ expect(finalCallerBalance < initialCallerBalance).to.be.true;
+ });
+
+ itEth('Fee for nested calls is withdrawn from the user', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const contract = await deployProxyContract(helper, deployer);
+
+ const initialCallerBalance = await helper.balance.getEthereum(caller);
+ const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
+ await contract.methods.flip().send({from: caller});
+ const finalCallerBalance = await helper.balance.getEthereum(caller);
+ const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
+ expect(finalCallerBalance < initialCallerBalance).to.be.true;
+ expect(finalContractBalance == initialContractBalance).to.be.true;
+ });
+
+ itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
+
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const contract = await deployProxyContract(helper, deployer);
+
+ const collectionAddress = (await contract.methods.createNFTCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection;
+ const initialCallerBalance = await helper.balance.getEthereum(caller);
+ const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
+ await contract.methods.mintNftToken(collectionAddress).send({from: caller});
+ const finalCallerBalance = await helper.balance.getEthereum(caller);
+ const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
+ expect(finalCallerBalance < initialCallerBalance).to.be.true;
+ expect(finalContractBalance == initialContractBalance).to.be.true;
+ });
+
+ itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const contract = await deployProxyContract(helper, deployer);
+
+ const initialCallerBalance = await helper.balance.getEthereum(caller);
+ const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
+ await contract.methods.createNFTCollection().send({from: caller, value: Number(CONTRACT_BALANCE)});
+ const finalCallerBalance = await helper.balance.getEthereum(caller);
+ const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
+ expect(finalCallerBalance < initialCallerBalance).to.be.true;
+ expect(finalContractBalance == initialContractBalance).to.be.true;
+ });
+
+ itEth('Negative test: call createNFTCollection with wrong fee', async({helper}) => {
+ const SMALL_FEE = 1n * helper.balance.getOneTokenNominal();
+ const BIG_FEE = 3n * helper.balance.getOneTokenNominal();
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(caller);
+
+ await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+
+ itEth('Negative test: call createRFTCollection with wrong fee', async({helper}) => {
+ const SMALL_FEE = 1n * helper.balance.getOneTokenNominal();
+ const BIG_FEE = 3n * helper.balance.getOneTokenNominal();
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collectionHelper = await helper.ethNativeContract.collectionHelpers(caller);
+
+ await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+ });
+
+ itEth('Get collection creation fee', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ expect(await helper.eth.getCollectionCreationFee(deployer)).to.be.equal(String(2n * helper.balance.getOneTokenNominal()));
+ });
+
+ async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
+ return await helper.ethContract.deployByCode(
+ deployer,
+ 'ProxyContract',
+ `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ import {CollectionHelpers} from "../api/CollectionHelpers.sol";
+ import {UniqueNFT} from "../api/UniqueNFT.sol";
+
+ error Value(uint256 value);
+
+ contract ProxyContract {
+ bool value = false;
+ address innerContract;
+
+ event CollectionCreated(address collection);
+ event TokenMinted(uint256 tokenId);
+
+ receive() external payable {}
+
+ constructor() {
+ innerContract = address(new InnerContract());
+ }
+
+ function flip() public {
+ value = !value;
+ InnerContract(innerContract).flip();
+ }
+
+ function createNFTCollection() external payable {
+ address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
+ address nftCollection = CollectionHelpers(collectionHelpers).createNFTCollection{value: msg.value}("A", "B", "C");
+ emit CollectionCreated(nftCollection);
+ }
+
+ function mintNftToken(address collectionAddress) external {
+ UniqueNFT collection = UniqueNFT(collectionAddress);
+ uint256 tokenId = collection.mint(msg.sender);
+ emit TokenMinted(tokenId);
+ }
+
+ function getValue() external view returns (bool) {
+ return InnerContract(innerContract).getValue();
+ }
+ }
+
+ contract InnerContract {
+ bool value = false;
+ function flip() external {
+ value = !value;
+ }
+ function getValue() external view returns (bool) {
+ return value;
+ }
+ }
+ `,
+ [
+ {
+ solPath: 'api/CollectionHelpers.sol',
+ fsPath: `${dirname}/api/CollectionHelpers.sol`,
+ },
+ {
+ solPath: 'api/UniqueNFT.sol',
+ fsPath: `${dirname}/api/UniqueNFT.sol`,
+ },
+ ],
+ );
+ }
+});
js-packages/tests/eth/precompile.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/precompile.test.ts
@@ -0,0 +1,112 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+
+describe('Precompiles', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('ecrecover is supported', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ecrecoverCompiledСontract = await helper.ethContract.compile(
+ 'ECRECOVER',
+ `
+ // SPDX-License-Identifier: MIT
+ pragma solidity ^0.8.17;
+
+ contract ECRECOVER{
+ address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd;
+ bytes32 msgHash1 = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50;
+ bytes32 msgHash2 = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d51;
+ uint8 v = 0x1b;
+ bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef;
+ bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4;
+
+
+ function verifyValid() public view returns(bool) {
+ // Use ECRECOVER to verify address
+ return ecrecover(msgHash1, v, r, s) == (addressTest);
+ }
+
+ function verifyInvalid() public view returns(bool) {
+ // Use ECRECOVER to verify address
+ return ecrecover(msgHash2, v, r, s) == (addressTest);
+ }
+ }
+ `,
+ );
+
+ const ecrecoverСontract = await helper.ethContract.deployByAbi(owner, ecrecoverCompiledСontract.abi, ecrecoverCompiledСontract.object);
+ expect(await ecrecoverСontract.methods.verifyValid().call({from: owner})).to.be.true;
+ expect(await ecrecoverСontract.methods.verifyInvalid().call({from: owner})).to.be.false;
+ });
+
+ itEth('sr25519 is supported', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sr25519CompiledСontract = await helper.ethContract.compile(
+ 'SR25519Contract',
+ `
+ // SPDX-License-Identifier: MIT
+ pragma solidity ^0.8.17;
+
+ /**
+ * @title SR25519 signature interface.
+ */
+ interface SR25519 {
+ /**
+ * @dev Verify signed message using SR25519 crypto.
+ * @return A boolean confirming whether the public key is signer for the message.
+ */
+ function verify(
+ bytes32 public_key,
+ bytes calldata signature,
+ bytes calldata message
+ ) external view returns (bool);
+ }
+
+ contract SR25519Contract{
+ SR25519 public constant sr25519 = SR25519(0x0000000000000000000000000000000000005002);
+
+ bytes32 public_key = 0x96b2f9237ed0890fbeed891ebb81b91ac0d5d5b6e3afcdbc95df1b68d9f14036;
+ bytes signature = hex"4a5d733d7c568f2e88abf0467fd497f87c1be3e940ed897efdf9da72eaad394ef9918cb574ee99c54485775b17a0deaf46ff7a1f10346cea39fff0e4ede97689";
+ bytes message1 = hex"7372323535313920697320737570706f72746564";
+ bytes message2 = hex"7372323535313920697320737570706f7274656401";
+
+
+ function verifyValid() public view returns(bool) {
+ return sr25519.verify(public_key, signature, message1);
+ }
+
+ function verifyInvalid() public view returns(bool) {
+ return sr25519.verify(public_key, signature, message2);
+ }
+ }
+ `,
+ );
+
+ const sr25519Сontract = await helper.ethContract.deployByAbi(owner, sr25519CompiledСontract.abi, sr25519CompiledСontract.object);
+ expect(await sr25519Сontract.methods.verifyValid().call({from: owner})).to.be.true;
+ expect(await sr25519Сontract.methods.verifyInvalid().call({from: owner})).to.be.false;
+ });
+});
js-packages/tests/eth/proxy/UniqueFungibleProxy.abidiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/UniqueFungibleProxy.abi
@@ -0,0 +1 @@
+[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"interfaceId","type":"uint32"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/tests/eth/proxy/UniqueFungibleProxy.bindiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/UniqueFungibleProxy.bin
@@ -0,0 +1 @@
+608060405234801561001057600080fd5b5060405161098038038061098083398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b6108ed806100936000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806370a082311161006657806370a082311461012757806395d89b411461013a578063a9059cbb14610142578063dd62ed3e14610155578063f4f4b5001461016857600080fd5b806306fdde03146100a3578063095ea7b3146100c157806318160ddd146100e457806323b872dd146100fa578063313ce5671461010d575b600080fd5b6100ab61017b565b6040516100b8919061083e565b60405180910390f35b6100d46100cf3660046106e3565b610200565b60405190151581526020016100b8565b6100ec61028f565b6040519081526020016100b8565b6100d46101083660046106a7565b610316565b6101156103ad565b60405160ff90911681526020016100b8565b6100ec610135366004610659565b610434565b6100ab6104b8565b6100d46101503660046106e3565b6104fc565b6100ec610163366004610674565b610536565b6100d46101763660046107f5565b6105bc565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b1580156101bf57600080fd5b505afa1580156101d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101fb919081019061072f565b905090565b6000805460405163095ea7b360e01b81526001600160a01b038581166004830152602482018590529091169063095ea7b3906044015b602060405180830381600087803b15801561025057600080fd5b505af1158015610264573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610288919061070d565b9392505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156102de57600080fd5b505afa1580156102f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101fb91906107dc565b600080546040516323b872dd60e01b81526001600160a01b038681166004830152858116602483015260448201859052909116906323b872dd90606401602060405180830381600087803b15801561036d57600080fd5b505af1158015610381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a5919061070d565b949350505050565b60008060009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156103fc57600080fd5b505afa158015610410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101fb919061081b565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a082319060240160206040518083038186803b15801561047a57600080fd5b505afa15801561048e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b291906107dc565b92915050565b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b1580156101bf57600080fd5b6000805460405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529091169063a9059cbb90604401610236565b60008054604051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301529091169063dd62ed3e9060440160206040518083038186803b15801561058457600080fd5b505afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028891906107dc565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b15801561060557600080fd5b505afa158015610619573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b2919061070d565b80356001600160a01b038116811461065457600080fd5b919050565b60006020828403121561066b57600080fd5b6102888261063d565b6000806040838503121561068757600080fd5b6106908361063d565b915061069e6020840161063d565b90509250929050565b6000806000606084860312156106bc57600080fd5b6106c58461063d565b92506106d36020850161063d565b9150604084013590509250925092565b600080604083850312156106f657600080fd5b6106ff8361063d565b946020939093013593505050565b60006020828403121561071f57600080fd5b8151801515811461028857600080fd5b60006020828403121561074157600080fd5b815167ffffffffffffffff8082111561075957600080fd5b818401915084601f83011261076d57600080fd5b81518181111561077f5761077f6108a1565b604051601f8201601f19908116603f011681019083821181831017156107a7576107a76108a1565b816040528281528760208487010111156107c057600080fd5b6107d1836020830160208801610871565b979650505050505050565b6000602082840312156107ee57600080fd5b5051919050565b60006020828403121561080757600080fd5b813563ffffffff8116811461028857600080fd5b60006020828403121561082d57600080fd5b815160ff8116811461028857600080fd5b602081526000825180602084015261085d816040850160208701610871565b601f01601f19169190910160400192915050565b60005b8381101561088c578181015183820152602001610874565b8381111561089b576000848401525b50505050565b634e487b7160e01b600052604160045260246000fdfea2646970667358221220c05e4cb7ab439b86c0b6ac8a84eec6a230b592fa63d1ab2e3a7f1474c27338f364736f6c63430008070033
\ No newline at end of file
js-packages/tests/eth/proxy/UniqueFungibleProxy.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/UniqueFungibleProxy.sol
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: OTHER
+
+pragma solidity >=0.8.0 <0.9.0;
+
+import "../api/UniqueFungible.sol";
+
+contract UniqueFungibleProxy is UniqueFungible {
+ UniqueFungible proxied;
+
+ constructor(address _proxied) UniqueFungible() {
+ proxied = UniqueFungible(_proxied);
+ }
+
+ function name() external view override returns (string memory) {
+ return proxied.name();
+ }
+
+ function symbol() external view override returns (string memory) {
+ return proxied.symbol();
+ }
+
+ function totalSupply() external view override returns (uint256) {
+ return proxied.totalSupply();
+ }
+
+ function supportsInterface(uint32 interfaceId)
+ external
+ view
+ override
+ returns (bool)
+ {
+ return proxied.supportsInterface(interfaceId);
+ }
+
+ function decimals() external view override returns (uint8) {
+ return proxied.decimals();
+ }
+
+ function balanceOf(address owner) external view override returns (uint256) {
+ return proxied.balanceOf(owner);
+ }
+
+ function transfer(address to, uint256 amount)
+ external
+ override
+ returns (bool)
+ {
+ return proxied.transfer(to, amount);
+ }
+
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) external override returns (bool) {
+ return proxied.transferFrom(from, to, amount);
+ }
+
+ function approve(address spender, uint256 amount)
+ external
+ override
+ returns (bool)
+ {
+ return proxied.approve(spender, amount);
+ }
+
+ function allowance(address owner, address spender)
+ external
+ view
+ override
+ returns (uint256)
+ {
+ return proxied.allowance(owner, spender);
+ }
+}
js-packages/tests/eth/proxy/UniqueNFTProxy.abidiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/UniqueNFTProxy.abi
@@ -0,0 +1 @@
+[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"}],"name":"deleteProperty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"mintBulk","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256","name":"field_0","type":"uint256"},{"internalType":"string","name":"field_1","type":"string"}],"internalType":"struct Tuple0[]","name":"tokens","type":"tuple[]"}],"name":"mintBulkWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setProperty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/tests/eth/proxy/UniqueNFTProxy.bindiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/UniqueNFTProxy.bin
@@ -0,0 +1 @@
+608060405234801561001057600080fd5b506040516116bb3803806116bb83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b611628806100936000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80634f6ccce7116100f957806379cc679011610097578063a22cb46511610071578063a22cb46514610399578063a9059cbb146103ac578063c87b56dd146103bf578063e985e9c5146103d257600080fd5b806379cc6790146103765780637d64bcb41461038957806395d89b411461039157600080fd5b806362d9491f116100d357806362d9491f146103355780636352211e1461034857806370a082311461035b57806375794a3c1461036e57600080fd5b80634f6ccce7146102fc57806350bb4e7f1461030f57806360a116721461032257600080fd5b80632f745c591161016657806340c10f191161014057806340c10f19146102b057806342842e0e146102c357806342966c68146102d657806344a9945e146102e957600080fd5b80632f745c5914610277578063342419141461028a578063365430061461029d57600080fd5b8063081812fc116101a2578063081812fc1461020e578063095ea7b31461023957806318160ddd1461024e57806323b872dd1461026457600080fd5b806301ffc9a7146101c957806305d2035b146101f157806306fdde03146101f9575b600080fd5b6101dc6101d7366004610dca565b6103e5565b60405190151581526020015b60405180910390f35b6101dc610462565b6102016104df565b6040516101e89190610e4c565b61022161021c366004610e5f565b610550565b6040516001600160a01b0390911681526020016101e8565b61024c610247366004610e90565b6105bf565b005b61025661062a565b6040519081526020016101e8565b61024c610272366004610ebc565b6106a2565b610256610285366004610e90565b610716565b61024c610298366004610ff3565b610793565b6101dc6102ab36600461104c565b6107f8565b6101dc6102be366004610e90565b61086e565b61024c6102d1366004610ebc565b6108a8565b61024c6102e4366004610e5f565b6108e9565b6101dc6102f736600461114f565b61091a565b61025661030a366004610e5f565b61094d565b6101dc61031d3660046111f5565b6109bc565b61024c61033036600461124e565b610a3c565b61024c6103433660046112ce565b610aab565b610221610356366004610e5f565b610add565b610256610369366004611332565b610b0f565b610256610b42565b61024c610384366004610e90565b610b96565b6101dc610bcf565b610201610c25565b61024c6103a736600461135d565b610c6e565b61024c6103ba366004610e90565b610ca8565b6102016103cd366004610e5f565b610ce1565b6102216103e0366004611396565b610d53565b600080546040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b03909116906301ffc9a790602401602060405180830381865afa158015610438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c91906113c4565b92915050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da91906113c4565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde0392600480820193918290030181865afa158015610528573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104da91908101906113e1565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b602060405180830381865afa15801561059b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c9190611458565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b15801561060e57600080fd5b505af1158015610622573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da9190611475565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b1580156106f957600080fd5b505af115801561070d573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c5990604401602060405180830381865afa158015610768573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c9190611475565b9392505050565b600054604051630d09064560e21b81526001600160a01b03909116906334241914906107c3908490600401610e4c565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b5050505050565b60008054604051631b2a180360e11b81526001600160a01b039091169063365430069061082b908690869060040161148e565b6020604051808303816000875af115801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c91906113c4565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f199060440161082b565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e906064016106df565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c68906024016107c3565b60008054604051632254ca2f60e11b81526001600160a01b03909116906344a9945e9061082b9086908690600401611513565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c9190611475565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f906109f190879087908790600401611569565b6020604051808303816000875af1158015610a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3491906113c4565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a1167290610a72908790879087908790600401611590565b600060405180830381600087803b158015610a8c57600080fd5b505af1158015610aa0573d6000803e3d6000fd5b505050505b50505050565b6000546040516362d9491f60e01b81526001600160a01b03909116906362d9491f906105f490859085906004016115cd565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e9060240161057e565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a082319060240161097b565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b60005460405163079cc67960e41b81526001600160a01b03848116600483015260248201849052909116906379cc6790906044016105f4565b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b81526004016020604051808303816000875af11580156104b6573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b4192600480820193918290030181865afa158015610528573d6000803e3d6000fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb465906044016105f4565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016105f4565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610d2b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261045c91908101906113e1565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c590604401602060405180830381865afa158015610da6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c9190611458565b600060208284031215610ddc57600080fd5b81356001600160e01b03198116811461078c57600080fd5b60005b83811015610e0f578181015183820152602001610df7565b83811115610aa55750506000910152565b60008151808452610e38816020860160208601610df4565b601f01601f19169290920160200192915050565b60208152600061078c6020830184610e20565b600060208284031215610e7157600080fd5b5035919050565b6001600160a01b0381168114610e8d57600080fd5b50565b60008060408385031215610ea357600080fd5b8235610eae81610e78565b946020939093013593505050565b600080600060608486031215610ed157600080fd5b8335610edc81610e78565b92506020840135610eec81610e78565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610f3657610f36610efd565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610f6557610f65610efd565b604052919050565b600067ffffffffffffffff821115610f8757610f87610efd565b50601f01601f191660200190565b6000610fa8610fa384610f6d565b610f3c565b9050828152838383011115610fbc57600080fd5b828260208301376000602084830101529392505050565b600082601f830112610fe457600080fd5b61078c83833560208501610f95565b60006020828403121561100557600080fd5b813567ffffffffffffffff81111561101c57600080fd5b610a3484828501610fd3565b600067ffffffffffffffff82111561104257611042610efd565b5060051b60200190565b600080604080848603121561106057600080fd5b833561106b81610e78565b925060208481013567ffffffffffffffff8082111561108957600080fd5b818701915087601f83011261109d57600080fd5b81356110ab610fa382611028565b81815260059190911b8301840190848101908a8311156110ca57600080fd5b8585015b8381101561113d578035858111156110e65760008081fd5b8601808d03601f19018913156110fc5760008081fd5b611104610f13565b888201358152898201358781111561111c5760008081fd5b61112a8f8b83860101610fd3565b828b0152508452509186019186016110ce565b50809750505050505050509250929050565b6000806040838503121561116257600080fd5b823561116d81610e78565b915060208381013567ffffffffffffffff81111561118a57600080fd5b8401601f8101861361119b57600080fd5b80356111a9610fa382611028565b81815260059190911b820183019083810190888311156111c857600080fd5b928401925b828410156111e6578335825292840192908401906111cd565b80955050505050509250929050565b60008060006060848603121561120a57600080fd5b833561121581610e78565b925060208401359150604084013567ffffffffffffffff81111561123857600080fd5b61124486828701610fd3565b9150509250925092565b6000806000806080858703121561126457600080fd5b843561126f81610e78565b9350602085013561127f81610e78565b925060408501359150606085013567ffffffffffffffff8111156112a257600080fd5b8501601f810187136112b357600080fd5b6112c287823560208401610f95565b91505092959194509250565b600080604083850312156112e157600080fd5b823567ffffffffffffffff808211156112f957600080fd5b61130586838701610fd3565b9350602085013591508082111561131b57600080fd5b5061132885828601610fd3565b9150509250929050565b60006020828403121561134457600080fd5b813561078c81610e78565b8015158114610e8d57600080fd5b6000806040838503121561137057600080fd5b823561137b81610e78565b9150602083013561138b8161134f565b809150509250929050565b600080604083850312156113a957600080fd5b82356113b481610e78565b9150602083013561138b81610e78565b6000602082840312156113d657600080fd5b815161078c8161134f565b6000602082840312156113f357600080fd5b815167ffffffffffffffff81111561140a57600080fd5b8201601f8101841361141b57600080fd5b8051611429610fa382610f6d565b81815285602083850101111561143e57600080fd5b61144f826020830160208601610df4565b95945050505050565b60006020828403121561146a57600080fd5b815161078c81610e78565b60006020828403121561148757600080fd5b5051919050565b6001600160a01b0383168152604060208083018290528351828401819052600092916060600583901b860181019290860190878301865b8281101561150457888603605f190184528151805187528501518587018890526114f188880182610e20565b96505092840192908401906001016114c5565b50939998505050505050505050565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b8181101561155c57845183529383019391830191600101611540565b5090979650505050505050565b60018060a01b038416815282602082015260606040820152600061144f6060830184610e20565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906115c390830184610e20565b9695505050505050565b6040815260006115e06040830185610e20565b828103602084015261144f8185610e2056fea26469706673582212205bdf4275f4b714a1029ccfe77c0f9a0e20e121a932e1e5840cace97dfa886da964736f6c634300080d0033
\ No newline at end of file
js-packages/tests/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/UniqueNFTProxy.sol
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: OTHER
+
+pragma solidity >=0.8.0 <0.9.0;
+
+import "../api/UniqueNFT.sol";
+
+contract UniqueNFTProxy is UniqueNFT {
+ UniqueNFT proxied;
+
+ constructor(address _proxied) UniqueNFT() {
+ proxied = UniqueNFT(_proxied);
+ }
+
+ function name() external view override returns (string memory) {
+ return proxied.name();
+ }
+
+ function symbol() external view override returns (string memory) {
+ return proxied.symbol();
+ }
+
+ function totalSupply() external view override returns (uint256) {
+ return proxied.totalSupply();
+ }
+
+ function balanceOf(address owner) external view override returns (uint256) {
+ return proxied.balanceOf(owner);
+ }
+
+ function ownerOf(uint256 tokenId) external view override returns (address) {
+ return proxied.ownerOf(tokenId);
+ }
+
+ function safeTransferFromWithData(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) external override {
+ return proxied.safeTransferFromWithData(from, to, tokenId, data);
+ }
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external override {
+ return proxied.safeTransferFrom(from, to, tokenId);
+ }
+
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) external override {
+ return proxied.transferFrom(from, to, tokenId);
+ }
+
+ function approve(address approved, uint256 tokenId) external override {
+ return proxied.approve(approved, tokenId);
+ }
+
+ function setApprovalForAll(address operator, bool approved)
+ external
+ override
+ {
+ return proxied.setApprovalForAll(operator, approved);
+ }
+
+ function getApproved(uint256 tokenId)
+ external
+ view
+ override
+ returns (address)
+ {
+ return proxied.getApproved(tokenId);
+ }
+
+ function isApprovedForAll(address owner, address operator)
+ external
+ view
+ override
+ returns (address)
+ {
+ return proxied.isApprovedForAll(owner, operator);
+ }
+
+ function burn(uint256 tokenId) external override {
+ return proxied.burn(tokenId);
+ }
+
+ function tokenByIndex(uint256 index)
+ external
+ view
+ override
+ returns (uint256)
+ {
+ return proxied.tokenByIndex(index);
+ }
+
+ function tokenOfOwnerByIndex(address owner, uint256 index)
+ external
+ view
+ override
+ returns (uint256)
+ {
+ return proxied.tokenOfOwnerByIndex(owner, index);
+ }
+
+ function tokenURI(uint256 tokenId)
+ external
+ view
+ override
+ returns (string memory)
+ {
+ return proxied.tokenURI(tokenId);
+ }
+
+ function mintingFinished() external view override returns (bool) {
+ return proxied.mintingFinished();
+ }
+
+ function mint(address to)
+ external
+ override
+ returns (uint256)
+ {
+ return proxied.mint(to);
+ }
+
+ function mintWithTokenURI(
+ address to,
+ string memory tokenUri
+ ) external override returns (uint256) {
+ return proxied.mintWithTokenURI(to, tokenUri);
+ }
+
+ function finishMinting() external override returns (bool) {
+ return proxied.finishMinting();
+ }
+
+ function transfer(address to, uint256 tokenId) external override {
+ return proxied.transfer(to, tokenId);
+ }
+
+ function nextTokenId() external view override returns (uint256) {
+ return proxied.nextTokenId();
+ }
+
+ function burnFrom(address from, uint256 tokenId) external override {
+ return proxied.burnFrom(from, tokenId);
+ }
+
+ function supportsInterface(bytes4 interfaceId)
+ external
+ view
+ override
+ returns (bool)
+ {
+ return proxied.supportsInterface(interfaceId);
+ }
+
+ function mintBulk(address to, uint256[] memory tokenIds)
+ external
+ override
+ returns (bool)
+ {
+ return proxied.mintBulk(to, tokenIds);
+ }
+
+ function mintBulkWithTokenURI(address to, TokenUri[] memory tokens)
+ external
+ override
+ returns (bool)
+ {
+ return proxied.mintBulkWithTokenURI(to, tokens);
+ }
+
+ function setProperty(string memory key, string memory value) external override {
+ return proxied.setProperty(key, value);
+ }
+
+ function deleteProperty(string memory key) external override {
+ return proxied.deleteProperty(key);
+ }
+}
js-packages/tests/eth/proxy/fungibleProxy.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/fungibleProxy.test.ts
@@ -0,0 +1,207 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect} from 'chai';
+import {readFile} from 'fs/promises';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds} from '../util/index.js';
+import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {makeNames} from '../../util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+async function proxyWrap(helper: EthUniqueHelper, wrapped: any, donor: IKeyringPair) {
+ // Proxy owner has no special privilegies, we don't need to reuse them
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const web3 = helper.getWeb3();
+ const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${dirname}/UniqueFungibleProxy.abi`)).toString()), undefined, {
+ from: owner,
+ gas: helper.eth.DEFAULT_GAS,
+ });
+ const proxy = await proxyContract.deploy({data: (await readFile(`${dirname}/UniqueFungibleProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});
+ return proxy;
+}
+
+describe('Fungible (Via EVM proxy): Information getting', () => {
+ let alice: IKeyringPair;
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itEth('totalSupply', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ await collection.mint(alice, 200n, {Substrate: alice.address});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const totalSupply = await contract.methods.totalSupply().call();
+
+ expect(totalSupply).to.equal('200');
+ });
+
+ itEth('balanceOf', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ await collection.mint(alice, 200n, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const balance = await contract.methods.balanceOf(caller).call();
+
+ expect(balance).to.equal('200');
+ });
+});
+
+describe('Fungible (Via EVM proxy): Plain calls', () => {
+ let alice: IKeyringPair;
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itEth('Can perform approve()', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ await collection.mint(alice, 200n, {Ethereum: contract.options.address});
+
+ {
+ const result = await contract.methods.approve(spender, 100).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Approval',
+ args: {
+ owner: contract.options.address,
+ spender,
+ value: '100',
+ },
+ },
+ ]);
+ }
+
+ {
+ const allowance = await contract.methods.allowance(contract.options.address, spender).call();
+ expect(+allowance).to.equal(100);
+ }
+ });
+
+ itEth('Can perform transferFrom()', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ await collection.mint(alice, 200n, {Ethereum: owner});
+ const receiver = helper.eth.createAccount();
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+
+ await evmCollection.methods.approve(contract.options.address, 100).send({from: owner});
+
+ {
+ const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: owner,
+ to: receiver,
+ value: '49',
+ },
+ },
+ {
+ address,
+ event: 'Approval',
+ args: {
+ owner,
+ spender: contract.options.address,
+ value: '51',
+ },
+ },
+ ]);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(49);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(owner).call();
+ expect(+balance).to.equal(151);
+ }
+ });
+
+ itEth('Can perform transfer()', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ await collection.mint(alice, 200n, {Ethereum: contract.options.address});
+
+ {
+ const result = await contract.methods.transfer(receiver, 50).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: contract.options.address,
+ to: receiver,
+ value: '50',
+ },
+ },
+ ]);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(contract.options.address).call();
+ expect(+balance).to.equal(150);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(50);
+ }
+ });
+});
js-packages/tests/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxy/nonFungibleProxy.test.ts
@@ -0,0 +1,372 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {readFile} from 'fs/promises';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds, expect} from '../util/index.js';
+import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {makeNames} from '../../util/index.js';
+
+const {dirname} = makeNames(import.meta.url);
+
+
+async function proxyWrap(helper: EthUniqueHelper, wrapped: any, donor: IKeyringPair) {
+ // Proxy owner has no special privilegies, we don't need to reuse them
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const web3 = helper.getWeb3();
+ const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${dirname}/UniqueNFTProxy.abi`)).toString()), undefined, {
+ from: owner,
+ gas: helper.eth.DEFAULT_GAS,
+ });
+ const proxy = await proxyContract.deploy({data: (await readFile(`${dirname}/UniqueNFTProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});
+ return proxy;
+}
+
+describe('NFT (Via EVM proxy): Information getting', () => {
+ let alice: IKeyringPair;
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itEth('totalSupply', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ await collection.mintToken(alice, {Substrate: alice.address});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const totalSupply = await contract.methods.totalSupply().call();
+
+ expect(totalSupply).to.equal('1');
+ });
+
+ itEth('balanceOf', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ await collection.mintMultipleTokens(alice, [
+ {owner: {Ethereum: caller}},
+ {owner: {Ethereum: caller}},
+ {owner: {Ethereum: caller}},
+ ]);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const balance = await contract.methods.balanceOf(caller).call();
+
+ expect(balance).to.equal('3');
+ });
+
+ itEth('ownerOf', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const owner = await contract.methods.ownerOf(tokenId).call();
+
+ expect(owner).to.equal(caller);
+ });
+});
+
+describe('NFT (Via EVM proxy): Plain calls', () => {
+ let alice: IKeyringPair;
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ // Soft-deprecated
+ itEth('[eth] Can perform mint()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'A', 'A', '');
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const collectionEvmOwned = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller, true);
+ const contract = await proxyWrap(helper, collectionEvm, donor);
+ await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send();
+
+ {
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ const result = await contract.methods.mintWithTokenURI(receiver, nextTokenId, 'Test URI').send({from: caller});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+
+ const event = helper.eth.normalizeEvents(result.events)
+ .find(event => event.event === 'Transfer')!;
+ event.address = event.address.toLocaleLowerCase();
+
+ expect(event).to.be.deep.equal({
+ address: collectionAddress.toLocaleLowerCase(),
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: receiver,
+ tokenId,
+ },
+ });
+
+ expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+ }
+ });
+
+ itEth('[cross] Can perform mint()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'A', 'A', '');
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const collectionEvmOwned = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
+ const contract = await proxyWrap(helper, collectionEvm, donor);
+ const contractAddressCross = helper.ethCrossAccount.fromAddress(contract.options.address);
+ await collectionEvmOwned.methods.addCollectionAdminCross(contractAddressCross).send();
+
+ {
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ const result = await contract.methods.mintWithTokenURI(receiver, nextTokenId, 'Test URI').send({from: caller});
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+
+ const event = helper.eth.normalizeEvents(result.events)
+ .find(event => event.event === 'Transfer')!;
+ event.address = event.address.toLocaleLowerCase();
+
+ expect(event).to.be.deep.equal({
+ address: collectionAddress.toLocaleLowerCase(),
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: receiver,
+ tokenId,
+ },
+ });
+
+ expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+ }
+ });
+
+ //TODO: CORE-302 add eth methods
+ itEth.skip('Can perform mintBulk()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(donor, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
+
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ await collection.addAdmin(donor, {Ethereum: contract.options.address});
+
+ {
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const result = await contract.methods.mintBulkWithTokenURI(
+ receiver,
+ [
+ [nextTokenId, 'Test URI 0'],
+ [+nextTokenId + 1, 'Test URI 1'],
+ [+nextTokenId + 2, 'Test URI 2'],
+ ],
+ ).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: receiver,
+ tokenId: nextTokenId,
+ },
+ },
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: receiver,
+ tokenId: String(+nextTokenId + 1),
+ },
+ },
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: receiver,
+ tokenId: String(+nextTokenId + 2),
+ },
+ },
+ ]);
+
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
+ expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
+ expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
+ }
+ });
+
+ itEth('Can perform burn()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
+ await collection.addAdmin(alice, {Ethereum: contract.options.address});
+
+ {
+ const result = await contract.methods.burn(tokenId).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: contract.options.address,
+ to: '0x0000000000000000000000000000000000000000',
+ tokenId: tokenId.toString(),
+ },
+ },
+ ]);
+ }
+ });
+
+ itEth('Can perform approve()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
+
+ {
+ const result = await contract.methods.approve(spender, tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS});
+ const events = helper.eth.normalizeEvents(result.events);
+
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Approval',
+ args: {
+ owner: contract.options.address,
+ approved: spender,
+ tokenId: tokenId.toString(),
+ },
+ },
+ ]);
+ }
+ });
+
+ itEth('Can perform transferFrom()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const receiver = helper.eth.createAccount();
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
+
+ await evmCollection.methods.approve(contract.options.address, tokenId).send({from: owner});
+
+ {
+ const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: owner,
+ to: receiver,
+ tokenId: tokenId.toString(),
+ },
+ },
+ ]);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(1);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(contract.options.address).call();
+ expect(+balance).to.equal(0);
+ }
+ });
+
+ itEth('Can perform transfer()', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
+ const contract = await proxyWrap(helper, evmCollection, donor);
+ const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
+
+ {
+ const result = await contract.methods.transfer(receiver, tokenId).send({from: caller});
+ const events = helper.eth.normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: contract.options.address,
+ to: receiver,
+ tokenId: tokenId.toString(),
+ },
+ },
+ ]);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(contract.options.address).call();
+ expect(+balance).to.equal(0);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(1);
+ }
+ });
+});
js-packages/tests/eth/proxyContract.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/proxyContract.test.ts
@@ -0,0 +1,153 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+
+describe('EVM payable contracts', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Update proxy contract', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const proxyContract = await deployProxyContract(helper, deployer);
+
+ const realContractV1 = await deployRealContractV1(helper, deployer);
+ const realContractV1proxy = new helper.web3!.eth.Contract(realContractV1.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS});
+ await proxyContract.methods.updateVersion(realContractV1.options.address).send();
+
+ await realContractV1proxy.methods.flip().send();
+ await realContractV1proxy.methods.flip().send();
+ await realContractV1proxy.methods.flip().send();
+ const value1 = await realContractV1proxy.methods.getValue().call();
+ const flipCount1 = await realContractV1proxy.methods.getFlipCount().call();
+ expect(flipCount1).to.be.equal('3');
+ expect(value1).to.be.equal(true);
+
+ const realContractV2 = await deployRealContractV2(helper, deployer);
+ const realContractV2proxy = new helper.web3!.eth.Contract(realContractV2.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS});
+ await proxyContract.methods.updateVersion(realContractV2.options.address).send();
+
+ await realContractV2proxy.methods.flip().send();
+ await realContractV2proxy.methods.flip().send();
+ await realContractV2proxy.methods.setStep(5).send();
+ await realContractV2proxy.methods.increaseFlipCount().send();
+ const value2 = await realContractV2proxy.methods.getValue().call();
+ const flipCount2 = await realContractV2proxy.methods.getFlipCount().call();
+ expect(value2).to.be.equal(true);
+ expect(flipCount2).to.be.equal('6');
+ });
+
+ async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
+ return await helper.ethContract.deployByCode(deployer, 'ProxyContract', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract ProxyContract {
+ event NewEvent(uint data);
+ receive() external payable {}
+ bytes32 private constant implementationSlot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1);
+ constructor() {}
+ function updateVersion(address newContractAddress) external {
+ bytes32 slot = implementationSlot;
+ assembly {
+ sstore(slot, newContractAddress)
+ }
+ }
+ fallback() external {
+ bytes32 slot = implementationSlot;
+ assembly {
+ let ptr := mload(0x40)
+ let contractAddress := sload(slot)
+
+ calldatacopy(ptr, 0, calldatasize())
+
+ let result := delegatecall(gas(), contractAddress, ptr, calldatasize(), 0, 0)
+ let size := returndatasize()
+
+ returndatacopy(ptr, 0, size)
+
+ switch result
+ case 0 { revert(ptr, size) }
+ default { return(ptr, size) }
+ }
+ }
+ }
+
+ interface RealContract {
+ function flip() external;
+ function getValue() external view returns (bool);
+ function getFlipCount() external view returns (uint);
+ }`);
+ }
+
+ async function deployRealContractV1(helper: EthUniqueHelper, deployer: string) {
+ return await helper.ethContract.deployByCode(deployer, 'RealContractV1', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract RealContractV1 {
+ bool value = false;
+ uint flipCount = 0;
+ function flip() external {
+ value = !value;
+ flipCount++;
+ }
+ function getValue() external view returns (bool) {
+ return value;
+ }
+ function getFlipCount() external view returns (uint) {
+ return flipCount;
+ }
+ }`);
+ }
+
+ async function deployRealContractV2(helper: EthUniqueHelper, deployer: string) {
+ return await helper.ethContract.deployByCode(deployer, 'RealContractV2', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract RealContractV2 {
+ bool value = false;
+ uint flipCount = 10;
+ uint step = 1;
+ function flip() external {
+ value = !value;
+ flipCount--;
+ }
+ function setStep(uint value) external {
+ step = value;
+ }
+ function increaseFlipCount() external {
+ flipCount = flipCount + step;
+ }
+ function getValue() external view returns (bool) {
+ return value;
+ }
+ function getFlipCount() external view returns (uint) {
+ return flipCount;
+ }
+ }`);
+ }
+});
js-packages/tests/eth/reFungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/reFungible.test.ts
@@ -0,0 +1,1019 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import type {ITokenPropertyPermission} from '@unique/playgrounds/types.js';
+import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from './util/playgrounds/types.js';
+
+describe('Refungible: Plain calls', () => {
+ let donor: IKeyringPair;
+ let minter: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ [
+ 'substrate' as const,
+ 'ethereum' as const,
+ ].map(testCase => {
+ itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
+ const collectionAdmin = await helper.eth.createAccountWithBalance(donor);
+
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverSub = bob;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+
+ const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
+ const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {
+ tokenOwner: false,
+ collectionAdmin: true,
+ mutable: false}}));
+
+
+ const collection = await helper.rft.mintCollection(minter, {
+ tokenPrefix: 'ethp',
+ tokenPropertyPermissions: permissions,
+ });
+ await collection.addAdmin(minter, {Ethereum: collectionAdmin});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', collectionAdmin, true);
+ let expectedTokenId = await contract.methods.nextTokenId().call();
+ let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();
+ let tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal(expectedTokenId);
+
+ let event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+
+ expectedTokenId = await contract.methods.nextTokenId().call();
+ result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();
+ event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+
+ tokenId = result.events.Transfer.returnValues.tokenId;
+
+ expect(tokenId).to.be.equal(expectedTokenId);
+
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
+ .map(p => helper.ethProperty.property(p.key, p.value.toString())));
+
+ expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))
+ .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});
+ });
+ });
+
+ itEth.skip('Can perform mintBulk()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'MintBulky', '6', '6', '');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ {
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const result = await contract.methods.mintBulkWithTokenURI(
+ receiver,
+ [
+ [nextTokenId, 'Test URI 0'],
+ [+nextTokenId + 1, 'Test URI 1'],
+ [+nextTokenId + 2, 'Test URI 2'],
+ ],
+ ).send();
+
+ const events = result.events.Transfer;
+ for(let i = 0; i < 2; i++) {
+ const event = events[i];
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(String(+nextTokenId + i));
+ }
+
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
+ expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
+ expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
+ }
+ });
+
+ itEth('Can perform mintBulkCross() with multiple tokens', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const receiver = helper.eth.createAccount();
+ const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
+
+ const permissions = [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.TokenOwner, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true},
+ ];
+ const {collectionAddress} = await helper.eth.createCollection(
+ caller,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'rft',
+ adminList: [callerCross],
+ tokenPropertyPermissions: [
+ {key: 'key_0_0', permissions},
+ {key: 'key_1_0', permissions},
+ {key: 'key_1_1', permissions},
+ {key: 'key_2_0', permissions},
+ {key: 'key_2_1', permissions},
+ {key: 'key_2_2', permissions},
+ ],
+ },
+ ).send();
+
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const result = await contract.methods.mintBulkCross([
+ {
+ owners: [{
+ owner: receiverCross,
+ pieces: 1,
+ }],
+ properties: [
+ {key: 'key_0_0', value: Buffer.from('value_0_0')},
+ ],
+ },
+ {
+ owners: [{
+ owner: receiverCross,
+ pieces: 2,
+ }],
+ properties: [
+ {key: 'key_1_0', value: Buffer.from('value_1_0')},
+ {key: 'key_1_1', value: Buffer.from('value_1_1')},
+ ],
+ },
+ {
+ owners: [{
+ owner: receiverCross,
+ pieces: 1,
+ }],
+ properties: [
+ {key: 'key_2_0', value: Buffer.from('value_2_0')},
+ {key: 'key_2_1', value: Buffer.from('value_2_1')},
+ {key: 'key_2_2', value: Buffer.from('value_2_2')},
+ ],
+ },
+ ]).send({from: caller});
+ const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);
+ const bulkSize = 3;
+ for(let i = 0; i < bulkSize; i++) {
+ const event = events[i];
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);
+ }
+
+ const properties = [
+ await contract.methods.properties(+nextTokenId, []).call(),
+ await contract.methods.properties(+nextTokenId + 1, []).call(),
+ await contract.methods.properties(+nextTokenId + 2, []).call(),
+ ];
+ expect(properties).to.be.deep.equal([
+ [
+ ['key_0_0', helper.getWeb3().utils.toHex('value_0_0')],
+ ],
+ [
+ ['key_1_0', helper.getWeb3().utils.toHex('value_1_0')],
+ ['key_1_1', helper.getWeb3().utils.toHex('value_1_1')],
+ ],
+ [
+ ['key_2_0', helper.getWeb3().utils.toHex('value_2_0')],
+ ['key_2_1', helper.getWeb3().utils.toHex('value_2_1')],
+ ['key_2_2', helper.getWeb3().utils.toHex('value_2_2')],
+ ],
+ ]);
+ });
+
+ itEth('Can perform mintBulkCross() with multiple owners', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const receiver = helper.eth.createAccount();
+ const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
+ const receiver2 = helper.eth.createAccount();
+ const receiver2Cross = helper.ethCrossAccount.fromAddress(receiver2);
+
+ const permissions = [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.TokenOwner, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true},
+ ];
+ const {collectionAddress} = await helper.eth.createCollection(
+ caller,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'rft',
+ adminList: [callerCross],
+ tokenPropertyPermissions: [
+ {key: 'key_2_0', permissions},
+ {key: 'key_2_1', permissions},
+ {key: 'key_2_2', permissions},
+ ],
+ },
+ ).send();
+
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const result = await contract.methods.mintBulkCross([{
+ owners: [
+ {
+ owner: receiverCross,
+ pieces: 1,
+ },
+ {
+ owner: receiver2Cross,
+ pieces: 2,
+ },
+ ],
+ properties: [
+ {key: 'key_2_0', value: Buffer.from('value_2_0')},
+ {key: 'key_2_1', value: Buffer.from('value_2_1')},
+ {key: 'key_2_2', value: Buffer.from('value_2_2')},
+ ],
+ }]).send({from: caller});
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+ expect(event.returnValues.tokenId).to.equal(`${+nextTokenId}`);
+
+ const properties = [
+ await contract.methods.properties(+nextTokenId, []).call(),
+ ];
+ expect(properties).to.be.deep.equal([[
+ ['key_2_0', helper.getWeb3().utils.toHex('value_2_0')],
+ ['key_2_1', helper.getWeb3().utils.toHex('value_2_1')],
+ ['key_2_2', helper.getWeb3().utils.toHex('value_2_2')],
+ ]]);
+ });
+
+ itEth('Can perform setApprovalForAll()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = helper.eth.createAccount();
+
+ const collection = await helper.rft.mintCollection(minter, {});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
+ expect(approvedBefore).to.be.equal(false);
+
+ {
+ const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+
+ expect(result.events.ApprovalForAll).to.be.like({
+ address: collectionAddress,
+ event: 'ApprovalForAll',
+ returnValues: {
+ owner,
+ operator,
+ approved: true,
+ },
+ });
+
+ const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+ expect(approvedAfter).to.be.equal(true);
+ }
+
+ {
+ const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
+
+ expect(result.events.ApprovalForAll).to.be.like({
+ address: collectionAddress,
+ event: 'ApprovalForAll',
+ returnValues: {
+ owner,
+ operator,
+ approved: false,
+ },
+ });
+
+ const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+ expect(approvedAfter).to.be.equal(false);
+ }
+ });
+
+ itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ {
+ await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
+ const events = result.events.Transfer;
+
+ expect(events).to.be.like({
+ address,
+ event: 'Transfer',
+ returnValues: {
+ from: owner,
+ to: '0x0000000000000000000000000000000000000000',
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+ });
+
+ itEth('Can perform burn with approve and approvalForAll', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner, true);
+
+ {
+ await rftToken.methods.approve(operator, 15n).send({from: owner});
+ await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+ await rftToken.methods.burnFrom(owner, 10n).send({from: operator});
+ }
+ {
+ const allowance = await rftToken.methods.allowance(owner, operator).call();
+ expect(+allowance).to.be.equal(5);
+ }
+ {
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const operatorCross = helper.ethCrossAccount.fromAddress(operator);
+ const allowance = await rftToken.methods.allowanceCross(ownerCross, operatorCross).call();
+ expect(+allowance).to.equal(5);
+ }
+ });
+
+ itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const operator = await helper.eth.createAccountWithBalance(donor);
+ const receiver = charlie;
+
+ const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ {
+ await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+ const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: owner,
+ to: helper.address.substrateToEth(receiver.address),
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);
+ });
+
+ itEth('Can perform burn()', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ {
+ const result = await contract.methods.burn(tokenId).send();
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal(caller);
+ expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.tokenId).to.equal(tokenId.toString());
+ }
+ });
+
+ itEth('Can perform transferFrom()', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+
+ const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller);
+ await tokenContract.methods.repartition(15).send();
+
+ {
+ const tokenEvents: any = [];
+ tokenContract.events.allEvents((_: any, event: any) => {
+ tokenEvents.push(event);
+ });
+ const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
+ if(tokenEvents.length == 0) await helper.wait.newBlocks(1);
+
+ let event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal(caller);
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(tokenId.toString());
+
+ event = tokenEvents[0];
+ expect(event.address).to.equal(tokenAddress);
+ expect(event.returnValues.from).to.equal(caller);
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.value).to.equal('15');
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(1);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(caller).call();
+ expect(+balance).to.equal(0);
+ }
+ });
+
+ // Soft-deprecated
+ itEth('Can perform burnFrom()', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft', spender, true);
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+ const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+ await tokenContract.methods.repartition(15).send();
+ await tokenContract.methods.approve(spender, 15).send();
+
+ {
+ const result = await contract.methods.burnFrom(owner, token.tokenId).send();
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: owner,
+ to: '0x0000000000000000000000000000000000000000',
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await collection.getTokenBalance(token.tokenId, {Ethereum: owner})).to.be.eq(0n);
+ });
+
+ itEth('Can perform burnFromCross()', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = bob;
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, 100n, {Substrate: owner.address});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ await token.repartition(owner, 15n);
+ await token.approve(owner, {Ethereum: spender}, 15n);
+
+ {
+ const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+ const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: '0x0000000000000000000000000000000000000000',
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await collection.getTokenBalance(token.tokenId, {Substrate: owner.address})).to.be.eq(0n);
+ });
+
+ itEth('Can perform transferFromCross()', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = bob;
+ const spender = await helper.eth.createAccountWithBalance(donor);
+ const receiver = charlie;
+
+ const token = await collection.mintToken(minter, 100n, {Substrate: owner.address});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ await token.repartition(owner, 15n);
+ await token.approve(owner, {Ethereum: spender}, 15n);
+
+ {
+ const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+ const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});
+ const event = result.events.Transfer;
+ expect(event).to.be.like({
+ address: helper.ethAddress.fromCollectionId(collection.collectionId),
+ event: 'Transfer',
+ returnValues: {
+ from: helper.address.substrateToEth(owner.address),
+ to: helper.address.substrateToEth(receiver.address),
+ tokenId: token.tokenId.toString(),
+ },
+ });
+ }
+
+ expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);
+ });
+
+ itEth('Can perform transfer()', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ {
+ const result = await contract.methods.transfer(receiver, tokenId).send();
+
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal(caller);
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(tokenId.toString());
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(caller).call();
+ expect(+balance).to.equal(0);
+ }
+
+ {
+ const balance = await contract.methods.balanceOf(receiver).call();
+ expect(+balance).to.equal(1);
+ }
+ });
+
+ itEth('Can perform transferCross()', async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+ const receiverEth = await helper.eth.createAccountWithBalance(donor);
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
+
+ const collection = await helper.rft.mintCollection(minter, {});
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
+
+ const token = await collection.mintToken(minter, 50n, {Ethereum: sender});
+
+ {
+ // Can transferCross to ethereum address:
+ const result = await collectionEvm.methods.transferCross(receiverCrossEth, token.tokenId).send({from: sender});
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal(sender);
+ expect(event.returnValues.to).to.equal(receiverEth);
+ expect(event.returnValues.tokenId).to.equal(token.tokenId.toString());
+ // Sender's balance decreased:
+ const senderBalance = await collectionEvm.methods.balanceOf(sender).call();
+ expect(+senderBalance).to.equal(0);
+ expect(await token.getBalance({Ethereum: sender})).to.eq(0n);
+ // Receiver's balance increased:
+ const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+ expect(+receiverBalance).to.equal(1);
+ expect(await token.getBalance({Ethereum: receiverEth})).to.eq(50n);
+ }
+
+ {
+ // Can transferCross to substrate address:
+ const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, token.tokenId).send({from: receiverEth});
+ // Check events:
+ const event = substrateResult.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal(receiverEth);
+ expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
+ expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
+ // Sender's balance decreased:
+ const senderBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+ expect(+senderBalance).to.equal(0);
+ expect(await token.getBalance({Ethereum: receiverEth})).to.eq(0n);
+ // Receiver's balance increased:
+ const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
+ expect(receiverBalance).to.contain(token.tokenId);
+ expect(await token.getBalance({Substrate: minter.address})).to.eq(50n);
+ }
+ });
+
+ ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {
+ const sender = await helper.eth.createAccountWithBalance(donor);
+ const tokenOwner = await helper.eth.createAccountWithBalance(donor);
+ const receiverSub = minter;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
+
+ const collection = await helper.rft.mintCollection(minter, {});
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
+
+ await collection.mintToken(minter, 50n, {Ethereum: sender});
+ const nonSendersToken = await collection.mintToken(minter, 50n, {Ethereum: tokenOwner});
+
+ // Cannot transferCross someone else's token:
+ const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;
+ await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;
+ // Cannot transfer token if it does not exist:
+ await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;
+ }));
+
+ itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
+
+ await tokenContract.methods.repartition(2).send();
+ await tokenContract.methods.transfer(receiver, 1).send();
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await tokenContract.methods.transfer(receiver, 1).send();
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+ expect(event.returnValues.to).to.equal(receiver);
+ expect(event.returnValues.tokenId).to.equal(tokenId.toString());
+ });
+
+ itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
+
+ await tokenContract.methods.repartition(2).send();
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ await tokenContract.methods.transfer(receiver, 1).send();
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal(caller);
+ expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+ expect(event.returnValues.tokenId).to.equal(tokenId.toString());
+ });
+
+ itEth('Check balanceOfCross()', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {});
+ const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
+
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
+
+ for(let i = 1n; i < 10n; i++) {
+ await collection.mintToken(minter, 100n, {Ethereum: owner.eth});
+ expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq(i.toString());
+ }
+ });
+
+ itEth('Check ownerOfCross()', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {});
+ let owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
+ const {tokenId} = await collection.mintToken(minter, 100n,{Ethereum: owner.eth});
+
+ for(let i = 1n; i < 10n; i++) {
+ const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth});
+ expect(ownerCross.eth).to.be.eq(owner.eth);
+ expect(ownerCross.sub).to.be.eq(owner.sub);
+
+ const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ await collectionEvm.methods.transferCross(newOwner, tokenId).send({from: owner.eth});
+ owner = newOwner;
+ }
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner.eth, true);
+ const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ await tokenContract.methods.transferCross(newOwner, 50).send({from: owner.eth});
+ const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth});
+ expect(ownerCross.eth.toUpperCase()).to.be.eq('0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
+ expect(ownerCross.sub).to.be.eq('0');
+ });
+});
+
+describe('RFT: Fees', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ expect(cost > 0n);
+ });
+
+ itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ expect(cost > 0n);
+ });
+});
+
+describe('Common metadata', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([1000n], donor);
+ });
+ });
+
+ itEth('Returns collection name', async ({helper}) => {
+ const caller = helper.eth.createAccount();
+ const tokenPropertyPermissions = [{
+ key: 'URI',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: false,
+ },
+ }];
+ const collection = await helper.rft.mintCollection(
+ alice,
+ {
+ name: 'Leviathan',
+ tokenPrefix: '11',
+ properties: [{key: 'ERC721Metadata', value: '1'}],
+ tokenPropertyPermissions,
+ },
+ );
+
+ const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
+ const name = await contract.methods.name().call();
+ expect(name).to.equal('Leviathan');
+ });
+
+ itEth('Returns symbol name', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const tokenPropertyPermissions = [{
+ key: 'URI',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ tokenOwner: false,
+ },
+ }];
+ const {collectionId} = await helper.rft.mintCollection(
+ alice,
+ {
+ name: 'Leviathan',
+ tokenPrefix: '12',
+ properties: [{key: 'ERC721Metadata', value: '1'}],
+ tokenPropertyPermissions,
+ },
+ );
+
+ const contract = await helper.ethNativeContract.collectionById(collectionId, 'rft', caller);
+ const symbol = await contract.methods.symbol().call();
+ expect(symbol).to.equal('12');
+ });
+});
+
+describe('Negative tests', () => {
+ let donor: IKeyringPair;
+ let minter: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itEth('[negative] Cant perform burn without approval', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+
+ await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
+
+ await contract.methods.setApprovalForAll(spender, true).send({from: owner});
+ await contract.methods.setApprovalForAll(spender, false).send({from: owner});
+
+ await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
+ });
+
+ itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = alice;
+
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'rft');
+
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+
+ await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
+
+ await contract.methods.setApprovalForAll(spender, true).send({from: owner});
+ await contract.methods.setApprovalForAll(spender, false).send({from: owner});
+
+ await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
+ });
+
+ itEth('[negative] Can perform mintBulkCross() with multiple owners and multiple tokens', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const callerCross = helper.ethCrossAccount.fromAddress(caller);
+ const receiver = helper.eth.createAccount();
+ const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
+ const receiver2 = helper.eth.createAccount();
+ const receiver2Cross = helper.ethCrossAccount.fromAddress(receiver2);
+
+ const permissions = [
+ {code: TokenPermissionField.Mutable, value: true},
+ {code: TokenPermissionField.TokenOwner, value: true},
+ {code: TokenPermissionField.CollectionAdmin, value: true},
+ ];
+ const {collectionAddress} = await helper.eth.createCollection(
+ caller,
+ {
+ ...CREATE_COLLECTION_DATA_DEFAULTS,
+ name: 'A',
+ description: 'B',
+ tokenPrefix: 'C',
+ collectionMode: 'rft',
+ adminList: [callerCross],
+ tokenPropertyPermissions: [
+ {key: 'key_0_0', permissions},
+ {key: 'key_2_0', permissions},
+ {key: 'key_2_1', permissions},
+ {key: 'key_2_2', permissions},
+ ],
+ },
+ ).send();
+
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+ const nextTokenId = await contract.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ const createData = [
+ {
+ owners: [{
+ owner: receiverCross,
+ pieces: 1,
+ }],
+ properties: [
+ {key: 'key_0_0', value: Buffer.from('value_0_0')},
+ ],
+ },
+ {
+ owners: [
+ {
+ owner: receiverCross,
+ pieces: 1,
+ },
+ {
+ owner: receiver2Cross,
+ pieces: 2,
+ },
+ ],
+ properties: [
+ {key: 'key_2_0', value: Buffer.from('value_2_0')},
+ {key: 'key_2_1', value: Buffer.from('value_2_1')},
+ {key: 'key_2_2', value: Buffer.from('value_2_2')},
+ ],
+ },
+ ];
+
+ await expect(contract.methods.mintBulkCross(createData).call({from: caller})).to.be.rejectedWith('creation of multiple tokens supported only if they have single owner each');
+ });
+});
js-packages/tests/eth/reFungibleToken.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/reFungibleToken.test.ts
@@ -0,0 +1,677 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {Pallets, requirePalletsOrSkip} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
+
+// FIXME: Need erc721 for ReFubgible.
+describe('Check ERC721 token URI for ReFungible', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ async function setup(helper: EthUniqueHelper, baseUri: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ const result = await contract.methods.mint(receiver).send();
+
+ const event = result.events.Transfer;
+ const tokenId = event.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(receiver);
+
+ if(propertyKey && propertyValue) {
+ // Set URL or suffix
+
+ await contract.methods.setProperties(tokenId, [{key: propertyKey, value: Buffer.from(propertyValue)}]).send();
+ }
+
+ return {contract, nextTokenId: tokenId};
+ }
+
+ itEth('Empty tokenURI', async ({helper}) => {
+ const {contract, nextTokenId} = await setup(helper, '');
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
+ });
+
+ itEth('TokenURI from url', async ({helper}) => {
+ const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URI', 'Token URI');
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
+ });
+
+ itEth('TokenURI from baseURI', async ({helper}) => {
+ const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_');
+ });
+
+ itEth('TokenURI from baseURI + suffix', async ({helper}) => {
+ const suffix = '/some/suffix';
+ const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URISuffix', suffix);
+ expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
+ });
+});
+
+describe('Refungible: Plain calls', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([50n], donor);
+ });
+ });
+
+ itEth('Can perform approve()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ {
+ const result = await contract.methods.approve(spender, 100).send({from: owner});
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(spender);
+ expect(event.returnValues.value).to.be.equal('100');
+ }
+
+ {
+ const allowance = await contract.methods.allowance(owner, spender).call();
+ expect(+allowance).to.equal(100);
+ }
+ });
+
+ itEth('Can perform approveCross()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0];
+ const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);
+ const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub);
+
+
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ {
+ const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(spender);
+ expect(event.returnValues.value).to.be.equal('100');
+ }
+
+ {
+ const allowance = await contract.methods.allowance(owner, spender).call();
+ expect(+allowance).to.equal(100);
+ }
+
+
+ {
+ const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner});
+ const event = result.events.Approval;
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.owner).to.be.equal(owner);
+ expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address));
+ expect(event.returnValues.value).to.be.equal('100');
+ }
+
+ {
+ const allowance = await collection.getTokenApprovedPieces(tokenId, {Ethereum: owner}, {Substrate: spenderSub.address});
+ expect(allowance).to.equal(100n);
+ }
+
+ {
+ //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call()
+ }
+ });
+
+ itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {
+ const nonOwner = await helper.eth.createAccountWithBalance(donor);
+ const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
+ const token = await collection.mintToken(alice, 100n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+ const tokenEvm = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ await expect(tokenEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');
+ });
+
+ [
+ 'transferFrom',
+ 'transferFromCross',
+ ].map(testCase =>
+ itEth(`Can perform ${testCase}`, async ({helper}) => {
+ const isCross = testCase === 'transferFromCross';
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const [receiverSub] = await helper.arrange.createAccounts([1n], donor);
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ await contract.methods.approve(spender, 100).send({from: owner});
+
+ // 1. Can transfer from
+ // 1.1 Plain ethereum or cross address:
+ {
+ const result = await contract.methods[testCase](
+ isCross ? ownerCross : owner,
+ isCross ? receiverCrossEth : receiverEth,
+ 49,
+ ).send({from: spender});
+
+ // Check events:
+ const transferEvent = result.events.Transfer;
+ expect(transferEvent.address).to.be.equal(tokenAddress);
+ expect(transferEvent.returnValues.from).to.be.equal(owner);
+ expect(transferEvent.returnValues.to).to.be.equal(receiverEth);
+ expect(transferEvent.returnValues.value).to.be.equal('49');
+
+ const approvalEvent = result.events.Approval;
+ expect(approvalEvent.address).to.be.equal(tokenAddress);
+ expect(approvalEvent.returnValues.owner).to.be.equal(owner);
+ expect(approvalEvent.returnValues.spender).to.be.equal(spender);
+ expect(approvalEvent.returnValues.value).to.be.equal('51');
+
+ // Check balances:
+ const receiverBalance = await contract.methods.balanceOf(receiverEth).call();
+ const ownerBalance = await contract.methods.balanceOf(owner).call();
+
+ expect(+receiverBalance).to.equal(49);
+ expect(+ownerBalance).to.equal(151);
+ }
+
+ // 1.2 Cross substrate address:
+ if(testCase === 'transferFromCross') {
+ const result = await contract.methods.transferFromCross(ownerCross, receiverCrossSub, 51).send({from: spender});
+ // Check events:
+ const transferEvent = result.events.Transfer;
+ expect(transferEvent.address).to.be.equal(tokenAddress);
+ expect(transferEvent.returnValues.from).to.be.equal(owner);
+ expect(transferEvent.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));
+ expect(transferEvent.returnValues.value).to.be.equal('51');
+
+ const approvalEvent = result.events.Approval;
+ expect(approvalEvent.address).to.be.equal(tokenAddress);
+ expect(approvalEvent.returnValues.owner).to.be.equal(owner);
+ expect(approvalEvent.returnValues.spender).to.be.equal(spender);
+ expect(approvalEvent.returnValues.value).to.be.equal('0');
+
+ // Check balances:
+ const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});
+ const ownerBalance = await contract.methods.balanceOf(owner).call();
+ expect(receiverBalance).to.equal(51n);
+ expect(+ownerBalance).to.equal(100);
+ }
+ }));
+
+ [
+ 'transfer',
+ 'transferCross',
+ ].map(testCase =>
+ itEth(`Can perform ${testCase}()`, async ({helper}) => {
+ const isCross = testCase === 'transferCross';
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const [receiverSub] = await helper.arrange.createAccounts([1n], donor);
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ // 1. Can transfer to plain ethereum or cross-ethereum account:
+ {
+ const result = await contract.methods[testCase](isCross ? receiverCrossEth : receiverEth, 50).send({from: owner});
+ // Check events
+ const transferEvent = result.events.Transfer;
+ expect(transferEvent.address).to.be.equal(tokenAddress);
+ expect(transferEvent.returnValues.from).to.be.equal(owner);
+ expect(transferEvent.returnValues.to).to.be.equal(receiverEth);
+ expect(transferEvent.returnValues.value).to.be.equal('50');
+ // Check balances:
+ const ownerBalance = await contract.methods.balanceOf(owner).call();
+ const receiverBalance = await contract.methods.balanceOf(receiverEth).call();
+ expect(+ownerBalance).to.equal(150);
+ expect(+receiverBalance).to.equal(50);
+ }
+
+ // 2. Can transfer to cross-substrate account:
+ if(isCross) {
+ const result = await contract.methods.transferCross(receiverCrossSub, 50).send({from: owner});
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));
+ expect(event.returnValues.value).to.be.equal('50');
+ // Check balances:
+ const ownerBalance = await contract.methods.balanceOf(owner).call();
+ const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});
+ expect(+ownerBalance).to.equal(100);
+ expect(receiverBalance).to.equal(50n);
+ }
+ }));
+
+ [
+ 'transfer',
+ 'transferCross',
+ ].map(testCase =>
+ itEth(`Cannot ${testCase}() non-owned token`, async ({helper}) => {
+ const isCross = testCase === 'transferCross';
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const receiverEth = await helper.eth.createAccountWithBalance(donor);
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const collection = await helper.rft.mintCollection(alice);
+ const rftOwner = await collection.mintToken(alice, 10n, {Ethereum: owner});
+ const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiverEth});
+ const tokenIdNonExist = 9999999;
+
+ const tokenAddress1 = helper.ethAddress.fromTokenId(collection.collectionId, rftOwner.tokenId);
+ const tokenAddress2 = helper.ethAddress.fromTokenId(collection.collectionId, rftReceiver.tokenId);
+ const tokenAddressNonExist = helper.ethAddress.fromTokenId(collection.collectionId, tokenIdNonExist);
+ const tokenEvmOwner = await helper.ethNativeContract.rftToken(tokenAddress1, owner);
+ const tokenEvmReceiver = await helper.ethNativeContract.rftToken(tokenAddress2, owner);
+ const tokenEvmNonExist = await helper.ethNativeContract.rftToken(tokenAddressNonExist, owner);
+
+ // 1. Can transfer zero amount (EIP-20):
+ await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 0).send({from: owner});
+ // 2. Cannot transfer non-owned token:
+ await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected;
+ await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected;
+ // 3. Cannot transfer non-existing token:
+ await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected;
+ await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected;
+
+ // 4. Storage is not corrupted:
+ expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);
+ expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]);
+ expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]);
+
+ // 4.1 Tokens can be transferred:
+ await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 10).send({from: owner});
+ await tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 10).send({from: receiverEth});
+ expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]);
+ expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);
+ }));
+
+ itEth('Can perform repartition()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ await contract.methods.repartition(200).send({from: owner});
+ expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);
+ await contract.methods.transfer(receiver, 110).send({from: owner});
+ expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);
+ expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);
+
+ await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected; // Transaction is reverted
+
+ await contract.methods.transfer(receiver, 90).send({from: owner});
+ expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);
+ expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);
+
+ await contract.methods.repartition(150).send({from: receiver});
+ await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected; // Transaction is reverted
+ expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);
+ });
+
+ itEth('Can repartition with increased amount', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ const result = await contract.methods.repartition(200).send();
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(owner);
+ expect(event.returnValues.value).to.be.equal('100');
+ });
+
+ itEth('Can repartition with decreased amount', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ const result = await contract.methods.repartition(50).send();
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.from).to.be.equal(owner);
+ expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.value).to.be.equal('50');
+ });
+
+ itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+ const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller, true);
+
+ await tokenContract.methods.repartition(2).send();
+ await tokenContract.methods.transfer(receiver, 1).send();
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+ await tokenContract.methods.burnFrom(caller, 1).send();
+
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.tokenId).to.be.equal(tokenId);
+ });
+
+ itEth('Can perform burnFromCross()', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const ownerSub = (await helper.arrange.createAccounts([10n], donor))[0];
+ const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+
+ const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);
+ const ownerSubCross = helper.ethCrossAccount.fromKeyringPair(ownerSub);
+
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ {
+ await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});
+
+ await expect(contract.methods.burnFromCross(ownerCross, 50).send({from: spender})).to.be.fulfilled;
+ await expect(contract.methods.burnFromCross(ownerCross, 100).send({from: spender})).to.be.rejected;
+ expect(await contract.methods.balanceOf(owner).call({from: owner})).to.be.equal('150');
+ }
+ {
+ const {tokenId} = await collection.mintToken(alice, 200n, {Substrate: ownerSub.address});
+ await collection.approveToken(ownerSub, tokenId, {Ethereum: spender}, 100n);
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ await expect(contract.methods.burnFromCross(ownerSubCross, 50).send({from: spender})).to.be.fulfilled;
+ await expect(contract.methods.burnFromCross(ownerSubCross, 100).send({from: spender})).to.be.rejected;
+ expect(await collection.getTokenBalance(tokenId, {Substrate: ownerSub.address})).to.be.equal(150n);
+ }
+ });
+
+ itEth('Check balanceOfCross()', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const other = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner.eth});
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner.eth);
+
+ expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('200');
+ expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
+
+ await tokenContract.methods.repartition(100n).send({from: owner.eth});
+ expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100');
+ expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
+
+ await tokenContract.methods.transferCross(other, 50n).send({from: owner.eth});
+ expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('50');
+ expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('50');
+
+ await tokenContract.methods.transferCross(other, 50n).send({from: owner.eth});
+ expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
+ expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('100');
+
+ await tokenContract.methods.repartition(1000n).send({from: other.eth});
+ await tokenContract.methods.transferCross(owner, 500n).send({from: other.eth});
+ expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('500');
+ expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('500');
+ });
+});
+
+describe('Refungible: Fees', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([50n], donor);
+ });
+ });
+
+ itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = helper.eth.createAccount();
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+
+ itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const spender = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ await contract.methods.approve(spender, 100).send({from: owner});
+
+ const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+
+ itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.rft.mintCollection(alice);
+ const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
+ expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
+ });
+});
+
+describe('Refungible: Substrate calls', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([50n], donor);
+ });
+ });
+
+ itEth('Events emitted for approve()', async ({helper}) => {
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.rft.mintCollection(alice);
+ const token = await collection.mintToken(alice, 200n);
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress);
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ expect(await token.approve(alice, {Ethereum: receiver}, 100n)).to.be.true;
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Approval');
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.spender).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('100');
+ });
+
+ itEth('Events emitted for transferFrom()', async ({helper}) => {
+ const [bob] = await helper.arrange.createAccounts([10n], donor);
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.rft.mintCollection(alice);
+ const token = await collection.mintToken(alice, 200n);
+ await token.approve(alice, {Substrate: bob.address}, 100n);
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress);
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ expect(await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n)).to.be.true;
+ if(events.length == 0) await helper.wait.newBlocks(1);
+
+ let event = events[0];
+ expect(event.event).to.be.equal('Transfer');
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('51');
+
+ event = events[1];
+ expect(event.event).to.be.equal('Approval');
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
+ expect(event.returnValues.value).to.be.equal('49');
+ });
+
+ itEth('Events emitted for transfer()', async ({helper}) => {
+ const receiver = helper.eth.createAccount();
+ const collection = await helper.rft.mintCollection(alice);
+ const token = await collection.mintToken(alice, 200n);
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
+ const contract = await helper.ethNativeContract.rftToken(tokenAddress);
+
+ const events: any = [];
+ contract.events.allEvents((_: any, event: any) => {
+ events.push(event);
+ });
+
+ expect(await token.transfer(alice, {Ethereum: receiver}, 51n)).to.be.true;
+ if(events.length == 0) await helper.wait.newBlocks(1);
+ const event = events[0];
+
+ expect(event.event).to.be.equal('Transfer');
+ expect(event.address).to.be.equal(tokenAddress);
+ expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
+ expect(event.returnValues.to).to.be.equal(receiver);
+ expect(event.returnValues.value).to.be.equal('51');
+ });
+});
+
+describe('ERC 1633 implementation', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Default parent token address and id', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN');
+ const collectionContract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+ const result = await collectionContract.methods.mint(owner).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
+ const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+ expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress);
+ expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId);
+ });
+});
js-packages/tests/eth/scheduling.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/scheduling.test.ts
@@ -0,0 +1,64 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect} from 'chai';
+import {itSchedEth} from './util/index.js';
+import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {Pallets, usingPlaygrounds} from '../util/index.js';
+
+describe('Scheduing EVM smart contracts', () => {
+
+ before(async () => {
+ await usingPlaygrounds(async (helper) => {
+ await helper.testUtils.enable(Pallets.TestUtils);
+ });
+ });
+
+ itSchedEth.ifWithPallets('Successfully schedules and periodically executes an EVM contract', [Pallets.UniqueScheduler], async (scheduleKind, {helper, privateKey}) => {
+ const donor = await privateKey({url: import.meta.url});
+ const [alice] = await helper.arrange.createAccounts([1000n], donor);
+
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+
+ const deployer = await helper.eth.createAccountWithBalance(alice);
+ const flipper = await helper.eth.deployFlipper(deployer);
+
+ const initialValue = await flipper.methods.getValue().call();
+ await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address));
+
+ const waitForBlocks = 4;
+ const periodic = {
+ period: 2,
+ repetitions: 2,
+ };
+
+ await helper.scheduler.scheduleAfter<EthUniqueHelper>(waitForBlocks, {scheduledId, periodic})
+ .eth.sendEVM(
+ alice,
+ flipper.options.address,
+ flipper.methods.flip().encodeABI(),
+ '0',
+ );
+
+ expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
+
+ await helper.wait.newBlocks(waitForBlocks + 1);
+ expect(await flipper.methods.getValue().call()).to.be.not.equal(initialValue);
+
+ await helper.wait.newBlocks(periodic.period);
+ expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
+ });
+});
js-packages/tests/eth/sponsoring.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/sponsoring.test.ts
@@ -0,0 +1,97 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, expect, SponsoringMode} from './util/index.js';
+import {usingPlaygrounds} from '../util/index.js';
+
+describe('EVM sponsoring', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Fee is deducted from contract if sponsoring is enabled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const caller = helper.eth.createAccount();
+ const originalCallerBalance = await helper.balance.getEthereum(caller);
+
+ expect(originalCallerBalance).to.be.equal(0n);
+
+ const flipper = await helper.eth.deployFlipper(owner);
+
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+
+ await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
+ await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
+
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send({from: owner});
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+
+ expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
+ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+ expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
+
+ const originalSponsorBalance = await helper.balance.getEthereum(sponsor);
+ expect(originalSponsorBalance).to.be.not.equal(0n);
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // Balance should be taken from flipper instead of caller
+ expect(await helper.balance.getEthereum(caller)).to.be.equal(originalCallerBalance);
+ expect(await helper.balance.getEthereum(sponsor)).to.be.not.equal(originalSponsorBalance);
+ });
+
+ itEth('...but this doesn\'t applies to payable value', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const sponsor = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const originalCallerBalance = await helper.balance.getEthereum(caller);
+
+ expect(originalCallerBalance).to.be.not.equal(0n);
+
+ const collector = await helper.eth.deployCollectorContract(owner);
+
+ const helpers = await helper.ethNativeContract.contractHelpers(owner);
+
+ await helpers.methods.toggleAllowlist(collector.options.address, true).send({from: owner});
+ await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner});
+
+ expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.false;
+ await helpers.methods.setSponsoringMode(collector.options.address, SponsoringMode.Allowlisted).send({from: owner});
+ await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});
+ expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;
+
+ await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});
+ await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});
+
+ const originalSponsorBalance = await helper.balance.getEthereum(sponsor);
+ expect(originalSponsorBalance).to.be.not.equal(0n);
+
+ await collector.methods.giveMoney().send({from: caller, value: '10000'});
+
+ // Balance will be taken from both caller (value) and from collector (fee)
+ expect(await helper.balance.getEthereum(caller)).to.be.equals((originalCallerBalance - 10000n));
+ expect(await helper.balance.getEthereum(sponsor)).to.be.not.equals(originalSponsorBalance);
+ expect(await collector.methods.getCollected().call()).to.be.equal('10000');
+ });
+});
js-packages/tests/eth/tokenProperties.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/tokenProperties.test.ts
@@ -0,0 +1,625 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Contract} from 'web3-eth-contract';
+import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import type {ITokenPropertyPermission} from '@unique/playgrounds/types.js';
+import {Pallets} from '../util/index.js';
+import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '@unique/playgrounds/unique.js';
+import {CreateCollectionData, TokenPermissionField} from './util/playgrounds/types.js';
+
+describe('EVM token properties', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([1000n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can set all possible token property permissions`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);
+ for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+ await collection.methods.addCollectionAdminCross(caller).send({from: owner});
+
+ await collection.methods.setTokenPropertyPermissions([
+ ['testKey', [
+ [TokenPermissionField.Mutable, mutable],
+ [TokenPermissionField.TokenOwner, tokenOwner],
+ [TokenPermissionField.CollectionAdmin, collectionAdmin]],
+ ],
+ ]).send({from: caller.eth});
+
+ expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{
+ key: 'testKey',
+ permission: {mutable, collectionAdmin, tokenOwner},
+ }]);
+
+ expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([
+ ['testKey', [
+ [TokenPermissionField.Mutable.toString(), mutable],
+ [TokenPermissionField.TokenOwner.toString(), tokenOwner],
+ [TokenPermissionField.CollectionAdmin.toString(), collectionAdmin]],
+ ],
+ ]);
+ }
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ await collection.methods.setTokenPropertyPermissions([
+ ['testKey_0', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ['testKey_1', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, false],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ['testKey_2', [
+ [TokenPermissionField.Mutable, false],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, false]],
+ ],
+ ]).send({from: owner});
+
+ expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([
+ {
+ key: 'testKey_0',
+ permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+ },
+ {
+ key: 'testKey_1',
+ permission: {mutable: true, tokenOwner: false, collectionAdmin: true},
+ },
+ {
+ key: 'testKey_2',
+ permission: {mutable: false, tokenOwner: true, collectionAdmin: false},
+ },
+ ]);
+
+ expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([
+ ['testKey_0', [
+ [TokenPermissionField.Mutable.toString(), true],
+ [TokenPermissionField.TokenOwner.toString(), true],
+ [TokenPermissionField.CollectionAdmin.toString(), true]],
+ ],
+ ['testKey_1', [
+ [TokenPermissionField.Mutable.toString(), true],
+ [TokenPermissionField.TokenOwner.toString(), false],
+ [TokenPermissionField.CollectionAdmin.toString(), true]],
+ ],
+ ['testKey_2', [
+ [TokenPermissionField.Mutable.toString(), false],
+ [TokenPermissionField.TokenOwner.toString(), true],
+ [TokenPermissionField.CollectionAdmin.toString(), false]],
+ ],
+ ]);
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);
+
+ const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+ await collection.methods.addCollectionAdminCross(caller).send({from: owner});
+
+ await collection.methods.setTokenPropertyPermissions([
+ ['testKey_0', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ['testKey_1', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, false],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ['testKey_2', [
+ [TokenPermissionField.Mutable, false],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, false]],
+ ],
+ ]).send({from: caller.eth});
+
+ expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([
+ {
+ key: 'testKey_0',
+ permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+ },
+ {
+ key: 'testKey_1',
+ permission: {mutable: true, tokenOwner: false, collectionAdmin: true},
+ },
+ {
+ key: 'testKey_2',
+ permission: {mutable: false, tokenOwner: true, collectionAdmin: false},
+ },
+ ]);
+
+ expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([
+ ['testKey_0', [
+ [TokenPermissionField.Mutable.toString(), true],
+ [TokenPermissionField.TokenOwner.toString(), true],
+ [TokenPermissionField.CollectionAdmin.toString(), true]],
+ ],
+ ['testKey_1', [
+ [TokenPermissionField.Mutable.toString(), true],
+ [TokenPermissionField.TokenOwner.toString(), false],
+ [TokenPermissionField.CollectionAdmin.toString(), true]],
+ ],
+ ['testKey_2', [
+ [TokenPermissionField.Mutable.toString(), false],
+ [TokenPermissionField.TokenOwner.toString(), true],
+ [TokenPermissionField.CollectionAdmin.toString(), false]],
+ ],
+ ]);
+
+ }));
+
+ [
+ {
+ method: 'setProperties',
+ methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]],
+ expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}],
+ },
+ {
+ method: 'setProperty' /*Soft-deprecated*/,
+ methodParams: ['testKey1', Buffer.from('testValue1')],
+ expectedProps: [{key: 'testKey1', value: 'testValue1'}],
+ },
+ ].map(testCase =>
+ itEth(`[${testCase.method}] Can be set`, async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.nft.mintCollection(alice, {
+ tokenPropertyPermissions: [{
+ key: 'testKey1',
+ permission: {
+ collectionAdmin: true,
+ },
+ }, {
+ key: 'testKey2',
+ permission: {
+ collectionAdmin: true,
+ },
+ }],
+ });
+
+ await collection.addAdmin(alice, {Ethereum: caller});
+ const token = await collection.mintToken(alice);
+
+ const collectionEvm = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller, testCase.method === 'setProperty');
+
+ await collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller});
+
+ const properties = await token.getProperties();
+ expect(properties).to.deep.equal(testCase.expectedProps);
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Can be multiple set/read for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
+ const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true}}));
+
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPrefix: 'ethp',
+ tokenPropertyPermissions: permissions,
+ }) as UniqueNFTCollection | UniqueRFTCollection;
+
+ const token = await collection.mintToken(alice);
+
+ const valuesBefore = await token.getProperties(properties.map(p => p.key));
+ expect(valuesBefore).to.be.deep.equal([]);
+
+
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
+
+ expect(await contract.methods.properties(token.tokenId, []).call()).to.be.deep.equal([]);
+
+ await contract.methods.setProperties(token.tokenId, properties).send({from: caller});
+
+ const values = await token.getProperties(properties.map(p => p.key));
+ expect(values).to.be.deep.equal(properties.map(p => ({key: p.key, value: p.value.toString()})));
+
+ expect(await contract.methods.properties(token.tokenId, []).call()).to.be.like(properties
+ .map(p => helper.ethProperty.property(p.key, p.value.toString())));
+
+ expect(await contract.methods.properties(token.tokenId, [properties[0].key]).call())
+ .to.be.like([helper.ethProperty.property(properties[0].key, properties[0].value.toString())]);
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`Can be deleted for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [{
+ key: 'testKey',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ },
+ },
+ {
+ key: 'testKey_1',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ },
+ }],
+ });
+
+ const token = await collection.mintToken(alice);
+ await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}, {key: 'testKey_1', value: 'testValue_1'}]);
+ expect(await token.getProperties()).to.has.length(2);
+
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
+
+ await contract.methods.deleteProperties(token.tokenId, ['testKey', 'testKey_1']).send({from: caller});
+
+ const result = await token.getProperties(['testKey', 'testKey_1']);
+ expect(result.length).to.equal(0);
+ }));
+
+ itEth('Can be read', async({helper}) => {
+ const caller = helper.eth.createAccount();
+ const collection = await helper.nft.mintCollection(alice, {
+ tokenPropertyPermissions: [{
+ key: 'testKey',
+ permission: {
+ collectionAdmin: true,
+ },
+ }],
+ });
+
+ const token = await collection.mintToken(alice);
+ await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
+
+ const value = await contract.methods.property(token.tokenId, 'testKey').call();
+ expect(value).to.equal(helper.getWeb3().utils.toHex('testValue'));
+ });
+});
+
+describe('EVM token properties negative', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let caller: string;
+ let aliceCollection: UniqueNFTCollection;
+ let token: UniqueNFToken;
+ const tokenProps = [{key: 'testKey_1', value: 'testValue_1'}, {key: 'testKey_2', value: 'testValue_2'}];
+ let collectionEvm: Contract;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ beforeEach(async () => {
+ // 1. create collection with props: testKey_1, testKey_2
+ // 2. create token and set props testKey_1, testKey_2
+ await usingEthPlaygrounds(async (helper) => {
+ aliceCollection = await helper.nft.mintCollection(alice, {
+ tokenPropertyPermissions: [{
+ key: 'testKey_1',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ },
+ },
+ {
+ key: 'testKey_2',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ },
+ }],
+ });
+ token = await aliceCollection.mintToken(alice);
+ await token.setProperties(alice, tokenProps);
+ collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true);
+ });
+ });
+
+ [
+ {method: 'setProperty', methodParams: [tokenProps[1].key, Buffer.from('newValue')]},
+ {method: 'setProperties', methodParams: [[{key: tokenProps[1].key, value: Buffer.from('newValue')}]]},
+ ].map(testCase =>
+ itEth(`[${testCase.method}] Cannot set properties of non-owned collection`, async ({helper}) => {
+ caller = await helper.eth.createAccountWithBalance(donor);
+ collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true);
+ // Caller not an owner and not an admin, so he cannot set properties:
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
+
+ // Props have not changed:
+ const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
+ const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
+ expect(actualProps).to.deep.eq(expectedProps);
+ }));
+
+ [
+ {method: 'setProperty', methodParams: ['testKey_3', Buffer.from('testValue3')]},
+ {method: 'setProperties', methodParams: [[{key: 'testKey_3', value: Buffer.from('testValue3')}]]},
+ ].map(testCase =>
+ itEth(`[${testCase.method}] Cannot set non-existing properties`, async ({helper}) => {
+ caller = await helper.eth.createAccountWithBalance(donor);
+ collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true);
+ await helper.collection.addAdmin(alice, aliceCollection.collectionId, {Ethereum: caller});
+
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
+
+ // Props have not changed:
+ const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
+ const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
+ expect(actualProps).to.deep.eq(expectedProps);
+ }));
+
+ [
+ {method: 'deleteProperty', methodParams: ['testKey_2']},
+ {method: 'deleteProperties', methodParams: [['testKey_2']]},
+ ].map(testCase =>
+ itEth(`[${testCase.method}] Cannot delete properties of non-owned collection`, async ({helper}) => {
+ caller = await helper.eth.createAccountWithBalance(donor);
+ collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, testCase.method == 'deleteProperty');
+ // Caller not an owner and not an admin, so he cannot set properties:
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
+
+ // Props have not changed:
+ const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
+ const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
+ expect(actualProps).to.deep.eq(expectedProps);
+ }));
+
+ [
+ {method: 'deleteProperty', methodParams: ['testKey_3']},
+ {method: 'deleteProperties', methodParams: [['testKey_3']]},
+ ].map(testCase =>
+ itEth(`[${testCase.method}] Cannot delete non-existing properties`, async ({helper}) => {
+ caller = await helper.eth.createAccountWithBalance(donor);
+ collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, testCase.method == 'deleteProperty');
+ await helper.collection.addAdmin(alice, aliceCollection.collectionId, {Ethereum: caller});
+ // Caller cannot delete non-existing properties:
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
+ await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
+ // Props have not changed:
+ const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
+ const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
+ expect(actualProps).to.deep.eq(expectedProps);
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ await expect(collection.methods.setTokenPropertyPermissions([
+ ['testKey_0', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).call({from: caller})).to.be.rejectedWith('NoPermission');
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ await expect(collection.methods.setTokenPropertyPermissions([
+ // "Space" is invalid character
+ ['testKey 0', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey');
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can reconfigure token property permissions to stricter ones`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ // 1. Owner sets strict property-permissions:
+ await collection.methods.setTokenPropertyPermissions([
+ ['testKey', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).send({from: owner});
+
+ // 2. Owner can set stricter property-permissions:
+ for(const values of [[true, true, false], [true, false, false], [false, false, false]]) {
+ await collection.methods.setTokenPropertyPermissions([
+ ['testKey', [
+ [TokenPermissionField.Mutable, values[0]],
+ [TokenPermissionField.TokenOwner, values[1]],
+ [TokenPermissionField.CollectionAdmin, values[2]]],
+ ],
+ ]).send({from: owner});
+ }
+
+ expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{
+ key: 'testKey',
+ permission: {mutable: false, collectionAdmin: false, tokenOwner: false},
+ }]);
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Cannot reconfigure token property permissions to less strict ones`, testCase.requiredPallets, async({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
+ const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ // 1. Owner sets strict property-permissions:
+ await collection.methods.setTokenPropertyPermissions([
+ ['testKey', [
+ [TokenPermissionField.Mutable, false],
+ [TokenPermissionField.TokenOwner, false],
+ [TokenPermissionField.CollectionAdmin, false]],
+ ],
+ ]).send({from: owner});
+
+ // 2. Owner cannot set less strict property-permissions:
+ for(const values of [[true, false, false], [false, true, false], [false, false, true]]) {
+ await expect(collection.methods.setTokenPropertyPermissions([
+ ['testKey', [
+ [TokenPermissionField.Mutable, values[0]],
+ [TokenPermissionField.TokenOwner, values[1]],
+ [TokenPermissionField.CollectionAdmin, values[2]]],
+ ],
+ ]).call({from: owner})).to.be.rejectedWith('NoPermission');
+ }
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can't be multiple set/read for non-existent token`, testCase.requiredPallets, async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
+ const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true}}));
+
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPrefix: 'ethp',
+ tokenPropertyPermissions: permissions,
+ }) as UniqueNFTCollection | UniqueRFTCollection;
+
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
+
+ await expect(contract.methods.setProperties(1, properties).call({from: caller})).to.be.rejectedWith('TokenNotFound');
+ }));
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itEth.ifWithPallets(`[${testCase.mode}] Can't be deleted for non-existent token`, testCase.requiredPallets, async({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [{
+ key: 'testKey',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ },
+ },
+ {
+ key: 'testKey_1',
+ permission: {
+ mutable: true,
+ collectionAdmin: true,
+ },
+ }],
+ });
+
+
+ await collection.addAdmin(alice, {Ethereum: caller});
+
+ const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
+
+ await expect(contract.methods.deleteProperties(1, ['testKey', 'testKey_1']).call({from: caller})).to.be.rejectedWith('TokenNotFound');
+ }));
+});
+
+
+type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
+function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
+ if(args.length === 0) {
+ yield internalRest as any;
+ return;
+ }
+ for(const value of args[0]) {
+ yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
+ }
+}
js-packages/tests/eth/tokens/callMethodsERC20.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/tokens/callMethodsERC20.test.ts
@@ -0,0 +1,92 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {Pallets, requirePalletsOrSkip} from '../../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {CreateCollectionData} from '../util/playgrounds/types.js';
+
+[
+ {mode: 'ft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+].map(testCase => {
+ describe(`${testCase.mode.toUpperCase()}: ERC-20 call methods`, () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, testCase.requiredPallets);
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('totalSupply', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const mintingParams = testCase.mode === 'ft' ? [caller, 200n] : [caller];
+
+ const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('TotalSupply', '6', '6', testCase.mode)).send();
+ if(testCase.mode === 'rft') await collection.methods.mint(caller).send({from: caller});
+
+ // Use collection contract for FT or token contract for RFT:
+ const contract = testCase.mode === 'ft'
+ ? collection
+ : await helper.ethNativeContract.rftTokenById(collectionId, 1, caller);
+
+ // Mint tokens:
+ testCase.mode === 'ft'
+ ? await contract.methods.mint(...mintingParams).send({from: caller})
+ : await contract.methods.repartition(200).send({from: caller});
+
+ const totalSupply = await contract.methods.totalSupply().call();
+ expect(totalSupply).to.equal('200');
+ });
+
+ itEth('balanceOf', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const mintingParams = testCase.mode === 'ft' ? [caller, 200n] : [caller];
+
+ const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('BalanceOf', 'Descroption', 'Prefix', testCase.mode)).send();
+ if(testCase.mode === 'rft') await collection.methods.mint(caller).send({from: caller});
+
+ // Use collection contract for FT or token contract for RFT:
+ const contract = testCase.mode === 'ft'
+ ? collection
+ : await helper.ethNativeContract.rftTokenById(collectionId, 1, caller);
+
+ // Mint tokens:
+ testCase.mode === 'ft'
+ ? await contract.methods.mint(...mintingParams).send({from: caller})
+ : await contract.methods.repartition(200).send({from: caller});
+
+ const balance = await contract.methods.balanceOf(caller).call();
+ expect(balance).to.equal('200');
+ });
+
+ itEth('decimals', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('BalanceOf', 'Descroption', 'Prefix', testCase.mode)).send();
+ if(testCase.mode === 'rft') await collection.methods.mint(caller).send({from: caller});
+
+ // Use collection contract for FT or token contract for RFT:
+ const contract = testCase.mode === 'ft'
+ ? collection
+ : await helper.ethNativeContract.rftTokenById(collectionId, 1, caller);
+
+ const decimals = await contract.methods.decimals().call();
+ expect(decimals).to.equal(testCase.mode === 'rft' ? '0' : '18');
+ });
+ });
+});
js-packages/tests/eth/tokens/callMethodsERC721.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/tokens/callMethodsERC721.test.ts
@@ -0,0 +1,144 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {Pallets} from '../../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {CreateCollectionData} from '../util/playgrounds/types.js';
+
+
+describe('ERC-721 call methods', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ [
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'nft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: name/symbol/description`, testCase.requiredPallets, async ({helper}) => {
+ const callerEth = await helper.eth.createAccountWithBalance(donor);
+ const [callerSub] = await helper.arrange.createAccounts([100n], donor);
+ const [name, description, tokenPrefix] = ['Name', 'Description', 'Symbol'];
+
+ const {collection: collectionEth} = await helper.eth.createCollection(callerEth, new CreateCollectionData(name, description, tokenPrefix, testCase.mode)).send();
+ await collectionEth.methods.mint(callerEth).send({from: callerEth});
+ const {collectionId} = await helper[testCase.mode].mintCollection(callerSub, {name, description, tokenPrefix});
+ const collectionSub = await helper.ethNativeContract.collectionById(collectionId, testCase.mode, callerEth);
+
+ // Can get name/symbol/description for Eth collection
+ expect(await collectionEth.methods.name().call()).to.eq(name);
+ expect(await collectionEth.methods.symbol().call()).to.eq(tokenPrefix);
+ expect(await collectionEth.methods.description().call()).to.eq(description);
+ // Can get name/symbol/description for Sub collection
+ expect(await collectionSub.methods.name().call()).to.eq(name);
+ expect(await collectionSub.methods.symbol().call()).to.eq(tokenPrefix);
+ expect(await collectionSub.methods.description().call()).to.eq(description);
+ });
+ });
+
+ [
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'nft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: totalSupply`, testCase.requiredPallets, async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const {collection} = await helper.eth.createCollection(caller, new CreateCollectionData('TotalSupply', '6', '6', testCase.mode)).send();
+ await collection.methods.mint(caller).send({from: caller});
+
+ const totalSupply = await collection.methods.totalSupply().call();
+ expect(totalSupply).to.equal('1');
+ });
+ });
+
+ [
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'nft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: balanceOf`, testCase.requiredPallets, async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+
+ const {collection} = await helper.eth.createCollection(caller, new CreateCollectionData('BalanceOf', 'Descroption', 'Prefix', testCase.mode)).send();
+ await collection.methods.mint(caller).send({from: caller});
+ await collection.methods.mint(caller).send({from: caller});
+ await collection.methods.mint(caller).send({from: caller});
+
+ const balance = await collection.methods.balanceOf(caller).call();
+ expect(balance).to.equal('3');
+ });
+ });
+
+ [
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'nft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: ownerOf`, testCase.requiredPallets, async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const {collection} = await helper.eth.createCollection(caller, new CreateCollectionData('OwnerOf', '6', '6', testCase.mode)).send();
+
+ const result = await collection.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+
+ const owner = await collection.methods.ownerOf(tokenId).call();
+ expect(owner).to.equal(caller);
+ });
+ });
+
+ [
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ // TODO {mode: 'nft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: ownerOf after burn`, testCase.requiredPallets, async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('OwnerOf-AfterBurn', '6', '6', testCase.mode)).send();
+
+ const result = await collection.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller, true);
+
+ await tokenContract.methods.repartition(2).send();
+ await tokenContract.methods.transfer(receiver, 1).send();
+
+ await tokenContract.methods.burnFrom(caller, 1).send();
+
+ const owner = await collection.methods.ownerOf(tokenId).call();
+ expect(owner).to.equal(receiver);
+ });
+ });
+
+ itEth.ifWithPallets('RFT: ownerOf for partial ownership', [Pallets.ReFungible], async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+
+ const result = await contract.methods.mint(caller).send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
+
+ await tokenContract.methods.repartition(2).send();
+ await tokenContract.methods.transfer(receiver, 1).send();
+
+ const owner = await contract.methods.ownerOf(tokenId).call();
+ expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
+ });
+});
js-packages/tests/eth/tokens/minting.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/tokens/minting.test.ts
@@ -0,0 +1,168 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {Pallets} from '../../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import {CreateCollectionData} from '../util/playgrounds/types.js';
+
+
+describe('Minting tokens', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([30n, 20n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mint() for Substrate collection`, testCase.requiredPallets, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const mintingParams = testCase.mode === 'ft' ? [receiver, 100] : [receiver];
+
+ const collection = await helper[testCase.mode].mintCollection(alice);
+ await collection.addAdmin(alice, {Ethereum: owner});
+
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ const result = await contract.methods.mint(...mintingParams).send({from: owner});
+
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ if(testCase.mode === 'ft')
+ expect(event.returnValues.value).to.equal('100');
+
+ // Check token exist:
+ if(testCase.mode === 'ft') {
+ expect(await helper.ft.getBalance(collection.collectionId, {Ethereum: receiver})).to.eq(100n);
+ } else {
+ const tokenId = event.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+ expect(await helper.collection.getLastTokenId(collection.collectionId)).to.eq(1);
+ expect(await contract.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
+ }
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mint() for Ethereum collection`, testCase.requiredPallets, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const mintingParams = testCase.mode === 'ft' ? [receiver, 100] : [receiver];
+
+ const {collection, collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Name', 'Desc', 'Prefix', testCase.mode)).send();
+
+ const result = await collection.methods.mint(...mintingParams).send({from: owner});
+
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ if(testCase.mode === 'ft')
+ expect(event.returnValues.value).to.equal('100');
+
+ // Check token exist:
+ if(testCase.mode === 'ft') {
+ expect(await helper.ft.getBalance(collectionId, {Ethereum: receiver})).to.eq(100n);
+ } else {
+ const tokenId = event.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+ expect(await helper.collection.getLastTokenId(collectionId)).to.eq(1);
+ expect(await collection.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
+ }
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'ft' as const, requiredPallets: []},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mint() for Ethereum collection`, testCase.requiredPallets, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+ const mintingParams = testCase.mode === 'ft' ? [receiver, 100] : [receiver];
+
+ const {collection, collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Name', 'Desc', 'Prefix', testCase.mode)).send();
+
+ const result = await collection.methods.mint(...mintingParams).send({from: owner});
+
+ // Check events:
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(receiver);
+ if(testCase.mode === 'ft')
+ expect(event.returnValues.value).to.equal('100');
+
+ // Check token exist:
+ if(testCase.mode === 'ft') {
+ expect(await helper.ft.getBalance(collectionId, {Ethereum: receiver})).to.eq(100n);
+ } else {
+ const tokenId = event.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+ expect(await helper.collection.getLastTokenId(collectionId)).to.eq(1);
+ expect(await collection.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
+ }
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase => {
+ itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mintWithTokenURI() for Ethereum collection`, testCase.requiredPallets, async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', '6', '6', '');
+ const contract = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
+
+ const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send();
+ const tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal('1');
+
+ const event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(receiver);
+
+ expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+ expect(await contract.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
+ // TODO: this wont work right now, need release 919000 first
+ // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();
+ // const tokenUri = await contract.methods.tokenURI(nextTokenId).call();
+ // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);
+ });
+ });
+});
js-packages/tests/eth/transferValue.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/transferValue.test.ts
@@ -0,0 +1,64 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect} from 'chai';
+
+describe('Send value to contract', () => {
+ let donor: IKeyringPair;
+
+ before(async () => {
+ await usingEthPlaygrounds(async (_helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Send to and from contract', async ({helper}) => {
+ const contractOwner = await helper.eth.createAccountWithBalance(donor, 600n);
+ const [buyer, receiver] = await helper.arrange.createAccounts([600n, 600n], donor);
+ const receiverMirror = helper.address.substrateToEth(receiver.address);
+ const contract = await helper.ethContract.deployByCode(
+ contractOwner,
+ 'Test',
+ `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.18;
+
+ contract Test {
+ function send() public payable {
+ if (msg.value < 1000000000000000000)
+ revert("Not enough gold");
+ }
+
+ function withdraw(address to) public {
+ payable(to).transfer(1000000000000000000);
+ }
+ }
+ `,
+ );
+
+ const balanceBefore = await helper.balance.getSubstrate(buyer.address);
+ await helper.eth.sendEVM(buyer, contract.options.address, contract.methods.send().encodeABI(), '2000000000000000000');
+ const balanceAfter = await helper.balance.getSubstrate(buyer.address);
+ expect(balanceBefore - balanceAfter > 2000000000000000000n).to.be.true;
+ expect(await helper.balance.getEthereum(contract.options.address)).to.be.equal(2000000000000000000n);
+
+ await helper.eth.sendEVM(buyer, contract.options.address, contract.methods.withdraw(receiverMirror).encodeABI(), '0');
+ expect(await helper.balance.getEthereum(receiverMirror)).to.be.equal(1000000000000000000n);
+ expect(await helper.balance.getEthereum(contract.options.address)).to.be.equal(1000000000000000000n);
+ });
+});
js-packages/tests/eth/util/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/util/index.ts
@@ -0,0 +1,107 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import * as path from 'path';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import config from '../../config.js';
+
+import {EthUniqueHelper} from './playgrounds/unique.dev.js';
+import {SilentLogger, SilentConsole} from '@unique/playgrounds/unique.dev.js';
+import {makeNames} from '../../util/index.js';
+import type {SchedKind} from '../../util/index.js';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import chaiLike from 'chai-like';
+import {getTestSeed, MINIMUM_DONOR_FUND, requirePalletsOrSkip} from '../../util/index.js';
+
+chai.use(chaiAsPromised);
+chai.use(chaiLike);
+export const expect = chai.expect;
+
+export enum SponsoringMode {
+ Disabled = 0,
+ Allowlisted = 1,
+ Generous = 2,
+}
+
+type PrivateKeyFn = (seed: string | {filename?: string, url?: string}) => Promise<IKeyringPair>;
+
+export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: PrivateKeyFn) => Promise<void>) => {
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
+
+ const helper = new EthUniqueHelper(new SilentLogger());
+
+ try {
+ await helper.connect(config.substrateUrl);
+ await helper.connectWeb3(config.substrateUrl);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const privateKey: PrivateKeyFn = async (seed) => {
+ if(typeof seed === 'string') {
+ return helper.util.fromSeed(seed, ss58Format);
+ }
+ if(seed.url) {
+ const {filename} = makeNames(seed.url);
+ seed.filename = filename;
+ } else if(seed.filename) {
+ // Pass
+ } else {
+ throw new Error('no url nor filename set');
+ }
+ const actualSeed = getTestSeed(seed.filename);
+ let account = helper.util.fromSeed(actualSeed, ss58Format);
+ if(await helper.balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND) {
+ console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
+ account = helper.util.fromSeed('//Alice', ss58Format);
+ }
+ return account;
+ };
+ await code(helper, privateKey);
+ }
+ finally {
+ await helper.disconnect();
+ silentConsole.disable();
+ }
+};
+
+export function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+ (opts.only ? it.only :
+ opts.skip ? it.skip : it)(name, async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ if(opts.requiredPallets) {
+ requirePalletsOrSkip(this, helper, opts.requiredPallets);
+ }
+
+ await cb({helper, privateKey});
+ });
+ });
+}
+
+export function itEthIfWithPallet(name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+ return itEth(name, cb, {requiredPallets: required, ...opts});
+}
+
+itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEth(name, cb, {only: true});
+itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEth(name, cb, {skip: true});
+
+itEthIfWithPallet.only = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {only: true});
+itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});
+itEth.ifWithPallets = itEthIfWithPallet;
+
+export function itSchedEth(
+ name: string,
+ cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any,
+ opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},
+) {
+ itEth(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);
+ itEth(name + ' (named scheduling)', (apis) => cb('named', apis), opts);
+}
+itSchedEth.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {only: true});
+itSchedEth.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {skip: true});
+itSchedEth.ifWithPallets = itSchedIfWithPallets;
+
+function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+ return itSchedEth(name, cb, {requiredPallets: required, ...opts});
+}
js-packages/tests/eth/util/playgrounds/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/util/playgrounds/types.ts
@@ -0,0 +1,133 @@
+import {CollectionFlag} from '@unique/playgrounds/types.js';
+import type {TCollectionMode} from '@unique/playgrounds/types.js';
+
+export interface ContractImports {
+ solPath: string;
+ fsPath: string;
+}
+
+export interface CompiledContract {
+ abi: any;
+ object: string;
+}
+
+export type NormalizedEvent = {
+ address: string,
+ event: string,
+ args: { [key: string]: string }
+};
+
+export interface OptionUint {
+ status: boolean,
+ value: bigint,
+}
+
+export type EthAddress = string;
+
+export interface CrossAddress {
+ readonly eth: EthAddress,
+ readonly sub: string | Uint8Array,
+}
+
+export type EthProperty = string[];
+
+export enum TokenPermissionField {
+ Mutable,
+ TokenOwner,
+ CollectionAdmin
+}
+
+export enum CollectionLimitField {
+ AccountTokenOwnership,
+ SponsoredDataSize,
+ SponsoredDataRateLimit,
+ TokenLimit,
+ SponsorTransferTimeout,
+ SponsorApproveTimeout,
+ OwnerCanTransfer,
+ OwnerCanDestroy,
+ TransferEnabled
+}
+
+export interface CollectionLimit {
+ field: CollectionLimitField,
+ value: OptionUint,
+}
+
+export interface CollectionLimitValue {
+ field: CollectionLimitField,
+ value: bigint,
+}
+
+export enum CollectionMode {
+ Nonfungible,
+ Fungible,
+ Refungible,
+}
+
+export interface PropertyPermission {
+ code: TokenPermissionField,
+ value: boolean,
+}
+export interface TokenPropertyPermission {
+ key: string,
+ permissions: PropertyPermission[],
+}
+export interface CollectionNestingAndPermission {
+ token_owner: boolean,
+ collection_admin: boolean,
+ restricted: string[],
+}
+
+export const emptyAddress: [string, string] = [
+ '0x0000000000000000000000000000000000000000',
+ '0',
+];
+
+export const CREATE_COLLECTION_DATA_DEFAULTS = {
+ decimals: 0,
+ properties: [],
+ tokenPropertyPermissions: [],
+ adminList: [],
+ nestingSettings: {token_owner: false, collection_admin: false, restricted: []},
+ limits: [],
+ pendingSponsor: emptyAddress,
+ flags: 0,
+};
+
+export interface Property {
+ key: string;
+ value: Buffer;
+}
+
+export class CreateCollectionData {
+ name: string;
+ description: string;
+ tokenPrefix: string;
+ collectionMode: TCollectionMode;
+ decimals? = 0;
+ properties?: Property[] = [];
+ tokenPropertyPermissions?: TokenPropertyPermission[] = [];
+ adminList?: CrossAddress[] = [];
+ nestingSettings?: CollectionNestingAndPermission = {token_owner: false, collection_admin: false, restricted: []};
+ limits?: CollectionLimitValue[] = [];
+ pendingSponsor?: [string, string] = emptyAddress;
+ flags?: number | CollectionFlag[] = [0];
+
+ constructor(
+ name: string,
+ description: string,
+ tokenPrefix: string,
+ collectionMode: TCollectionMode,
+ decimals = 18,
+ ) {
+ this.name = name;
+ this.description = description;
+ this.tokenPrefix = tokenPrefix;
+ this.collectionMode = collectionMode;
+ if(collectionMode == 'ft')
+ this.decimals = decimals;
+ else
+ this.decimals = 0;
+ }
+}
js-packages/tests/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/eth/util/playgrounds/unique.dev.ts
@@ -0,0 +1,616 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+/* eslint-disable function-call-argument-newline */
+
+import {readFile} from 'fs/promises';
+
+import * as web3 from 'web3';
+import {WebsocketProvider} from 'web3-core';
+import {Contract} from 'web3-eth-contract';
+
+// @ts-ignore
+import solc from 'solc';
+
+import {evmToAddress} from '@polkadot/util-crypto';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import {ArrangeGroup, DevUniqueHelper} from '@unique/playgrounds/unique.dev.js';
+
+import type {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types.js';
+import {CollectionMode, CreateCollectionData} from './types.js';
+
+// Native contracts ABI
+import collectionHelpersAbi from '../../abi/collectionHelpers.json' assert {type: 'json'};
+import nativeFungibleAbi from '../../abi/nativeFungible.json' assert {type: 'json'};
+import fungibleAbi from '../../abi/fungible.json' assert {type: 'json'};
+import fungibleDeprecatedAbi from '../../abi/fungibleDeprecated.json' assert {type: 'json'};
+import nonFungibleAbi from '../../abi/nonFungible.json' assert {type: 'json'};
+import nonFungibleDeprecatedAbi from '../../abi/nonFungibleDeprecated.json' assert {type: 'json'};
+import refungibleAbi from '../../abi/reFungible.json' assert {type: 'json'};
+import refungibleDeprecatedAbi from '../../abi/reFungibleDeprecated.json' assert {type: 'json'};
+import refungibleTokenAbi from '../../abi/reFungibleToken.json' assert {type: 'json'};
+import refungibleTokenDeprecatedAbi from '../../abi/reFungibleTokenDeprecated.json' assert {type: 'json'};
+import contractHelpersAbi from '../../abi/contractHelpers.json' assert {type: 'json'};
+import type {ICrossAccountId, TEthereumAccount, TCollectionMode} from '@unique/playgrounds/types.js';
+
+class EthGroupBase {
+ helper: EthUniqueHelper;
+ gasPrice?: string;
+
+ constructor(helper: EthUniqueHelper) {
+ this.helper = helper;
+ }
+ async getGasPrice() {
+ if(this.gasPrice)
+ return this.gasPrice;
+ this.gasPrice = await this.helper.getWeb3().eth.getGasPrice();
+ return this.gasPrice;
+ }
+}
+
+class ContractGroup extends EthGroupBase {
+ async findImports(imports?: ContractImports[]) {
+ if(!imports) return function(path: string) {
+ return {error: `File not found: ${path}`};
+ };
+
+ const knownImports = {} as { [key: string]: string };
+ for(const imp of imports) {
+ knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
+ }
+
+ return function(path: string) {
+ if(path in knownImports) return {contents: knownImports[path]};
+ return {error: `File not found: ${path}`};
+ };
+ }
+
+ async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {
+ const compiled = JSON.parse(solc.compile(JSON.stringify({
+ language: 'Solidity',
+ sources: {
+ [`${name}.sol`]: {
+ content: src,
+ },
+ },
+ settings: {
+ outputSelection: {
+ '*': {
+ '*': ['*'],
+ },
+ },
+ },
+ }), {import: await this.findImports(imports)}));
+
+ const hasErrors = compiled['errors']
+ && compiled['errors'].length > 0
+ && compiled.errors.some(function(err: any) {
+ return err.severity == 'error';
+ });
+
+ if(hasErrors) {
+ throw compiled.errors;
+ }
+ const out = compiled.contracts[`${name}.sol`][name];
+
+ return {
+ abi: out.abi,
+ object: '0x' + out.evm.bytecode.object,
+ };
+ }
+
+ async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[], gas?: number, args?: any[]): Promise<Contract> {
+ const compiledContract = await this.compile(name, src, imports);
+ return this.deployByAbi(signer, compiledContract.abi, compiledContract.object, gas, args);
+ }
+
+ async deployByAbi(signer: string, abi: any, object: string, gas?: number, args?: any[]): Promise<Contract> {
+ const web3 = this.helper.getWeb3();
+ const contract = new web3.eth.Contract(abi, undefined, {
+ data: object,
+ from: signer,
+ gas: gas ?? this.helper.eth.DEFAULT_GAS,
+ });
+ return await contract.deploy({data: object, arguments: args}).send({from: signer});
+ }
+
+}
+
+class NativeContractGroup extends EthGroupBase {
+
+ contractHelpers(caller: string) {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {
+ from: caller,
+ gas: this.helper.eth.DEFAULT_GAS,
+ });
+ }
+
+ collectionHelpers(caller: string) {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {
+ from: caller,
+ gas: this.helper.eth.DEFAULT_GAS,
+ });
+ }
+
+ collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) {
+ let abi;
+ if(address === this.helper.ethAddress.fromCollectionId(0)) {
+ abi = nativeFungibleAbi;
+ } else {
+ abi ={
+ 'nft': nonFungibleAbi,
+ 'rft': refungibleAbi,
+ 'ft': fungibleAbi,
+ }[mode];
+ }
+ if(mergeDeprecated) {
+ const deprecated = {
+ 'nft': nonFungibleDeprecatedAbi,
+ 'rft': refungibleDeprecatedAbi,
+ 'ft': fungibleDeprecatedAbi,
+ }[mode];
+ abi = [...abi, ...deprecated];
+ }
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(abi as any, address, {
+ gas: this.helper.eth.DEFAULT_GAS,
+ ...(caller ? {from: caller} : {}),
+ });
+ }
+
+ collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string, mergeDeprecated = false) {
+ return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated);
+ }
+
+ rftToken(address: string, caller?: string, mergeDeprecated = false) {
+ const web3 = this.helper.getWeb3();
+ const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi;
+ return new web3.eth.Contract(abi as any, address, {
+ gas: this.helper.eth.DEFAULT_GAS,
+ ...(caller ? {from: caller} : {}),
+ });
+ }
+
+ rftTokenById(collectionId: number, tokenId: number, caller?: string, mergeDeprecated = false) {
+ return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller, mergeDeprecated);
+ }
+}
+
+class CreateCollectionTransaction {
+ signer: string;
+ data: CreateCollectionData;
+ mergeDeprecated: boolean;
+ helper: EthUniqueHelper;
+
+ constructor(helper: EthUniqueHelper, signer: string, data: CreateCollectionData, mergeDeprecated = false) {
+ this.helper = helper;
+ this.signer = signer;
+
+ let flags = 0;
+ // convert CollectionFlags to number and join them in one number
+ if(!data.flags) {
+ flags = 0;
+ } else if(typeof data.flags == 'number') {
+ flags = data.flags;
+ } else {
+ for(let i = 0; i < data.flags.length; i++){
+ const flag = data.flags[i];
+ flags = flags | flag;
+ }
+ }
+ data.flags = flags;
+
+ this.data = data;
+ this.mergeDeprecated = mergeDeprecated;
+ }
+
+ // eslint-disable-next-line require-await
+ private async createTransaction() {
+ const collectionHelper = this.helper.ethNativeContract.collectionHelpers(this.signer);
+ let collectionMode;
+ switch (this.data.collectionMode) {
+ case 'nft': collectionMode = CollectionMode.Nonfungible; break;
+ case 'rft': collectionMode = CollectionMode.Refungible; break;
+ case 'ft': collectionMode = CollectionMode.Fungible; break;
+ }
+
+ const tx = collectionHelper.methods.createCollection([
+ this.data.name,
+ this.data.description,
+ this.data.tokenPrefix,
+ collectionMode,
+ this.data.decimals,
+ this.data.properties,
+ this.data.tokenPropertyPermissions,
+ this.data.adminList,
+ this.data.nestingSettings,
+ this.data.limits,
+ this.data.pendingSponsor,
+ this.data.flags,
+ ]);
+ return tx;
+ }
+
+ async send(options?: any): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[], collection: Contract }> {
+ const collectionCreationPrice = {
+ value: Number(this.helper.balance.getCollectionCreationPrice()),
+ };
+ const tx = await this.createTransaction();
+ const result = await tx.send({...options, ...collectionCreationPrice});
+
+ const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+ const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+ const events = this.helper.eth.normalizeEvents(result.events);
+ const collection = await this.helper.ethNativeContract.collectionById(collectionId, this.data.collectionMode, this.signer, this.mergeDeprecated);
+
+ return {collectionId, collectionAddress, events, collection};
+ }
+
+ async call(options?: any) {
+ const collectionCreationPrice = {
+ value: Number(this.helper.balance.getCollectionCreationPrice()),
+ };
+ const tx = await this.createTransaction();
+
+ return await tx.call({...options, ...collectionCreationPrice});
+ }
+}
+
+
+class EthGroup extends EthGroupBase {
+ DEFAULT_GAS = 2_500_000;
+
+ createAccount() {
+ const web3 = this.helper.getWeb3();
+ const account = web3.eth.accounts.create();
+ web3.eth.accounts.wallet.add(account.privateKey);
+ return account.address;
+ }
+
+ async createAccountWithBalance(donor: IKeyringPair, amount = 600n) {
+ const account = this.createAccount();
+ await this.transferBalanceFromSubstrate(donor, account, amount);
+
+ return account;
+ }
+
+ async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount = 100n, inTokens = true) {
+ return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
+ }
+
+ async getCollectionCreationFee(signer: string) {
+ const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+ return await collectionHelper.methods.collectionCreationFee().call();
+ }
+
+ async sendEVM(signer: IKeyringPair, contractAddress: string, abi: string, value: string, gasLimit?: number) {
+ if(!gasLimit) gasLimit = this.DEFAULT_GAS;
+ const web3 = this.helper.getWeb3();
+ // FIXME: can't send legacy transaction using tx.evm.call
+ const gasPrice = await web3.eth.getGasPrice();
+ // TODO: check execution status
+ await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []],
+ true,
+ );
+ }
+
+ async callEVM(signer: TEthereumAccount, contractAddress: string, abi: string) {
+ return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);
+ }
+
+ createCollectionMethodName(mode: TCollectionMode) {
+ switch (mode) {
+ case 'ft':
+ return 'createFTCollection';
+ case 'nft':
+ return 'createNFTCollection';
+ case 'rft':
+ return 'createRFTCollection';
+ }
+ }
+
+ createCollection(signer: string, data: CreateCollectionData, mergeDeprecated = false): CreateCollectionTransaction {
+ return new CreateCollectionTransaction(this.helper, signer, data, mergeDeprecated);
+ }
+
+ createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+ return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
+ }
+
+ async createERC721MetadataCompatibleCollection(signer: string, data: CreateCollectionData, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+ const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+
+ const {collectionId, collectionAddress, events} = await this.createCollection(signer, data).send();
+
+ await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
+
+ return {collectionId, collectionAddress, events};
+ }
+
+ async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+ const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+
+ const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
+
+ await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
+
+ return {collectionId, collectionAddress, events};
+ }
+
+ createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+ return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
+ }
+
+ createFungibleCollection(signer: string, name: string, _decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+ return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'ft')).send();
+ }
+
+ async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+ const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+
+ const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
+
+ await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
+
+ return {collectionId, collectionAddress, events};
+ }
+
+ async deployCollectorContract(signer: string): Promise<Contract> {
+ return await this.helper.ethContract.deployByCode(signer, 'Collector', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract Collector {
+ uint256 collected;
+ fallback() external payable {
+ giveMoney();
+ }
+ function giveMoney() public payable {
+ collected += msg.value;
+ }
+ function getCollected() public view returns (uint256) {
+ return collected;
+ }
+ function getUnaccounted() public view returns (uint256) {
+ return address(this).balance - collected;
+ }
+
+ function withdraw(address payable target) public {
+ target.transfer(collected);
+ collected = 0;
+ }
+ }
+ `);
+ }
+
+ async deployFlipper(signer: string): Promise<Contract> {
+ return await this.helper.ethContract.deployByCode(signer, 'Flipper', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract Flipper {
+ bool value = false;
+ function flip() public {
+ value = !value;
+ }
+ function getValue() public view returns (bool) {
+ return value;
+ }
+ }
+ `);
+ }
+
+ async recordCallFee(user: string, call: () => Promise<any>): Promise<bigint> {
+ const before = await this.helper.balance.getEthereum(user);
+ await call();
+ // In dev mode, the transaction might not finish processing in time
+ await this.helper.wait.newBlocks(1);
+ const after = await this.helper.balance.getEthereum(user);
+
+ return before - after;
+ }
+
+ normalizeEvents(events: any): NormalizedEvent[] {
+ const output = [];
+ for(const key of Object.keys(events)) {
+ if(key.match(/^[0-9]+$/)) {
+ output.push(events[key]);
+ } else if(Array.isArray(events[key])) {
+ output.push(...events[key]);
+ } else {
+ output.push(events[key]);
+ }
+ }
+ output.sort((a, b) => a.logIndex - b.logIndex);
+ return output.map(({address, event, returnValues}) => {
+ const args: { [key: string]: string } = {};
+ for(const key of Object.keys(returnValues)) {
+ if(!key.match(/^[0-9]+$/)) {
+ args[key] = returnValues[key];
+ }
+ }
+ return {
+ address,
+ event,
+ args,
+ };
+ });
+ }
+
+ async calculateFee(address: ICrossAccountId, code: () => Promise<any>): Promise<bigint> {
+ const wrappedCode = async () => {
+ await code();
+ // In dev mode, the transaction might not finish processing in time
+ await this.helper.wait.newBlocks(1);
+ };
+ return await this.helper.arrange.calculcateFee(address, wrappedCode);
+ }
+}
+
+class EthAddressGroup extends EthGroupBase {
+ extractCollectionId(address: string): number {
+ if(!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
+ return parseInt(address.slice(address.length - 8), 16);
+ }
+
+ fromCollectionId(collectionId: number): string {
+ if(collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow');
+ return (web3 as any).utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`);
+ }
+
+ extractTokenId(address: string): { collectionId: number, tokenId: number } {
+ if(!address.startsWith('0x'))
+ throw 'address not starts with "0x"';
+ if(address.length > 42)
+ throw 'address length is more than 20 bytes';
+ return {
+ collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
+ tokenId: Number('0x' + address.substring(address.length - 8)),
+ };
+ }
+
+ fromTokenId(collectionId: number, tokenId: number): string {
+ return this.helper.util.getTokenAddress({collectionId, tokenId});
+ }
+
+ normalizeAddress(address: string): string {
+ return '0x' + address.substring(address.length - 40);
+ }
+}
+export class EthPropertyGroup extends EthGroupBase {
+ property(key: string, value: string): EthProperty {
+ return [
+ key,
+ '0x' + Buffer.from(value).toString('hex'),
+ ];
+ }
+}
+export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;
+
+export class EthCrossAccountGroup extends EthGroupBase {
+ createAccount(): CrossAddress {
+ return this.fromAddress(this.helper.eth.createAccount());
+ }
+
+ async createAccountWithBalance(donor: IKeyringPair, amount = 100n) {
+ return this.fromAddress(await this.helper.eth.createAccountWithBalance(donor, amount));
+ }
+
+ fromAddress(address: TEthereumAccount): CrossAddress {
+ return {
+ eth: address,
+ sub: '0',
+ };
+ }
+
+ fromAddr(address: TEthereumAccount): [string, string] {
+ return [
+ address,
+ '0',
+ ];
+ }
+
+ fromKeyringPair(keyring: IKeyringPair): CrossAddress {
+ return {
+ eth: '0x0000000000000000000000000000000000000000',
+ sub: keyring.addressRaw,
+ };
+ }
+}
+
+export class FeeGas {
+ fee: number | bigint = 0n;
+
+ gas: number | bigint = 0n;
+
+ public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
+ const instance = new FeeGas();
+ instance.fee = instance.convertToTokens(fee);
+ instance.gas = await instance.convertToGas(fee, helper);
+ return instance;
+ }
+
+ private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
+ const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
+ return fee / gasPrice;
+ }
+
+ private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
+ return Number((value * 1000n) / nominal) / 1000;
+ }
+}
+
+class EthArrangeGroup extends ArrangeGroup {
+ declare helper: EthUniqueHelper;
+
+ constructor(helper: EthUniqueHelper) {
+ super(helper);
+ this.helper = helper;
+ }
+
+ async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
+ const fee = await this.calculcateFee(payer, promise);
+ return await FeeGas.build(this.helper, fee);
+ }
+}
+export class EthUniqueHelper extends DevUniqueHelper {
+ web3: web3.default | null = null;
+ web3Provider: WebsocketProvider | null = null;
+
+ eth: EthGroup;
+ ethAddress: EthAddressGroup;
+ ethCrossAccount: EthCrossAccountGroup;
+ ethNativeContract: NativeContractGroup;
+ ethContract: ContractGroup;
+ ethProperty: EthPropertyGroup;
+ declare arrange: EthArrangeGroup;
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: { [key: string]: any } = {}) {
+ options.helperBase = options.helperBase ?? EthUniqueHelper;
+
+ super(logger, options);
+ this.eth = new EthGroup(this);
+ this.ethAddress = new EthAddressGroup(this);
+ this.ethCrossAccount = new EthCrossAccountGroup(this);
+ this.ethNativeContract = new NativeContractGroup(this);
+ this.ethContract = new ContractGroup(this);
+ this.ethProperty = new EthPropertyGroup(this);
+ this.arrange = new EthArrangeGroup(this);
+ super.arrange = this.arrange;
+ }
+
+ getWeb3(): web3.default {
+ if(this.web3 === null) throw Error('Web3 not connected');
+ return this.web3;
+ }
+
+ connectWeb3(wsEndpoint: string) {
+ if(this.web3 !== null) return;
+ this.web3Provider = new (web3 as any).providers.WebsocketProvider(wsEndpoint);
+ this.web3 = new (web3 as any)(this.web3Provider);
+ }
+
+ override async disconnect() {
+ if(this.web3 === null) return;
+ this.web3Provider?.connection.close();
+
+ await super.disconnect();
+ }
+
+ override clearApi() {
+ super.clearApi();
+ this.web3 = null;
+ }
+
+ override clone(helperCls: EthUniqueHelperConstructor, options?: { [key: string]: any; }): EthUniqueHelper {
+ const newHelper = super.clone(helperCls, options) as EthUniqueHelper;
+ newHelper.web3 = this.web3;
+ newHelper.web3Provider = this.web3Provider;
+
+ return newHelper;
+ }
+}
js-packages/tests/fungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/fungible.test.ts
@@ -0,0 +1,186 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect, requirePalletsOrSkip, Pallets} from './util/index.js';
+
+const U128_MAX = (1n << 128n) - 1n;
+
+describe('integration test: Fungible functionality:', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+ });
+ });
+
+ itSub('Create fungible collection and token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'trest'});
+ const defaultTokenId = await collection.getLastTokenId();
+ expect(defaultTokenId).to.be.equal(0);
+
+ await collection.mint(alice, U128_MAX);
+ const aliceBalance = await collection.getBalance({Substrate: alice.address});
+ const itemCountAfter = await collection.getLastTokenId();
+
+ expect(itemCountAfter).to.be.equal(defaultTokenId);
+ expect(aliceBalance).to.be.equal(U128_MAX);
+ });
+
+ itSub('RPC method tokenOnewrs for fungible collection and token', async ({helper}) => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const facelessCrowd = (await helper.arrange.createAccounts(Array(7).fill(0n), donor)).map(keyring => ({Substrate: keyring.address}));
+
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ await collection.mint(alice, U128_MAX);
+
+ await collection.transfer(alice, {Substrate: bob.address}, 1000n);
+ await collection.transfer(alice, ethAcc, 900n);
+
+ for(let i = 0; i < 7; i++) {
+ await collection.transfer(alice, facelessCrowd[i], 1n);
+ }
+
+ const owners = await collection.getTop10Owners();
+
+ // What to expect
+ expect(owners).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]);
+ expect(owners.length).to.be.equal(10);
+
+ const [eleven] = await helper.arrange.createAccounts([0n], donor);
+ expect(await collection.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true;
+ expect((await collection.getTop10Owners()).length).to.be.equal(10);
+ });
+
+ itSub('Transfer token', async ({helper}) => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ await collection.mint(alice, 500n);
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(500n);
+ expect(await collection.transfer(alice, {Substrate: bob.address}, 60n)).to.be.true;
+ expect(await collection.transfer(alice, ethAcc, 140n)).to.be.true;
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(300n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(60n);
+ expect(await collection.getBalance(ethAcc)).to.be.equal(140n);
+
+ await expect(collection.transfer(alice, {Substrate: bob.address}, 350n)).to.eventually.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub('Tokens multiple creation', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ await collection.mintWithOneOwner(alice, [
+ {value: 500n},
+ {value: 400n},
+ {value: 300n},
+ ]);
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1200n);
+ });
+
+ itSub('Burn some tokens ', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ await collection.mint(alice, 500n);
+
+ expect(await collection.doesTokenExist(0)).to.be.true;
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(500n);
+ expect(await collection.burnTokens(alice, 499n)).to.be.true;
+ expect(await collection.doesTokenExist(0)).to.be.true;
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);
+ });
+
+ itSub('Burn all tokens ', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ await collection.mint(alice, 500n);
+
+ expect(await collection.doesTokenExist(0)).to.be.true;
+ expect(await collection.burnTokens(alice, 500n)).to.be.true;
+ expect(await collection.doesTokenExist(0)).to.be.true;
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(0n);
+ expect(await collection.getTotalPieces()).to.be.equal(0n);
+ });
+
+ itSub('Set allowance for token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ await collection.mint(alice, 100n);
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(100n);
+
+ expect(await collection.approveTokens(alice, {Substrate: bob.address}, 60n)).to.be.true;
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(60n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);
+
+ expect(await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: bob.address}, 20n)).to.be.true;
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(80n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(20n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(40n);
+
+ await collection.burnTokensFrom(bob, {Substrate: alice.address}, 10n);
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(70n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(30n);
+ expect(await collection.transferFrom(bob, {Substrate: alice.address}, ethAcc, 10n)).to.be.true;
+ expect(await collection.getBalance(ethAcc)).to.be.equal(10n);
+ });
+});
+
+describe('Fungible negative tests', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('Cannot transfer incorrect amount of tokens', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const nonExistingCollection = helper.ft.getCollectionObject(99999);
+ await collection.mint(alice, 10n, {Substrate: bob.address});
+
+ // 1. Alice cannot transfer more than 0 tokens if balance low:
+ await expect(collection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
+ await expect(collection.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow');
+
+ // 2. Alice cannot transfer non-existing token:
+ await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.CollectionNotFound');
+ await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.CollectionNotFound');
+
+ // 3. Zero transfer allowed (EIP-20):
+ await collection.transfer(bob, {Substrate: charlie.address}, 0n);
+ // 3.1 even if the balance = 0
+ await collection.transfer(alice, {Substrate: charlie.address}, 0n);
+
+ expect(await collection.getBalance({Substrate: alice.address})).to.eq(0n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.eq(10n);
+ expect(await collection.getBalance({Substrate: charlie.address})).to.eq(0n);
+ });
+});
js-packages/tests/getPropertiesRpc.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/getPropertiesRpc.test.ts
@@ -0,0 +1,150 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+import {UniqueHelper, UniqueNFTCollection} from '@unique/playgrounds/unique.js';
+
+const collectionProps = [
+ {key: 'col-0', value: 'col-0-value'},
+ {key: 'col-1', value: 'col-1-value'},
+];
+
+const tokenProps = [
+ {key: 'tok-0', value: 'tok-0-value'},
+ {key: 'tok-1', value: 'tok-1-value'},
+];
+
+const tokPropPermission = {
+ mutable: false,
+ tokenOwner: true,
+ collectionAdmin: false,
+};
+
+const tokenPropPermissions = [
+ {
+ key: 'tok-0',
+ permission: tokPropPermission,
+ },
+ {
+ key: 'tok-1',
+ permission: tokPropPermission,
+ },
+];
+
+describe('query properties RPC', () => {
+ let alice: IKeyringPair;
+
+ const mintCollection = async (helper: UniqueHelper) => await helper.nft.mintCollection(alice, {
+ tokenPrefix: 'prps',
+ properties: collectionProps,
+ tokenPropertyPermissions: tokenPropPermissions,
+ });
+
+ const mintToken = async (collection: UniqueNFTCollection) => await collection.mintToken(alice, {Substrate: alice.address}, tokenProps);
+
+
+ before(async () => {
+ await usingPlaygrounds(async (_, privateKey) => {
+ alice = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itSub('query empty collection key set', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const props = await collection.getProperties([]);
+ expect(props).to.be.empty;
+ });
+
+ itSub('query empty token key set', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const token = await mintToken(collection);
+ const props = await token.getProperties([]);
+ expect(props).to.be.empty;
+ });
+
+ itSub('query empty token key permissions set', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const propPermissions = await collection.getPropertyPermissions([]);
+ expect(propPermissions).to.be.empty;
+ });
+
+ itSub('query all collection props by null arg', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const props = await collection.getProperties(null);
+ expect(props).to.be.deep.equal(collectionProps);
+ });
+
+ itSub('query all token props by null arg', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const token = await mintToken(collection);
+ const props = await token.getProperties(null);
+ expect(props).to.be.deep.equal(tokenProps);
+ });
+
+ itSub('query empty token key permissions by null arg', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const propPermissions = await collection.getPropertyPermissions(null);
+ expect(propPermissions).to.be.deep.equal(tokenPropPermissions);
+ });
+
+ itSub('query all collection props by undefined arg', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const props = await collection.getProperties();
+ expect(props).to.be.deep.equal(collectionProps);
+ });
+
+ itSub('query all token props by undefined arg', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const token = await mintToken(collection);
+ const props = await token.getProperties();
+ expect(props).to.be.deep.equal(tokenProps);
+ });
+
+ itSub('query empty token key permissions by undefined arg', async ({helper}) => {
+ const collection = await mintCollection(helper);
+ const propPermissions = await collection.getPropertyPermissions();
+ expect(propPermissions).to.be.deep.equal(tokenPropPermissions);
+ });
+});
+
+[
+ {mode: 'nft' as const},
+ {mode: 'rft' as const},
+].map(testCase =>
+ describe('negative properties', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (_, privateKey) => {
+ alice = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itSub(`[${testCase.mode}] set token property for non-existent token`, async ({helper}) => {
+ const collection = await helper[testCase.mode].mintCollection(alice);
+ await collection.setTokenPropertyPermissions(alice, [{key: 'key', permission: {mutable: true, tokenOwner: true, collectionAdmin: true}}]);
+ await expect(collection.setTokenProperties(alice, 1, [{key: 'key', value: 'value'}])).to.be.rejectedWith('common.TokenNotFound');
+ expect(await collection.getTokenProperties(1, ['key'])).to.be.empty;
+ });
+
+ itSub(`[${testCase.mode}] delete token property for non-existent token`, async ({helper}) => {
+ const collection = await helper[testCase.mode].mintCollection(alice);
+ await collection.setTokenPropertyPermissions(alice, [{key: 'key', permission: {mutable: true, tokenOwner: true, collectionAdmin: true}}]);
+ await expect(collection.deleteTokenProperties(alice, 1, ['key'])).to.be.rejectedWith('common.TokenNotFound');
+ expect(await collection.getTokenProperties(1, ['key'])).to.be.empty;
+ });
+ }));
js-packages/tests/governance/council.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/governance/council.test.ts
@@ -0,0 +1,457 @@
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';
+import type {ICounselors} from './util.js';
+
+describeGov('Governance: Council tests', () => {
+ let donor: IKeyringPair;
+ let counselors: ICounselors;
+ let sudoer: IKeyringPair;
+
+ const moreThanHalfCouncilThreshold = 3;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Council]);
+
+ donor = await privateKey({url: import.meta.url});
+ sudoer = await privateKey('//Alice');
+ });
+ });
+
+ beforeEach(async () => {
+ counselors = await initCouncil(donor, sudoer);
+ });
+
+ afterEach(async () => {
+ await clearCouncil(sudoer);
+ await clearTechComm(sudoer);
+ });
+
+ async function proposalFromMoreThanHalfCouncil(proposal: any) {
+ return await usingPlaygrounds(async (helper) => {
+ expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
+ const proposeResult = await helper.council.collective.propose(
+ counselors.filip,
+ proposal,
+ moreThanHalfCouncilThreshold,
+ );
+
+ const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+
+ await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
+
+ return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+ });
+ }
+
+ async function proposalFromAllCouncil(proposal: any) {
+ return await usingPlaygrounds(async (helper) => {
+ expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
+ const proposeResult = await helper.council.collective.propose(
+ counselors.filip,
+ proposal,
+ moreThanHalfCouncilThreshold,
+ );
+
+ const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+
+ await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.ildar, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.irina, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
+
+ return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+ });
+ }
+
+ itSub('>50% of Council can externally propose SuperMajorityAgainst', async ({helper}) => {
+ const forceSetBalanceReceiver = helper.arrange.createEmptyAccount();
+ const forceSetBalanceTestValue = 20n * 10n ** 25n;
+
+ const democracyProposal = await helper.constructApiCall('api.tx.balances.forceSetBalance', [
+ forceSetBalanceReceiver.address, forceSetBalanceTestValue,
+ ]);
+
+ const councilProposal = await helper.democracy.externalProposeDefaultCall(democracyProposal);
+
+ const proposeResult = await helper.council.collective.propose(
+ counselors.filip,
+ councilProposal,
+ moreThanHalfCouncilThreshold,
+ );
+
+ const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+ await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
+ await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
+
+ await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+
+ const democracyStartedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const democracyReferendumIndex = democracyStartedEvent.referendumIndex;
+ const democracyThreshold = democracyStartedEvent.threshold;
+
+ expect(democracyThreshold).to.be.equal('SuperMajorityAgainst');
+
+ await helper.democracy.vote(counselors.filip, democracyReferendumIndex, {
+ Standard: {
+ vote: {
+ aye: true,
+ conviction: 1,
+ },
+ balance: 10_000n,
+ },
+ });
+
+ await helper.democracy.vote(counselors.charu, democracyReferendumIndex, {
+ Standard: {
+ vote: {
+ aye: false,
+ conviction: 1,
+ },
+ balance: 50_000n,
+ },
+ });
+
+ const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
+ expect(passedReferendumEvent.referendumIndex).to.be.equal(democracyReferendumIndex);
+
+ await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
+ const receiverBalance = await helper.balance.getSubstrate(forceSetBalanceReceiver.address);
+ expect(receiverBalance).to.be.equal(forceSetBalanceTestValue);
+ });
+
+ itSub('Council prime member vote is the default', async ({helper}) => {
+ const newTechCommMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
+ const proposeResult = await helper.council.collective.propose(
+ counselors.filip,
+ addMemberProposal,
+ moreThanHalfCouncilThreshold,
+ );
+
+ const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+ await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+
+ await helper.wait.newBlocks(councilMotionDuration);
+ const closeResult = await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+ const closeEvent = Event.Council.Closed.expect(closeResult);
+ const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as string[];
+ expect(closeEvent.yes).to.be.equal(members.length);
+ });
+
+ itSub('Superuser can add a member', async ({helper}) => {
+ const newMember = helper.arrange.createEmptyAccount();
+ await expect(helper.getSudo().council.membership.addMember(sudoer, newMember.address)).to.be.fulfilled;
+
+ const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+ expect(members).to.contains(newMember.address);
+ });
+
+ itSub('Superuser can remove a member', async ({helper}) => {
+ await expect(helper.getSudo().council.membership.removeMember(sudoer, counselors.alex.address)).to.be.fulfilled;
+
+ const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+ expect(members).to.not.contains(counselors.alex.address);
+ });
+
+ itSub('>50% Council can add TechComm member', async ({helper}) => {
+ const newTechCommMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
+
+ await proposalFromMoreThanHalfCouncil(addMemberProposal);
+
+ const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+ expect(techCommMembers).to.contains(newTechCommMember.address);
+ });
+
+ itSub('Council can remove TechComm member', async ({helper}) => {
+ const techComm = await initTechComm(donor, sudoer);
+ const removeMemberPrpoposal = helper.technicalCommittee.membership.removeMemberCall(techComm.andy.address);
+ await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
+
+ const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+ expect(techCommMembers).to.not.contains(techComm.andy.address);
+ });
+
+ itSub.skip('Council member can add Fellowship member', async ({helper}) => {
+ const newFellowshipMember = helper.arrange.createEmptyAccount();
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
+ )).to.be.fulfilled;
+ const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
+ expect(fellowshipMembers).to.contains(newFellowshipMember.address);
+ });
+
+ itSub('>50% Council can promote Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const memberWithZeroRank = fellowship[0][0];
+
+ const proposal = helper.fellowship.collective.promoteCall(memberWithZeroRank.address);
+ await proposalFromMoreThanHalfCouncil(proposal);
+ const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithZeroRank.address])).toJSON();
+ expect(record).to.be.deep.equal({rank: 1});
+
+ await clearFellowship(sudoer);
+ });
+
+ itSub('>50% Council can demote Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const memberWithRankOne = fellowship[1][0];
+
+ const proposal = helper.fellowship.collective.demoteCall(memberWithRankOne.address);
+ await proposalFromMoreThanHalfCouncil(proposal);
+
+ const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithRankOne.address])).toJSON();
+ expect(record).to.be.deep.equal({rank: 0});
+
+ await clearFellowship(sudoer);
+ });
+
+ itSub('>50% Council can add\remove Fellowship member', async ({helper}) => {
+ try {
+ const newMember = helper.arrange.createEmptyAccount();
+
+ const proposalAdd = helper.fellowship.collective.addMemberCall(newMember.address);
+ const proposalRemove = helper.fellowship.collective.removeMemberCall(newMember.address, fellowshipRankLimit);
+ await expect(proposalFromMoreThanHalfCouncil(proposalAdd)).to.be.fulfilled;
+ expect(await helper.fellowship.collective.getMembers()).to.be.deep.contain(newMember.address);
+ await expect(proposalFromMoreThanHalfCouncil(proposalRemove)).to.be.fulfilled;
+ expect(await helper.fellowship.collective.getMembers()).to.be.not.deep.contain(newMember.address);
+ }
+ finally {
+ await clearFellowship(sudoer);
+ }
+ });
+
+ itSub('Council can blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash, null))).to.be.fulfilled;
+ });
+
+ itSub('Sudo can blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await expect(helper.getSudo().democracy.blacklist(sudoer, preimageHash)).to.be.fulfilled;
+ });
+
+ itSub('[Negative] Council cannot add Council member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+
+ await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejected;
+ });
+
+ itSub('[Negative] Council cannot remove Council member', async ({helper}) => {
+ const removeMemberProposal = helper.council.membership.removeMemberCall(counselors.alex.address);
+
+ await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejected;
+ });
+
+ itSub('[Negative] Council cannot submit regular democracy proposal', async ({helper}) => {
+ const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+ await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council cannot externally propose SimpleMajority', async ({helper}) => {
+ const councilProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ const councilProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council member cannot add/remove a Council member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.council.membership.addMemberCall(newCouncilMember.address),
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.council.membership.removeMemberCall(counselors.charu.address),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council cannot set/clear Council prime member', async ({helper}) => {
+ const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+ const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+ await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith(/BadOrigin/);
+ await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith(/BadOrigin/);
+
+ });
+
+ itSub('[Negative] Council member cannot set/clear Council prime member', async ({helper}) => {
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.council.membership.setPrimeCall(counselors.charu.address),
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.council.membership.clearPrimeCall(),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council member cannot add/remove a TechComm member', async ({helper}) => {
+ const newTechCommMember = helper.arrange.createEmptyAccount();
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address),
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.technicalCommittee.membership.removeMemberCall(newTechCommMember.address),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const memberWithRankOne = fellowship[1][0];
+
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.fellowship.collective.promoteCall(memberWithRankOne.address),
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.fellowship.collective.demoteCall(memberWithRankOne.address),
+ )).to.be.rejectedWith('BadOrigin');
+ await clearFellowship(sudoer);
+ });
+
+ itSub('[Negative] Council cannot fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))
+ .to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council member cannot fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council cannot cancel Democracy proposals', async ({helper}) => {
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))
+ .to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council member cannot cancel Democracy proposals', async ({helper}) => {
+
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.democracy.cancelProposalCall(proposalIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council cannot cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))
+ .to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council member cannot cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.democracy.emergencyCancelCall(referendumIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council cannot cancel Fellowship referendums', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const fellowshipProposer = fellowship[5][0];
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ fellowshipProposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+ await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))
+ .to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Council member cannot cancel Fellowship referendums', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const fellowshipProposer = fellowship[5][0];
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ fellowshipProposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.fellowship.referenda.cancelCall(referendumIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council referendum cannot be closed until the voting threshold is met', async ({helper}) => {
+ const councilSize = (await helper.callRpc('api.query.councilMembership.members')).toJSON().length as any as number;
+ expect(councilSize).is.greaterThan(1);
+ const proposeResult = await helper.council.collective.propose(
+ counselors.filip,
+ dummyProposalCall(helper),
+ councilSize,
+ );
+
+ const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+
+ await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+ await expect(helper.council.collective.close(counselors.filip, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
+ });
+
+});
js-packages/tests/governance/democracy.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/governance/democracy.test.ts
@@ -0,0 +1,89 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
+import {clearFellowship, democracyLaunchPeriod, democracyTrackMinRank, dummyProposalCall, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, fellowshipPreparePeriod, fellowshipPropositionOrigin, initFellowship, voteUnanimouslyInFellowship} from './util.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+
+describeGov('Governance: Democracy tests', () => {
+ let regularUser: IKeyringPair;
+ let donor: IKeyringPair;
+ let sudoer: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Democracy]);
+
+ donor = await privateKey({url: import.meta.url});
+ sudoer = await privateKey('//Alice');
+
+ [regularUser] = await helper.arrange.createAccounts([1000n], donor);
+ });
+ });
+
+ itSub('Regular user can vote', async ({helper}) => {
+ const fellows = await initFellowship(donor, sudoer);
+ const rank1Proposer = fellows[1][0];
+
+ const democracyProposalCall = dummyProposalCall(helper);
+ const fellowshipProposal = {
+ Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
+ };
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ rank1Proposer,
+ fellowshipPropositionOrigin,
+ fellowshipProposal,
+ {After: 0},
+ );
+
+ const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ await voteUnanimouslyInFellowship(helper, fellows, democracyTrackMinRank, fellowshipReferendumIndex);
+ await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
+
+ await helper.wait.expectEvent(
+ fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
+ Event.Democracy.Proposed,
+ );
+
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ const ayeBalance = 10_000n;
+
+ await helper.democracy.vote(regularUser, referendumIndex, {
+ Standard: {
+ vote: {
+ aye: true,
+ conviction: 1,
+ },
+ balance: ayeBalance,
+ },
+ });
+
+ const referendumInfo = await helper.democracy.referendumInfo(referendumIndex);
+ const tally = referendumInfo.ongoing.tally;
+
+ expect(BigInt(tally.ayes)).to.be.equal(ayeBalance);
+
+ await clearFellowship(sudoer);
+ });
+
+ itSub('[Negative] Regular user cannot submit a regular proposal', async ({helper}) => {
+ const submitResult = helper.democracy.propose(regularUser, dummyProposalCall(helper), 0n);
+ await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Regular user cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+ const submitResult = helper.democracy.externalProposeDefault(regularUser, dummyProposalCall(helper));
+ await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Regular user cannot externally propose SimpleMajority', async ({helper}) => {
+ const submitResult = helper.democracy.externalProposeMajority(regularUser, dummyProposalCall(helper));
+ await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Regular user cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ const submitResult = helper.democracy.externalPropose(regularUser, dummyProposalCall(helper));
+ await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+ });
+});
js-packages/tests/governance/fellowship.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/governance/fellowship.test.ts
@@ -0,0 +1,335 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
+import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
+import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, voteUnanimouslyInFellowship, democracyTrackMinRank, fellowshipPreparePeriod, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, democracyTrackId, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
+import type {ICounselors, ITechComms} from './util.js';
+
+describeGov('Governance: Fellowship tests', () => {
+ let members: IKeyringPair[][];
+
+ let rank1Proposer: IKeyringPair;
+
+ let sudoer: any;
+ let donor: any;
+ let counselors: ICounselors;
+ let techcomms: ITechComms;
+
+ const submissionDeposit = 1000n;
+
+ async function testBadFellowshipProposal(
+ helper: DevUniqueHelper,
+ proposalCall: any,
+ ) {
+ const badProposal = {
+ Inline: proposalCall.method.toHex(),
+ };
+ const submitResult = await helper.fellowship.referenda.submit(
+ rank1Proposer,
+ fellowshipPropositionOrigin,
+ badProposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, referendumIndex);
+ await helper.fellowship.referenda.placeDecisionDeposit(donor, referendumIndex);
+
+ const enactmentId = await helper.fellowship.referenda.enactmentEventId(referendumIndex);
+ const dispatchedEvent = await helper.wait.expectEvent(
+ fellowshipPreparePeriod + fellowshipConfirmPeriod + defaultEnactmentMoment.After,
+ Event.Scheduler.Dispatched,
+ (event: any) => event.id == enactmentId,
+ );
+
+ expect(dispatchedEvent.result.isErr, 'Bad Fellowship must fail')
+ .to.be.true;
+
+ expect(dispatchedEvent.result.asErr.isBadOrigin, 'Bad Fellowship must fail with BadOrigin')
+ .to.be.true;
+ }
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Fellowship, Pallets.TechnicalCommittee, Pallets.Council]);
+
+ sudoer = await privateKey('//Alice');
+ donor = await privateKey({url: import.meta.url});
+ });
+
+ counselors = await initCouncil(donor, sudoer);
+ techcomms = await initTechComm(donor, sudoer);
+ members = await initFellowship(donor, sudoer);
+
+ rank1Proposer = members[1][0];
+ });
+
+ after(async () => {
+ await clearFellowship(sudoer);
+ await clearTechComm(sudoer);
+ await clearCouncil(sudoer);
+ await hardResetFellowshipReferenda(sudoer);
+ await hardResetDemocracy(sudoer);
+ await hardResetGovScheduler(sudoer);
+ });
+
+ itSub('FellowshipProposition can submit regular Democracy proposals', async ({helper}) => {
+ const democracyProposalCall = dummyProposalCall(helper);
+ const fellowshipProposal = {
+ Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
+ };
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ rank1Proposer,
+ fellowshipPropositionOrigin,
+ fellowshipProposal,
+ defaultEnactmentMoment,
+ );
+
+ const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, fellowshipReferendumIndex);
+ await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
+
+ const democracyProposed = await helper.wait.expectEvent(
+ fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
+ Event.Democracy.Proposed,
+ );
+
+ const democracyEnqueuedProposal = await helper.democracy.expectPublicProposal(democracyProposed.proposalIndex);
+ expect(democracyEnqueuedProposal.inline, 'Fellowship proposal expected to be in the Democracy')
+ .to.be.equal(democracyProposalCall.method.toHex());
+
+ await helper.wait.newBlocks(democracyVotingPeriod);
+ });
+
+ itSub('Fellowship (rank-1 or greater) member can submit Fellowship proposals on the Democracy track', async ({helper}) => {
+ for(let rank = 1; rank < fellowshipRankLimit; rank++) {
+ const rankMembers = members[rank];
+
+ for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
+ const member = rankMembers[memberIdx];
+ const newDummyProposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ member,
+ fellowshipPropositionOrigin,
+ newDummyProposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+ expect(referendumInfo.ongoing.track, `${memberIdx}-th member of rank #${rank}: proposal #${referendumIndex} is on invalid track`)
+ .to.be.equal(democracyTrackId);
+ }
+ }
+ });
+
+ itSub(`Fellowship (rank-${democracyTrackMinRank} or greater) members can vote on the Democracy track`, async ({helper}) => {
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ rank1Proposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+ let expectedAyes = 0;
+ for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
+ const rankMembers = members[rank];
+
+ for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
+ const member = rankMembers[memberIdx];
+ await helper.fellowship.collective.vote(member, referendumIndex, true);
+ expectedAyes += 1;
+
+ const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+ expect(referendumInfo.ongoing.tally.bareAyes, `Vote from ${memberIdx}-th member of rank #${rank} isn't accounted`)
+ .to.be.equal(expectedAyes);
+ }
+ }
+ });
+
+ itSub('Fellowship rank vote strength is correct', async ({helper}) => {
+ const excessRankWeightTable = [
+ 1,
+ 3,
+ 6,
+ 10,
+ 15,
+ 21,
+ ];
+
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ rank1Proposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+ for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
+ const rankMembers = members[rank];
+
+ for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
+ const member = rankMembers[memberIdx];
+
+ const referendumInfoBefore = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+ const ayesBefore = referendumInfoBefore.ongoing.tally.ayes;
+
+ await helper.fellowship.collective.vote(member, referendumIndex, true);
+
+ const referendumInfoAfter = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+ const ayesAfter = referendumInfoAfter.ongoing.tally.ayes;
+
+ const expectedVoteWeight = excessRankWeightTable[rank - democracyTrackMinRank];
+ const voteWeight = ayesAfter - ayesBefore;
+
+ expect(voteWeight, `Vote weight of ${memberIdx}-th member of rank #${rank} is invalid`)
+ .to.be.equal(expectedVoteWeight);
+ }
+ }
+ });
+
+ itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+ await testBadFellowshipProposal(helper, helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper)));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot externally propose SimpleMajority', async ({helper}) => {
+ await testBadFellowshipProposal(helper, helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper)));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ await testBadFellowshipProposal(helper, helper.democracy.externalProposeCall(dummyProposalCall(helper)));
+ });
+
+ itSub('[Negative] Fellowship (rank-0) member cannot submit Fellowship proposals on the Democracy track', async ({helper}) => {
+ const rank0Proposer = members[0][0];
+
+ const proposal = dummyProposal(helper);
+
+ const submitResult = helper.fellowship.referenda.submit(
+ rank0Proposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+ });
+
+ itSub('[Negative] Fellowship (rank-1 or greater) member cannot submit if no deposit can be provided', async ({helper}) => {
+ const poorMember = rank1Proposer;
+
+ const balanceBefore = await helper.balance.getSubstrate(poorMember.address);
+ await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, submissionDeposit - 1n);
+
+ const proposal = dummyProposal(helper);
+
+ const submitResult = helper.fellowship.referenda.submit(
+ poorMember,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ await expect(submitResult).to.be.rejectedWith(/account balance too low/);
+
+ await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, balanceBefore);
+ });
+
+ itSub(`[Negative] Fellowship (rank-${democracyTrackMinRank - 1} or less) members cannot vote on the Democracy track`, async ({helper}) => {
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ rank1Proposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+ for(let rank = 0; rank < democracyTrackMinRank; rank++) {
+ for(const member of members[rank]) {
+ const voteResult = helper.fellowship.collective.vote(member, referendumIndex, true);
+ await expect(voteResult).to.be.rejectedWith(/RankTooLow/);
+ }
+ }
+ });
+
+ itSub('[Negative] FellowshipProposition cannot add/remove a Council member', async ({helper}) => {
+ const [councilNonMember] = await helper.arrange.createAccounts([10n], donor);
+
+ await testBadFellowshipProposal(helper, helper.council.membership.addMemberCall(councilNonMember.address));
+ await testBadFellowshipProposal(helper, helper.council.membership.removeMemberCall(counselors.ildar.address));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot set/clear Council prime member', async ({helper}) => {
+ await testBadFellowshipProposal(helper, helper.council.membership.setPrimeCall(counselors.ildar.address));
+ await testBadFellowshipProposal(helper, helper.council.membership.clearPrimeCall());
+ });
+
+ itSub('[Negative] FellowshipProposition cannot add/remove a TechComm member', async ({helper}) => {
+ const [techCommNonMember] = await helper.arrange.createAccounts([10n], donor);
+
+ await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.addMemberCall(techCommNonMember.address));
+ await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.removeMemberCall(techcomms.constantine.address));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot add/remove a Fellowship member', async ({helper}) => {
+ const [fellowshipNonMember] = await helper.arrange.createAccounts([10n], donor);
+
+ await testBadFellowshipProposal(helper, helper.fellowship.collective.addMemberCall(fellowshipNonMember.address));
+ await testBadFellowshipProposal(helper, helper.fellowship.collective.removeMemberCall(rank1Proposer.address, 1));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot promote/demote a Fellowship member', async ({helper}) => {
+ await testBadFellowshipProposal(helper, helper.fellowship.collective.promoteCall(rank1Proposer.address));
+ await testBadFellowshipProposal(helper, helper.fellowship.collective.demoteCall(rank1Proposer.address));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await testBadFellowshipProposal(helper, helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot cancel Democracy proposals', async ({helper}) => {
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ await testBadFellowshipProposal(helper, helper.democracy.cancelProposalCall(proposalIndex));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ await testBadFellowshipProposal(helper, helper.democracy.emergencyCancelCall(referendumIndex));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await testBadFellowshipProposal(helper, helper.democracy.blacklistCall(preimageHash, null));
+ });
+
+ itSub('[Negative] FellowshipProposition cannot veto external proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await testBadFellowshipProposal(helper, helper.democracy.vetoExternalCall(preimageHash));
+ });
+});
js-packages/tests/governance/init.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/governance/init.test.ts
@@ -0,0 +1,193 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, clearCouncil, clearTechComm, clearFellowship} from './util.js';
+import type {ICounselors, ITechComms} from './util.js';
+
+describeGov('Governance: Initialization', () => {
+ let donor: IKeyringPair;
+ let sudoer: IKeyringPair;
+ let counselors: ICounselors;
+ let techcomms: ITechComms;
+ let coreDevs: any;
+
+ const expectedAlexFellowRank = 7;
+ const expectedFellowRank = 6;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Council, Pallets.TechnicalCommittee]);
+
+ const councilMembers = await helper.council.membership.getMembers();
+ const techcommMembers = await helper.technicalCommittee.membership.getMembers();
+ expect(councilMembers.length == 0, 'The Council must be empty before the Gov Init');
+ expect(techcommMembers.length == 0, 'The Technical Commettee must be empty before the Gov Init');
+
+ donor = await privateKey({url: import.meta.url});
+ sudoer = await privateKey('//Alice');
+
+ const counselorsNum = 5;
+ const techCommsNum = 3;
+ const coreDevsNum = 2;
+ const [
+ alex,
+ ildar,
+ charu,
+ filip,
+ irina,
+
+ greg,
+ andy,
+ constantine,
+
+ yaroslav,
+ daniel,
+ ] = await helper.arrange.createAccounts(new Array(counselorsNum + techCommsNum + coreDevsNum).fill(10_000n), donor);
+
+ counselors = {
+ alex,
+ ildar,
+ charu,
+ filip,
+ irina,
+ };
+
+ techcomms = {
+ greg,
+ andy,
+ constantine,
+ };
+
+ coreDevs = {
+ yaroslav: yaroslav,
+ daniel: daniel,
+ };
+ });
+ });
+
+ itSub('Initialize Governance', async ({helper}) => {
+ const promoteFellow = (fellow: string, promotionsNum: number) => new Array(promotionsNum).fill(helper.fellowship.collective.promoteCall(fellow));
+
+ const expectFellowRank = async (fellow: string, expectedRank: number) => {
+ expect(await helper.fellowship.collective.getMemberRank(fellow)).to.be.equal(expectedRank);
+ };
+
+ console.log('\t- Setup the Prime of the Council via sudo');
+ await helper.getSudo().utility.batchAll(sudoer, [
+ helper.council.membership.addMemberCall(counselors.alex.address),
+ helper.council.membership.setPrimeCall(counselors.alex.address),
+
+ helper.fellowship.collective.addMemberCall(counselors.alex.address),
+ ...promoteFellow(counselors.alex.address, expectedAlexFellowRank),
+ ]);
+
+ let councilMembers = await helper.council.membership.getMembers();
+ const councilPrime = await helper.council.collective.getPrimeMember();
+ const alexFellowRank = await helper.fellowship.collective.getMemberRank(counselors.alex.address);
+ expect(councilMembers).to.be.deep.equal([counselors.alex.address]);
+ expect(councilPrime).to.be.equal(counselors.alex.address);
+ expect(alexFellowRank).to.be.equal(expectedAlexFellowRank);
+
+ console.log('\t- The Council Prime initializes the Technical Commettee');
+ const councilProposalThreshold = 1;
+
+ await helper.council.collective.propose(
+ counselors.alex,
+ helper.utility.batchAllCall([
+ helper.technicalCommittee.membership.addMemberCall(techcomms.greg.address),
+ helper.technicalCommittee.membership.addMemberCall(techcomms.andy.address),
+ helper.technicalCommittee.membership.addMemberCall(techcomms.constantine.address),
+
+ helper.technicalCommittee.membership.setPrimeCall(techcomms.greg.address),
+ ]),
+ councilProposalThreshold,
+ );
+
+ const techCommMembers = await helper.technicalCommittee.membership.getMembers();
+ const techCommPrime = await helper.technicalCommittee.membership.getPrimeMember();
+ const expectedTechComms = [techcomms.greg.address, techcomms.andy.address, techcomms.constantine.address];
+ expect(techCommMembers.length).to.be.equal(expectedTechComms.length);
+ expect(techCommMembers).to.containSubset(expectedTechComms);
+ expect(techCommPrime).to.be.equal(techcomms.greg.address);
+
+ console.log('\t- The Council Prime initiates a referendum to add counselors');
+ const returnPreimageHash = true;
+ const preimageHash = await helper.preimage.notePreimageFromCall(counselors.alex, helper.utility.batchAllCall([
+ helper.council.membership.addMemberCall(counselors.ildar.address),
+ helper.council.membership.addMemberCall(counselors.charu.address),
+ helper.council.membership.addMemberCall(counselors.filip.address),
+ helper.council.membership.addMemberCall(counselors.irina.address),
+
+ helper.fellowship.collective.addMemberCall(counselors.charu.address),
+ helper.fellowship.collective.addMemberCall(counselors.ildar.address),
+ helper.fellowship.collective.addMemberCall(counselors.irina.address),
+ helper.fellowship.collective.addMemberCall(counselors.filip.address),
+ helper.fellowship.collective.addMemberCall(techcomms.greg.address),
+ helper.fellowship.collective.addMemberCall(techcomms.andy.address),
+ helper.fellowship.collective.addMemberCall(techcomms.constantine.address),
+ helper.fellowship.collective.addMemberCall(coreDevs.yaroslav.address),
+ helper.fellowship.collective.addMemberCall(coreDevs.daniel.address),
+
+ ...promoteFellow(counselors.charu.address, expectedFellowRank),
+ ...promoteFellow(counselors.ildar.address, expectedFellowRank),
+ ...promoteFellow(counselors.irina.address, expectedFellowRank),
+ ...promoteFellow(counselors.filip.address, expectedFellowRank),
+ ...promoteFellow(techcomms.greg.address, expectedFellowRank),
+ ...promoteFellow(techcomms.andy.address, expectedFellowRank),
+ ...promoteFellow(techcomms.constantine.address, expectedFellowRank),
+ ...promoteFellow(coreDevs.yaroslav.address, expectedFellowRank),
+ ...promoteFellow(coreDevs.daniel.address, expectedFellowRank),
+ ]), returnPreimageHash);
+
+ await helper.council.collective.propose(
+ counselors.alex,
+ helper.democracy.externalProposeDefaultWithPreimageCall(preimageHash),
+ councilProposalThreshold,
+ );
+
+ console.log('\t- The referendum is being decided');
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+
+ await helper.democracy.vote(counselors.filip, startedEvent.referendumIndex, {
+ Standard: {
+ vote: {
+ aye: true,
+ conviction: 1,
+ },
+ balance: 10_000n,
+ },
+ });
+
+ const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
+ expect(passedReferendumEvent.referendumIndex).to.be.equal(startedEvent.referendumIndex);
+
+ await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
+
+ councilMembers = await helper.council.membership.getMembers();
+ const expectedCounselors = [
+ counselors.alex.address,
+ counselors.ildar.address,
+ counselors.charu.address,
+ counselors.filip.address,
+ counselors.irina.address,
+ ];
+ expect(councilMembers.length).to.be.equal(expectedCounselors.length);
+ expect(councilMembers).to.containSubset(expectedCounselors);
+
+ await expectFellowRank(counselors.ildar.address, expectedFellowRank);
+ await expectFellowRank(counselors.charu.address, expectedFellowRank);
+ await expectFellowRank(counselors.filip.address, expectedFellowRank);
+ await expectFellowRank(counselors.irina.address, expectedFellowRank);
+ await expectFellowRank(techcomms.greg.address, expectedFellowRank);
+ await expectFellowRank(techcomms.andy.address, expectedFellowRank);
+ await expectFellowRank(techcomms.constantine.address, expectedFellowRank);
+ await expectFellowRank(coreDevs.yaroslav.address, expectedFellowRank);
+ await expectFellowRank(coreDevs.daniel.address, expectedFellowRank);
+ });
+
+ after(async function() {
+ await clearFellowship(sudoer);
+ await clearTechComm(sudoer);
+ await clearCouncil(sudoer);
+ });
+});
js-packages/tests/governance/technicalCommittee.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/governance/technicalCommittee.test.ts
@@ -0,0 +1,383 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {initCouncil, democracyLaunchPeriod, democracyFastTrackVotingPeriod, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
+import type {ITechComms} from './util.js';
+
+describeGov('Governance: Technical Committee tests', () => {
+ let sudoer: IKeyringPair;
+ let techcomms: ITechComms;
+ let donor: IKeyringPair;
+ let preImageHash: string;
+
+
+ const allTechCommitteeThreshold = 3;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.TechnicalCommittee]);
+ sudoer = await privateKey('//Alice');
+ donor = await privateKey({url: import.meta.url});
+
+ techcomms = await initTechComm(donor, sudoer);
+
+ const proposalCall = await helper.constructApiCall('api.tx.balances.forceSetBalance', [donor.address, 20n * 10n ** 25n]);
+ preImageHash = await helper.preimage.notePreimageFromCall(sudoer, proposalCall, true);
+ });
+ });
+
+ after(async () => {
+ await usingPlaygrounds(async (helper) => {
+ await clearTechComm(sudoer);
+
+ await helper.preimage.unnotePreimage(sudoer, preImageHash);
+ await hardResetFellowshipReferenda(sudoer);
+ await hardResetDemocracy(sudoer);
+ await hardResetGovScheduler(sudoer);
+ });
+ });
+
+ function proposalFromAllCommittee(proposal: any) {
+ return usingPlaygrounds(async (helper) => {
+ expect((await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length).to.be.equal(allTechCommitteeThreshold);
+ const proposeResult = await helper.technicalCommittee.collective.propose(
+ techcomms.andy,
+ proposal,
+ allTechCommitteeThreshold,
+ );
+
+ const commiteeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
+ const proposalIndex = commiteeProposedEvent.proposalIndex;
+ const proposalHash = commiteeProposedEvent.proposalHash;
+
+
+ await helper.technicalCommittee.collective.vote(techcomms.andy, proposalHash, proposalIndex, true);
+ await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
+ await helper.technicalCommittee.collective.vote(techcomms.greg, proposalHash, proposalIndex, true);
+
+ const closeResult = await helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex);
+ Event.TechnicalCommittee.Closed.expect(closeResult);
+ Event.TechnicalCommittee.Approved.expect(closeResult);
+ const {result} = Event.TechnicalCommittee.Executed.expect(closeResult);
+ expect(result).to.eq('Ok');
+
+ return closeResult;
+ });
+ }
+
+ itSub('TechComm can fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.wait.parachainBlockMultiplesOf(35n);
+
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ const fastTrackProposal = await proposalFromAllCommittee(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
+ Event.Democracy.Started.expect(fastTrackProposal);
+ });
+
+ itSub('TechComm can cancel Democracy proposals', async ({helper}) => {
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ const cancelProposal = await proposalFromAllCommittee(helper.democracy.cancelProposalCall(proposalIndex));
+ Event.Democracy.ProposalCanceled.expect(cancelProposal);
+ });
+
+ itSub('TechComm can cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ const emergencyCancelProposal = await proposalFromAllCommittee(helper.democracy.emergencyCancelCall(referendumIndex));
+ Event.Democracy.Cancelled.expect(emergencyCancelProposal);
+ });
+
+ itSub('TechComm member can veto Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ const vetoExternalCall = await helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.democracy.vetoExternalCall(preimageHash),
+ );
+ Event.Democracy.Vetoed.expect(vetoExternalCall);
+ });
+
+ itSub('TechComm can cancel Fellowship referendums', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const fellowshipProposer = fellowship[5][0];
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ fellowshipProposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ const cancelProposal = await proposalFromAllCommittee(helper.fellowship.referenda.cancelCall(referendumIndex));
+ Event.FellowshipReferenda.Cancelled.expect(cancelProposal);
+ });
+
+ itSub.skip('TechComm member can add a Fellowship member', async ({helper}) => {
+ const newFellowshipMember = helper.arrange.createEmptyAccount();
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
+ )).to.be.fulfilled;
+ const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
+ expect(fellowshipMembers).to.contains(newFellowshipMember.address);
+ await clearFellowship(sudoer);
+ });
+
+ itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
+ const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+ await expect(proposalFromAllCommittee(councilProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+ const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm cannot externally propose SimpleMajority', async ({helper}) => {
+ const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot submit regular democracy proposal', async ({helper}) => {
+ const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+ const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot externally propose SimpleMajority', async ({helper}) => {
+ const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+
+ itSub.skip('[Negative] TechComm cannot promote/demote Fellowship member', async () => {
+
+ });
+
+ itSub.skip('[Negative] TechComm member cannot promote/demote Fellowship member', async () => {
+
+ });
+
+ itSub('[Negative] TechComm cannot add/remove a Council member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
+
+ await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot add/remove a Council member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ addMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ removeMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm cannot set/clear Council prime member', async ({helper}) => {
+ const counselors = await initCouncil(donor, sudoer);
+ const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+ const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+ await expect(proposalFromAllCommittee(proposalForSet)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCommittee(proposalForClear)).to.be.rejectedWith('BadOrigin');
+ await clearCouncil(sudoer);
+ });
+
+ itSub('[Negative] TechComm member cannot set/clear Council prime member', async ({helper}) => {
+ const counselors = await initCouncil(donor, sudoer);
+ const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+ const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ proposalForSet,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ proposalForClear,
+ )).to.be.rejectedWith('BadOrigin');
+ await clearCouncil(sudoer);
+ });
+
+ itSub('[Negative] TechComm cannot add/remove a TechComm member', async ({helper}) => {
+ const newCommMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
+
+ await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot add/remove a TechComm member', async ({helper}) => {
+ const newCommMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ addMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ removeMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm cannot remove a Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+
+ await expect(proposalFromAllCommittee(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');
+ await clearFellowship(sudoer);
+ });
+
+ itSub('[Negative] TechComm member cannot remove a Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),
+ )).to.be.rejectedWith('BadOrigin');
+ await clearFellowship(sudoer);
+ });
+
+ itSub('[Negative] TechComm member cannot fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot cancel Democracy proposals', async ({helper}) => {
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.democracy.cancelProposalCall(proposalIndex),
+ ))
+ .to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.democracy.emergencyCancelCall(referendumIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm cannot blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(proposalFromAllCommittee(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.democracy.blacklistCall(preimageHash),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub.skip('[Negative] TechComm member cannot veto external Democracy proposals until the cool-off period pass', async () => {
+
+ });
+
+ itSub('[Negative] TechComm member cannot cancel Fellowship referendums', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const fellowshipProposer = fellowship[5][0];
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ fellowshipProposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.andy,
+ helper.fellowship.referenda.cancelCall(referendumIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm referendum cannot be closed until the voting threshold is met', async ({helper}) => {
+ const committeeSize = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length as any as number;
+ expect(committeeSize).is.greaterThan(1);
+ const proposeResult = await helper.technicalCommittee.collective.propose(
+ techcomms.andy,
+ dummyProposalCall(helper),
+ committeeSize,
+ );
+
+ const committeeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
+ const proposalIndex = committeeProposedEvent.proposalIndex;
+ const proposalHash = committeeProposedEvent.proposalHash;
+
+ await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
+
+ await expect(helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
+ });
+});
js-packages/tests/governance/util.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/governance/util.ts
@@ -0,0 +1,224 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {xxhashAsHex} from '@polkadot/util-crypto';
+import type {u32} from '@polkadot/types-codec';
+import {usingPlaygrounds, expect} from '../util/index.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+import {DevUniqueHelper} from '@unique/playgrounds/unique.dev.js';
+
+export const democracyLaunchPeriod = 35;
+export const democracyVotingPeriod = 35;
+export const councilMotionDuration = 35;
+export const democracyEnactmentPeriod = 40;
+export const democracyFastTrackVotingPeriod = 5;
+
+export const fellowshipRankLimit = 7;
+export const fellowshipPropositionOrigin = 'FellowshipProposition';
+export const fellowshipPreparePeriod = 3;
+export const fellowshipConfirmPeriod = 3;
+export const fellowshipMinEnactPeriod = 1;
+
+export const defaultEnactmentMoment = {After: 0};
+
+export const democracyTrackId = 10;
+export const democracyTrackMinRank = 3;
+const twox128 = (data: any) => xxhashAsHex(data, 128);
+export interface ICounselors {
+ alex: IKeyringPair;
+ ildar: IKeyringPair;
+ charu: IKeyringPair;
+ filip: IKeyringPair;
+ irina: IKeyringPair;
+}
+export interface ITechComms {
+ greg: IKeyringPair;
+ andy: IKeyringPair;
+ constantine: IKeyringPair;
+}
+
+export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
+ let counselors: IKeyringPair[] = [];
+
+ await usingPlaygrounds(async (helper) => {
+ const [alex, ildar, charu, filip, irina] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n, 10_000n, 10_000n], donor);
+ const sudo = helper.getSudo();
+ {
+ const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as [];
+ if(members.length != 0) {
+ await clearCouncil(superuser);
+ }
+ }
+ const expectedMembers = [alex, ildar, charu, filip, irina];
+ for(const member of expectedMembers) {
+ await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.addMember', [member.address]);
+ }
+ await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.setPrime', [alex.address]);
+ {
+ const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+ expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
+ expect(members.length).to.be.equal(expectedMembers.length);
+ }
+
+ counselors = [alex, ildar, charu, filip, irina];
+ });
+ return {
+ alex: counselors[0],
+ ildar: counselors[1],
+ charu: counselors[2],
+ filip: counselors[3],
+ irina: counselors[4],
+ };
+}
+
+export async function clearCouncil(superuser: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ let members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+ if(members.length) {
+ const sudo = helper.getSudo();
+ for(const address of members) {
+ await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.removeMember', [address]);
+ }
+ members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+ }
+ expect(members).to.be.deep.equal([]);
+ });
+}
+
+
+export async function initTechComm(donor: IKeyringPair, superuser: IKeyringPair) {
+ let techcomms: IKeyringPair[] = [];
+
+ await usingPlaygrounds(async (helper) => {
+ const [greg, andy, constantine] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
+ const sudo = helper.getSudo();
+ {
+ const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON() as [];
+ if(members.length != 0) {
+ await clearTechComm(superuser);
+ }
+ }
+ await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [greg.address]);
+ await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [andy.address]);
+ await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [constantine.address]);
+ await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.setPrime', [greg.address]);
+ {
+ const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+ expect(members).to.containSubset([greg.address, andy.address, constantine.address]);
+ expect(members.length).to.be.equal(3);
+ }
+
+ techcomms = [greg, andy, constantine];
+ });
+
+ return {
+ greg: techcomms[0],
+ andy: techcomms[1],
+ constantine: techcomms[2],
+ };
+}
+
+export async function clearTechComm(superuser: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ let members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+ if(members.length) {
+ const sudo = helper.getSudo();
+ for(const address of members) {
+ await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.removeMember', [address]);
+ }
+ members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+ }
+ expect(members).to.be.deep.equal([]);
+ });
+}
+
+export async function initFellowship(donor: IKeyringPair, sudoer: IKeyringPair) {
+ const numMembersInRank = 3;
+ const memberBalance = 5000n;
+ const members: IKeyringPair[][] = [];
+
+ await usingPlaygrounds(async (helper) => {
+ const currentFellows = await helper.getApi().query.fellowshipCollective.members.keys();
+
+ if(currentFellows.length != 0) {
+ await clearFellowship(sudoer);
+ }
+ for(let i = 0; i < fellowshipRankLimit; i++) {
+ const rankMembers = await helper.arrange.createAccounts(
+ Array(numMembersInRank).fill(memberBalance),
+ donor,
+ );
+
+ for(const member of rankMembers) {
+ await helper.getSudo().fellowship.collective.addMember(sudoer, member.address);
+
+ for(let rank = 0; rank < i; rank++) {
+ await helper.getSudo().fellowship.collective.promote(sudoer, member.address);
+ }
+ }
+
+ members.push(rankMembers);
+ }
+ });
+
+ return members;
+}
+
+export async function clearFellowship(sudoer: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ const fellowship = (await helper.getApi().query.fellowshipCollective.members.keys())
+ .map((key) => key.args[0].toString());
+ for(const member of fellowship) {
+ await helper.getSudo().fellowship.collective.removeMember(sudoer, member, fellowshipRankLimit);
+ }
+ });
+}
+
+export async function clearFellowshipReferenda(sudoer: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ const proposalsCount = (await helper.getApi().query.fellowshipReferenda.referendumCount()) as u32;
+ for(let i = 0; i < proposalsCount.toNumber(); i++) {
+ await helper.getSudo().fellowship.referenda.cancel(sudoer, i);
+ }
+ });
+}
+
+export async function hardResetFellowshipReferenda(sudoer: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ const api = helper.getApi();
+ const prefix = twox128('FellowshipReferenda');
+ await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
+ });
+}
+
+export async function hardResetDemocracy(sudoer: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ const api = helper.getApi();
+ const prefix = twox128('Democracy');
+ await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
+ });
+}
+
+export async function hardResetGovScheduler(sudoer: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ const api = helper.getApi();
+ const prefix = twox128('GovScheduler');
+ await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 500)));
+ });
+}
+
+export async function voteUnanimouslyInFellowship(helper: DevUniqueHelper, fellows: IKeyringPair[][], minRank: number, referendumIndex: number) {
+ for(let rank = minRank; rank < fellowshipRankLimit; rank++) {
+ for(const member of fellows[rank]) {
+ await helper.fellowship.collective.vote(member, referendumIndex, true);
+ }
+ }
+}
+
+export function dummyProposalCall(helper: UniqueHelper) {
+ return helper.constructApiCall('api.tx.system.remark', ['dummy proposal' + (new Date()).getTime()]);
+}
+
+export function dummyProposal(helper: UniqueHelper) {
+ return {
+ Inline: dummyProposalCall(helper).method.toHex(),
+ };
+}
js-packages/tests/inflation.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/inflation.seqtest.ts
@@ -0,0 +1,58 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from './util/index.js';
+
+// todo:playgrounds requires sudo, look into on the later stage
+describe('integration test: Inflation', () => {
+ let superuser: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (_, privateKey) => {
+ superuser = await privateKey('//Alice');
+ });
+ });
+
+ itSub('First year inflation is 10%', async ({helper}) => {
+ // Make sure non-sudo can't start inflation
+ const [bob] = await helper.arrange.createAccounts([10n], superuser);
+
+ await expect(helper.executeExtrinsic(bob, 'api.tx.inflation.startInflation', [1])).to.be.rejectedWith(/BadOrigin/);
+
+ // Make sure superuser can't start inflation without explicit sudo
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.inflation.startInflation', [1])).to.be.rejectedWith(/BadOrigin/);
+
+ // Start inflation on relay block 1 (Alice is sudo)
+ const tx = helper.constructApiCall('api.tx.inflation.startInflation', [1]);
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [tx])).to.not.be.rejected;
+
+ const blockInterval = (helper.getApi().consts.inflation.inflationBlockInterval as any).toBigInt();
+ const totalIssuanceStart = ((await helper.callRpc('api.query.inflation.startingYearTotalIssuance', [])) as any).toBigInt();
+ const blockInflation = (await helper.callRpc('api.query.inflation.blockInflation', []) as any).toBigInt();
+
+ const YEAR = 5259600n; // 6-second block. Blocks in one year
+ // const YEAR = 2629800n; // 12-second block. Blocks in one year
+
+ const totalExpectedInflation = totalIssuanceStart / 10n;
+ const totalActualInflation = blockInflation * YEAR / blockInterval;
+
+ const tolerance = 0.00001; // Relative difference per year between theoretical and actual inflation
+ const expectedInflation = totalExpectedInflation / totalActualInflation - 1n;
+
+ expect(Math.abs(Number(expectedInflation))).to.be.lessThanOrEqual(tolerance);
+ });
+});
js-packages/tests/limits.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/limits.test.ts
@@ -0,0 +1,474 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util/index.js';
+
+describe('Number of tokens per address (NFT)', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itSub.skip('Collection limits allow greater number than chain limits, chain limits are enforced', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 20});
+
+ for(let i = 0; i < 10; i++){
+ await expect(collection.mintToken(alice)).to.be.not.rejected;
+ }
+ await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
+ for(let i = 1; i < 11; i++) {
+ await expect(collection.burnToken(alice, i)).to.be.not.rejected;
+ }
+ await collection.burn(alice);
+ });
+
+ itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 1});
+
+ await collection.mintToken(alice);
+ await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
+
+ await collection.burnToken(alice, 1);
+ await expect(collection.burn(alice)).to.be.not.rejected;
+ });
+});
+
+describe('Number of tokens per address (ReFungible)', () => {
+ let alice: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itSub.skip('Collection limits allow greater number than chain limits, chain limits are enforced', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 20});
+
+ for(let i = 0; i < 10; i++){
+ await expect(collection.mintToken(alice, 10n)).to.be.not.rejected;
+ }
+ await expect(collection.mintToken(alice, 10n)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
+ for(let i = 1; i < 11; i++) {
+ await expect(collection.burnToken(alice, i, 10n)).to.be.not.rejected;
+ }
+ await collection.burn(alice);
+ });
+
+ itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 1});
+
+ await collection.mintToken(alice);
+ await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
+
+ await collection.burnToken(alice, 1);
+ await expect(collection.burn(alice)).to.be.not.rejected;
+ });
+});
+
+// todo:playgrounds skipped ~ postponed
+describe.skip('Sponsor timeout (NFT) (only for special chain limits test)', () => {
+ /*let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ alice = privateKeyWrapper('//Alice');
+ bob = privateKeyWrapper('//Bob');
+ charlie = privateKeyWrapper('//Charlie');
+ });
+ });
+
+ itSub.skip('Collection limits have greater timeout value than chain limits, collection limits are enforced', async ({helper}) => {
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 7});
+ const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
+ await transferExpectSuccess(collectionId, tokenId, alice, bob);
+ const aliceBalanceBefore = await getFreeBalance(alice);
+
+ // check setting SponsorTimeout = 5, fail
+ await waitNewBlocks(5);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie);
+ const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
+
+ // check setting SponsorTimeout = 7, success
+ await waitNewBlocks(2); // 5 + 2
+ await transferExpectSuccess(collectionId, tokenId, charlie, bob);
+ const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
+ //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
+ await destroyCollectionExpectSuccess(collectionId);
+ });
+
+ itSub('Collection limits have lower timeout value than chain limits, chain limits are enforced', async ({helper}) => {
+
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 1});
+ const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
+ await transferExpectSuccess(collectionId, tokenId, alice, bob);
+ const aliceBalanceBefore = await getFreeBalance(alice);
+
+ // check setting SponsorTimeout = 1, fail
+ await waitNewBlocks(1);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie);
+ const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
+
+ // check setting SponsorTimeout = 5, success
+ await waitNewBlocks(4);
+ await transferExpectSuccess(collectionId, tokenId, charlie, bob);
+ const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
+ //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
+ await destroyCollectionExpectSuccess(collectionId);
+ });
+});
+
+describe.skip('Sponsor timeout (Fungible) (only for special chain limits test)', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ alice = privateKeyWrapper('//Alice');
+ bob = privateKeyWrapper('//Bob');
+ charlie = privateKeyWrapper('//Charlie');
+ });
+ });
+
+ itSub('Collection limits have greater timeout value than chain limits, collection limits are enforced', async ({helper}) => {
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 7});
+ const tokenId = await createItemExpectSuccess(alice, collectionId, 'Fungible');
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
+ await transferExpectSuccess(collectionId, tokenId, alice, bob, 10, 'Fungible');
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
+ const aliceBalanceBefore = await getFreeBalance(alice);
+
+ // check setting SponsorTimeout = 5, fail
+ await waitNewBlocks(5);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
+ const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
+
+ // check setting SponsorTimeout = 7, success
+ await waitNewBlocks(2); // 5 + 2
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
+ const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
+ //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
+
+ await destroyCollectionExpectSuccess(collectionId);
+ });
+
+ itSub('Collection limits have lower timeout value than chain limits, chain limits are enforced', async ({helper}) => {
+
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 1});
+ const tokenId = await createItemExpectSuccess(alice, collectionId, 'Fungible');
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
+ await transferExpectSuccess(collectionId, tokenId, alice, bob, 10, 'Fungible');
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
+ const aliceBalanceBefore = await getFreeBalance(alice);
+
+ // check setting SponsorTimeout = 1, fail
+ await waitNewBlocks(1);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
+ const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
+
+ // check setting SponsorTimeout = 5, success
+ await waitNewBlocks(4);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
+ const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
+ //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
+
+ await destroyCollectionExpectSuccess(collectionId);
+ });
+});
+
+describe.skip('Sponsor timeout (ReFungible) (only for special chain limits test)', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ alice = privateKeyWrapper('//Alice');
+ bob = privateKeyWrapper('//Bob');
+ charlie = privateKeyWrapper('//Charlie');
+ });
+ });
+
+ itSub('Collection limits have greater timeout value than chain limits, collection limits are enforced', async ({helper}) => {
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 7});
+ const tokenId = await createItemExpectSuccess(alice, collectionId, 'ReFungible');
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
+ await transferExpectSuccess(collectionId, tokenId, alice, bob, 100, 'ReFungible');
+ const aliceBalanceBefore = await getFreeBalance(alice);
+
+ // check setting SponsorTimeout = 5, fail
+ await waitNewBlocks(5);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 20, 'ReFungible');
+ const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
+
+ // check setting SponsorTimeout = 7, success
+ await waitNewBlocks(2); // 5 + 2
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie, 20, 'ReFungible');
+ const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
+ //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
+ await destroyCollectionExpectSuccess(collectionId);
+ });
+
+ itSub('Collection limits have lower timeout value than chain limits, chain limits are enforced', async ({helper}) => {
+
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 1});
+ const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
+ await transferExpectSuccess(collectionId, tokenId, alice, bob);
+ const aliceBalanceBefore = await getFreeBalance(alice);
+
+ // check setting SponsorTimeout = 1, fail
+ await waitNewBlocks(1);
+ await transferExpectSuccess(collectionId, tokenId, bob, charlie);
+ const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
+
+ // check setting SponsorTimeout = 5, success
+ await waitNewBlocks(4);
+ await transferExpectSuccess(collectionId, tokenId, charlie, bob);
+ const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
+ expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
+ //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
+ await destroyCollectionExpectSuccess(collectionId);
+ });*/
+});
+
+describe('Collection zero limits (NFT)', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itSub.skip('Limits have 0 in tokens per address field, the chain limits are applied', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 0});
+
+ for(let i = 0; i < 10; i++){
+ await collection.mintToken(alice);
+ }
+ await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
+ });
+
+ itSub('Limits have 0 in sponsor timeout, no limits are applied', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setLimits(alice, {sponsorTransferTimeout: 0});
+ const token = await collection.mintToken(alice);
+
+ await collection.setSponsor(alice, alice.address);
+ await collection.confirmSponsorship(alice);
+
+ await token.transfer(alice, {Substrate: bob.address});
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+
+ // check setting SponsorTimeout = 0, success with next block
+ await helper.wait.newBlocks(1);
+ await token.transfer(bob, {Substrate: charlie.address});
+ const aliceBalanceAfterSponsoredTransaction1 = await helper.balance.getSubstrate(alice.address);
+ expect(aliceBalanceAfterSponsoredTransaction1 < aliceBalanceBefore).to.be.true;
+ });
+});
+
+describe('Collection zero limits (Fungible)', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('Limits have 0 in sponsor timeout, no limits are applied', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {});
+ await collection.setLimits(alice, {sponsorTransferTimeout: 0});
+ await collection.mint(alice, 3n);
+
+ await collection.setSponsor(alice, alice.address);
+ await collection.confirmSponsorship(alice);
+
+ await collection.transfer(alice, {Substrate: bob.address}, 2n);
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+
+ // check setting SponsorTimeout = 0, success with next block
+ await helper.wait.newBlocks(1);
+ await collection.transfer(bob, {Substrate: charlie.address});
+ const aliceBalanceAfterSponsoredTransaction1 = await helper.balance.getSubstrate(alice.address);
+ expect(aliceBalanceAfterSponsoredTransaction1 < aliceBalanceBefore).to.be.true;
+ });
+});
+
+describe('Collection zero limits (ReFungible)', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ });
+ });
+
+ itSub.skip('Limits have 0 in tokens per address field, the chain limits are applied', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ await collection.setLimits(alice, {accountTokenOwnershipLimit: 0});
+ for(let i = 0; i < 10; i++){
+ await collection.mintToken(alice);
+ }
+ await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
+ });
+
+ itSub('Limits have 0 in sponsor timeout, no limits are applied', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ await collection.setLimits(alice, {sponsorTransferTimeout: 0});
+ const token = await collection.mintToken(alice, 3n);
+
+ await collection.setSponsor(alice, alice.address);
+ await collection.confirmSponsorship(alice);
+
+ await token.transfer(alice, {Substrate: bob.address}, 2n);
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+
+ // check setting SponsorTimeout = 0, success with next block
+ await helper.wait.newBlocks(1);
+ await token.transfer(bob, {Substrate: charlie.address});
+ const aliceBalanceAfterSponsoredTransaction1 = await helper.balance.getSubstrate(alice.address);
+ expect(aliceBalanceAfterSponsoredTransaction1 < aliceBalanceBefore).to.be.true;
+ });
+});
+
+describe('Effective collection limits (NFT)', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itSub('Effective collection limits', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {});
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+
+ {
+ // Check that limits are undefined
+ const collectionInfo = await collection.getData();
+ const limits = collectionInfo?.raw.limits;
+ expect(limits).to.be.any;
+
+ expect(limits.accountTokenOwnershipLimit).to.be.null;
+ expect(limits.sponsoredDataSize).to.be.null;
+ expect(limits.sponsoredDataRateLimit).to.be.null;
+ expect(limits.tokenLimit).to.be.null;
+ expect(limits.sponsorTransferTimeout).to.be.null;
+ expect(limits.sponsorApproveTimeout).to.be.null;
+ expect(limits.ownerCanTransfer).to.be.true;
+ expect(limits.ownerCanDestroy).to.be.null;
+ expect(limits.transfersEnabled).to.be.null;
+ }
+
+ { // Check that limits is undefined for non-existent collection
+ const limits = await helper.collection.getEffectiveLimits(999999);
+ expect(limits).to.be.null;
+ }
+
+ { // Check that default values defined for collection limits
+ const limits = await collection.getEffectiveLimits();
+
+ expect(limits.accountTokenOwnershipLimit).to.be.eq(100000);
+ expect(limits.sponsoredDataSize).to.be.eq(2048);
+ expect(limits.sponsoredDataRateLimit).to.be.deep.eq({sponsoringDisabled: null});
+ expect(limits.tokenLimit).to.be.eq(4294967295);
+ expect(limits.sponsorTransferTimeout).to.be.eq(5);
+ expect(limits.sponsorApproveTimeout).to.be.eq(5);
+ expect(limits.ownerCanTransfer).to.be.true;
+ expect(limits.ownerCanDestroy).to.be.true;
+ expect(limits.transfersEnabled).to.be.true;
+ }
+
+ {
+ // Check the values for collection limits
+ await collection.setLimits(alice, {
+ accountTokenOwnershipLimit: 99_999,
+ sponsoredDataSize: 1024,
+ tokenLimit: 123,
+ transfersEnabled: false,
+ });
+
+ const limits = await collection.getEffectiveLimits();
+
+ expect(limits.accountTokenOwnershipLimit).to.be.eq(99999);
+ expect(limits.sponsoredDataSize).to.be.eq(1024);
+ expect(limits.sponsoredDataRateLimit).to.be.deep.eq({sponsoringDisabled: null});
+ expect(limits.tokenLimit).to.be.eq(123);
+ expect(limits.sponsorTransferTimeout).to.be.eq(5);
+ expect(limits.sponsorApproveTimeout).to.be.eq(5);
+ expect(limits.ownerCanTransfer).to.be.true;
+ expect(limits.ownerCanDestroy).to.be.true;
+ expect(limits.transfersEnabled).to.be.false;
+ }
+ });
+});
js-packages/tests/maintenance.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/maintenance.seqtest.ts
@@ -0,0 +1,348 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {ApiPromise} from '@polkadot/api';
+import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util/index.js';
+import {itEth} from './eth/util/index.js';
+import {main as correctState} from './migrations/correctStateAfterMaintenance.js';
+import type {PalletBalancesIdAmount} from '@polkadot/types/lookup';
+import type {Vec} from '@polkadot/types-codec';
+
+async function maintenanceEnabled(api: ApiPromise): Promise<boolean> {
+ return (await api.query.maintenance.enabled()).toJSON() as boolean;
+}
+
+describe('Integration Test: Maintenance Functionality', () => {
+ let superuser: IKeyringPair;
+ let donor: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Maintenance]);
+ superuser = await privateKey('//Alice');
+ donor = await privateKey({url: import.meta.url});
+ [bob] = await helper.arrange.createAccounts([10000n], donor);
+
+ });
+ });
+
+ describe('Maintenance Mode', () => {
+ before(async function() {
+ await usingPlaygrounds(async (helper) => {
+ if(await maintenanceEnabled(helper.getApi())) {
+ console.warn('\tMaintenance mode was left enabled BEFORE the test suite! Disabling it now.');
+ await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', [])).to.be.fulfilled;
+ }
+ });
+ });
+
+ itSub('Allows superuser to enable and disable maintenance mode - and disallows anyone else', async ({helper}) => {
+ // Make sure non-sudo can't enable maintenance mode
+ await expect(helper.executeExtrinsic(superuser, 'api.tx.maintenance.enable', []), 'on commoner enabling MM')
+ .to.be.rejectedWith(/BadOrigin/);
+
+ // Set maintenance mode
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ // Make sure non-sudo can't disable maintenance mode
+ await expect(helper.executeExtrinsic(bob, 'api.tx.maintenance.disable', []), 'on commoner disabling MM')
+ .to.be.rejectedWith(/BadOrigin/);
+
+ // Disable maintenance mode
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+ });
+
+ itSub('MM blocks unique pallet calls', async ({helper}) => {
+ // Can create an NFT collection before enabling the MM
+ const nftCollection = await helper.nft.mintCollection(bob, {
+ tokenPropertyPermissions: [{
+ key: 'test', permission: {
+ collectionAdmin: true,
+ tokenOwner: true,
+ mutable: true,
+ },
+ }],
+ });
+
+ // Can mint an NFT before enabling the MM
+ const nft = await nftCollection.mintToken(bob);
+
+ // Can create an FT collection before enabling the MM
+ const ftCollection = await helper.ft.mintCollection(superuser);
+
+ // Can mint an FT before enabling the MM
+ await expect(ftCollection.mint(superuser)).to.be.fulfilled;
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ // Unable to create a collection when the MM is enabled
+ await expect(helper.nft.mintCollection(superuser), 'cudo forbidden stuff')
+ .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
+
+ // Unable to set token properties when the MM is enabled
+ await expect(nft.setProperties(
+ bob,
+ [{key: 'test', value: 'test-val'}],
+ )).to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
+
+ // Unable to mint an NFT when the MM is enabled
+ await expect(nftCollection.mintToken(superuser))
+ .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
+
+ // Unable to mint an FT when the MM is enabled
+ await expect(ftCollection.mint(superuser))
+ .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+
+ // Can create a collection after disabling the MM
+ await expect(helper.nft.mintCollection(bob), 'MM is disabled, the collection should be created').to.be.fulfilled;
+
+ // Can set token properties after disabling the MM
+ await nft.setProperties(bob, [{key: 'test', value: 'test-val'}]);
+
+ // Can mint an NFT after disabling the MM
+ await nftCollection.mintToken(bob);
+
+ // Can mint an FT after disabling the MM
+ await ftCollection.mint(superuser);
+ });
+
+ itSub.ifWithPallets('MM blocks unique pallet calls (Re-Fungible)', [Pallets.ReFungible], async ({helper}) => {
+ // Can create an RFT collection before enabling the MM
+ const rftCollection = await helper.rft.mintCollection(superuser);
+
+ // Can mint an RFT before enabling the MM
+ await expect(rftCollection.mintToken(superuser)).to.be.fulfilled;
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ // Unable to mint an RFT when the MM is enabled
+ await expect(rftCollection.mintToken(superuser))
+ .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+
+ // Can mint an RFT after disabling the MM
+ await rftCollection.mintToken(superuser);
+ });
+
+ itSub('MM allows native token transfers and RPC calls', async ({helper}) => {
+ // We can use RPC before the MM is enabled
+ const totalCount = await helper.collection.getTotalCount();
+
+ // We can transfer funds before the MM is enabled
+ await expect(helper.balance.transferToSubstrate(superuser, bob.address, 2n)).to.be.fulfilled;
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ // RPCs work while in maintenance
+ expect(await helper.collection.getTotalCount()).to.be.deep.equal(totalCount);
+
+ // We still able to transfer funds
+ await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled;
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+
+ // RPCs work after maintenance
+ expect(await helper.collection.getTotalCount()).to.be.deep.equal(totalCount);
+
+ // Transfers work after maintenance
+ await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled;
+ });
+
+ itSched.ifWithPallets('MM blocks scheduled calls and the scheduler itself', [Pallets.UniqueScheduler], async (scheduleKind, {helper}) => {
+ const collection = await helper.nft.mintCollection(bob);
+
+ const nftBeforeMM = await collection.mintToken(bob);
+ const nftDuringMM = await collection.mintToken(bob);
+ const nftAfterMM = await collection.mintToken(bob);
+
+ const [
+ scheduledIdBeforeMM,
+ scheduledIdDuringMM,
+ scheduledIdBunkerThroughMM,
+ scheduledIdAttemptDuringMM,
+ scheduledIdAfterMM,
+ ] = scheduleKind == 'named'
+ ? helper.arrange.makeScheduledIds(5)
+ : new Array(5);
+
+ const blocksToWait = 6;
+
+ // Scheduling works before the maintenance
+ await helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdBeforeMM})
+ .nft.transferToken(bob, collection.collectionId, nftBeforeMM.tokenId, {Substrate: superuser.address});
+
+
+ await helper.wait.newBlocks(blocksToWait + 1);
+ expect(await nftBeforeMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});
+
+ // Schedule a transaction that should occur *during* the maintenance
+ await helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdDuringMM})
+ .nft.transferToken(bob, collection.collectionId, nftDuringMM.tokenId, {Substrate: superuser.address});
+
+
+ // Schedule a transaction that should occur *after* the maintenance
+ await helper.scheduler.scheduleAfter(blocksToWait * 2, {scheduledId: scheduledIdBunkerThroughMM})
+ .nft.transferToken(bob, collection.collectionId, nftDuringMM.tokenId, {Substrate: superuser.address});
+
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ await helper.wait.newBlocks(blocksToWait + 1);
+ // The owner should NOT change since the scheduled transaction should be rejected
+ expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: bob.address});
+
+ // Any attempts to schedule a tx during the MM should be rejected
+ await expect(helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAttemptDuringMM})
+ .nft.transferToken(bob, collection.collectionId, nftDuringMM.tokenId, {Substrate: superuser.address}))
+ .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+
+ // Scheduling works after the maintenance
+ await helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAfterMM})
+ .nft.transferToken(bob, collection.collectionId, nftAfterMM.tokenId, {Substrate: superuser.address});
+
+ await helper.wait.newBlocks(blocksToWait + 1);
+
+ expect(await nftAfterMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});
+ // The owner of the token scheduled for transaction *before* maintenance should now change *after* maintenance
+ expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});
+ });
+
+ itEth('Disallows Ethereum transactions to execute while in maintenance', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const receiver = helper.eth.createAccount();
+
+ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'B', 'C', '');
+
+ // Set maintenance mode
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+ const tokenId = await contract.methods.nextTokenId().call();
+ expect(tokenId).to.be.equal('1');
+
+ await expect(contract.methods.mintWithTokenURI(receiver, 'Test URI').send())
+ .to.be.rejectedWith(/Returned error: unknown error/);
+
+ await expect(contract.methods.ownerOf(tokenId).call()).rejectedWith(/token not found/);
+
+ // Disable maintenance mode
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+ });
+
+ itSub('Allows to enable and disable MM repeatedly', async ({helper}) => {
+ // Set maintenance mode
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
+
+ // Disable maintenance mode
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
+ });
+
+ afterEach(async () => {
+ await usingPlaygrounds(async helper => {
+ if(helper.fetchMissingPalletNames([Pallets.Maintenance]).length != 0) return;
+ if(await maintenanceEnabled(helper.getApi())) {
+ console.warn('\tMaintenance mode was left enabled AFTER a test has finished! Be careful. Disabling it now.');
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ }
+ expect(await maintenanceEnabled(helper.getApi()), 'Disastrous! Exited the test suite with maintenance mode on.').to.be.false;
+ });
+ });
+ });
+
+ describe('Integration Test: Maintenance mode & App Promo', () => {
+ let superuser: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.Maintenance]);
+ superuser = await privateKey('//Alice');
+ });
+ });
+
+ describe('Test AppPromo script for check state after Maintenance mode', () => {
+ before(async function () {
+ await usingPlaygrounds(async (helper) => {
+ if(await maintenanceEnabled(helper.getApi())) {
+ console.warn('\tMaintenance mode was left enabled BEFORE the test suite! Disabling it now.');
+ await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', [])).to.be.fulfilled;
+ }
+ });
+ });
+ itSub('Can find and fix inconsistent state', async ({helper}) => {
+ const api = helper.getApi();
+
+ await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.system.setStorage([
+ // pendingUnstake(1 -> [superuser.address, 100UNQ])
+ ['0x42b67acb8bd223c60d0c8f621ffefc0ae280fa2db99bd3827aac976de75af95f5153cb1f00942ff401000000',
+ '0x04d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d000010632d5ec76b0500000000000000'],
+ // pendingUnstake(2 -> [superuser.address, 100UNQ])
+ ['0x42b67acb8bd223c60d0c8f621ffefc0ae280fa2db99bd3827aac976de75af95f9eb2dcce60f37a2702000000',
+ '0x04d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d000010632d5ec76b0500000000000000'],
+ // Balances.freezes(superuser.address -> freeze with app promo id and 200 UNQ )
+ ['0xc2261276cc9d1f8598ea4b6a74b15c2fb1c0eb12e038e5c7f91e120ed4b7ebf1de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d',
+ '0x046170707374616b656170707374616b65000020c65abc8ed70a00000000000000'],
+ ])]);
+
+ expect((await api.query.appPromotion.pendingUnstake(1)).toJSON()).to.be.deep.equal([[superuser.address, '0x00000000000000056bc75e2d63100000']]);
+ expect((await api.query.appPromotion.pendingUnstake(2)).toJSON()).to.be.deep.equal([[superuser.address, '0x00000000000000056bc75e2d63100000']]);
+ expect((await api.query.balances.freezes(superuser.address) as Vec<PalletBalancesIdAmount>)
+ .map(lock => ({id: lock.id.toUtf8(), amount: lock.amount.toBigInt()})))
+ .to.be.deep.equal([{id: 'appstakeappstake', amount: 200000000000000000000n}]);
+ await correctState();
+
+ expect((await api.query.appPromotion.pendingUnstake(1)).toJSON()).to.be.deep.equal([]);
+ expect((await api.query.appPromotion.pendingUnstake(2)).toJSON()).to.be.deep.equal([]);
+ expect((await api.query.balances.freezes(superuser.address)).toJSON()).to.be.deep.equal([]);
+
+ });
+
+ itSub('(!negative test!) Only works when Maintenance mode is disabled', async({helper}) => {
+ await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', [])).to.be.fulfilled;
+ await expect(correctState()).to.be.rejectedWith('The network is still in maintenance mode');
+ await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', [])).to.be.fulfilled;
+ });
+ });
+ });
+
+ after(async () => {
+ await usingPlaygrounds(async(helper) => {
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
+ });
+ });
+});
js-packages/tests/migrations/942057-appPromotion/README.mddiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/942057-appPromotion/README.md
@@ -0,0 +1,42 @@
+# Update Procedure
+
+- Enable maintenance mode
+- [Collect migration data using ChainQL](#stakers-data-loading)
+- ❗️❗️❗️ Initiate the runtime upgrade only at this point ❗️❗️❗️
+- Wait for the upgrade to complete
+- [Execute offchain migration](#execute-offchain-migration)
+- Disable maintenance mode
+
+## Stakers Data Loading
+
+Set the environment variable (WS_RPC). For example, ws://localhost:9944. Execute the following command:
+
+```sh
+chainql --tla-str=chainUrl=<WS_RPC> stakersParser.jsonnet > output.json
+```
+
+where `<WS_RPC>` - is the network address.
+
+Example for Opal:
+
+```sh
+chainql --tla-str=chainUrl=wss://eu-ws-opal.unique.network:443 stakersParser.jsonnet > output.json
+```
+
+To install chainql, execute the following command:
+
+```sh
+cargo install chainql
+```
+
+## Execute offchain migration
+
+To run, you need to set an environment variables:
+- `SUPERUSER_SEED` – the sudo key seed.
+- `WS_RPC` – the network address
+
+Run the migration by executing the following command:
+
+```sh
+npx ts-node --esm executeMigration.ts
+```
js-packages/tests/migrations/942057-appPromotion/collectData.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/942057-appPromotion/collectData.ts
@@ -0,0 +1,12 @@
+import {exec} from 'child_process';
+import path from 'path';
+import {dirname} from 'path';
+import {fileURLToPath} from 'url';
+
+export const collectData = () => {
+ const dirName = dirname(fileURLToPath(import.meta.url));
+
+ const pathToScript = path.resolve(dirName, './stakersParser.jsonnet');
+ const outputPath = path.resolve(dirName, './output.json');
+ exec(`chainql --tla-str=chainUrl=ws://127.0.0.1:9944 ${pathToScript} > ${outputPath}`);
+};
js-packages/tests/migrations/942057-appPromotion/executeMigration.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/942057-appPromotion/executeMigration.ts
@@ -0,0 +1,11 @@
+import {migrateLockedToFreeze} from './lockedToFreeze.js';
+
+
+const WS_RPC = process.env.WS_RPC || 'wss://ws-opal.unique.network:443';
+const SUPERUSER_SEED = process.env.SUPERUSER_SEED || '';
+
+migrateLockedToFreeze({
+ wsEndpoint: WS_RPC,
+ donorSeed: SUPERUSER_SEED,
+})
+ .catch(console.error);
\ No newline at end of file
js-packages/tests/migrations/942057-appPromotion/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/942057-appPromotion/index.ts
@@ -0,0 +1,12 @@
+import type {Migration} from '../../util/frankensteinMigrate.js';
+import {collectData} from './collectData.js';
+import {migrateLockedToFreeze} from './lockedToFreeze.js';
+
+export const migration: Migration = {
+ async before() {
+ await collectData();
+ },
+ async after() {
+ await migrateLockedToFreeze();
+ },
+};
\ No newline at end of file
js-packages/tests/migrations/942057-appPromotion/lockedToFreeze.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/942057-appPromotion/lockedToFreeze.ts
@@ -0,0 +1,259 @@
+// import { usingApi, privateKey, onlySign } from "./../../load/lib";
+import * as fs from 'fs';
+import {usingPlaygrounds} from '../../util/index.js';
+import path, {dirname} from 'path';
+import {isInteger, parse} from 'lossless-json';
+import {fileURLToPath} from 'url';
+import config from '../../config.js';
+
+
+const WS_ENDPOINT = config.substrateUrl;
+const DONOR_SEED = '//Alice';
+const UPDATE_IF_VERSION = 942057;
+
+export function customNumberParser(value: any) {
+ return isInteger(value) ? BigInt(value) : parseFloat(value);
+}
+
+export const migrateLockedToFreeze = async(options: { wsEndpoint: string; donorSeed: string } = {
+ wsEndpoint: WS_ENDPOINT,
+ donorSeed: DONOR_SEED,
+}) => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const api = helper.getApi();
+ // 1. Check version equal 942057 or skip
+ console.log((api.consts.system.version as any).specVersion.toNumber());
+ if((api.consts.system.version as any).specVersion.toNumber() != UPDATE_IF_VERSION) {
+ console.log("Version isn't 942057.");
+ return;
+ }
+
+ // 2. Get sudo signer
+ const signer = await privateKey(options.donorSeed);
+ console.log('2. Getting sudo:', signer.address);
+
+ // 3. Parse data to migrate
+ console.log('3. Parsing chainql results...');
+ const dirName = dirname(fileURLToPath(import.meta.url));
+ const parsingResult = parse(fs.readFileSync(path.resolve(dirName, 'output.json'), 'utf-8'), undefined, customNumberParser);
+
+ const chainqlImportData = parsingResult as {
+ address: string;
+ balance: string;
+ account: {
+ fee_frozen: string,
+ free: string,
+ misc_frozen: string,
+ reserved: string,
+ },
+ locks: {
+ amount: string,
+ id: string,
+ }[],
+ stakes: object,
+ unstakes: object,
+ }[];
+ testChainqlData(chainqlImportData);
+
+ const stakers = chainqlImportData.map((i) => i.address);
+
+ // 3.1 Split into chunks by 100
+ console.log('3.1 Splitting into chunks...');
+ const stakersChunks = chunk(stakers, 100);
+ console.log('3.1 Done, total chunks:', stakersChunks.length);
+
+ // 4. Get signer/sudo nonce
+ console.log('4. Getting sudo nonce...');
+ const signerAccount = (
+ await api.query.system.account(signer.address)
+ ).toJSON() as any;
+
+ let nonce: number = signerAccount.nonce;
+ console.log('4. Sudo nonce is:', nonce);
+
+ // 5. Only sign upgradeAccounts-transactions for each chunk
+ console.log('5. Signing transactions...');
+ const signedTxs = [];
+ for(const chunk of stakersChunks) {
+ const tx = api.tx.sudo.sudo(api.tx.appPromotion.upgradeAccounts(chunk));
+ const signed = tx.sign(signer, {
+ blockHash: api.genesisHash,
+ genesisHash: api.genesisHash,
+ runtimeVersion: api.runtimeVersion,
+ nonce: nonce++,
+ });
+ signedTxs.push(signed);
+ }
+
+ // 6. Send all signed transactions
+ console.log('6. Sending transactions...');
+ const promises = signedTxs.map((tx) => api.rpc.author.submitAndWatchExtrinsic(tx));
+ // 6.1 Wait all transactions settled
+ console.log('6.1 Waiting all transactions settled...');
+ const res = await Promise.allSettled(promises);
+
+ console.log('Wait 5 blocks for transactions to be included in a block...');
+ await helper.wait.newBlocks(5);
+ // 6.2 Filter failed transactions
+ console.log('6.2 Getting failed transactions...');
+ const failedTx = res.filter((r) => r.status == 'rejected') as PromiseRejectedResult[];
+ console.log('6.2. total failedTxs:', failedTx.length);
+
+ // 6.3 Log the reasons of failed tx
+ for(const tx of failedTx) {
+ console.log(tx.reason);
+ }
+
+ // 7. Check balances for 10 blocks:
+ console.log('7. Check balances...');
+ let blocksLeft = 10;
+ let notMigrated = stakers;
+ const suspiciousAccounts = [];
+ do {
+ console.log('blocks left:', blocksLeft);
+ const _notMigrated: string[] = [];
+ console.log('accounts to migrate...', notMigrated.length);
+ for(const accountToMigrate of notMigrated) {
+ let accountMigrated = true;
+ // 7.0 get data from chainql:
+ const oldAccount = chainqlImportData.find(acc => acc.address === accountToMigrate);
+ if(!oldAccount) {
+ console.log('Cannot find old account data for', accountMigrated);
+ accountMigrated = false;
+ _notMigrated.push(accountToMigrate);
+ continue;
+ }
+
+ // 7.1 system.account
+ const balance = await api.query.system.account(accountToMigrate) as any;
+ // new balances
+ const free = balance.data.free;
+ const reserved = balance.data.reserved;
+ const frozen = balance.data.frozen;
+ // old balances
+ const oldFree = oldAccount.account.free;
+ const oldReserved = oldAccount.account.reserved;
+ const oldFrozen = oldAccount.account.fee_frozen;
+ // asserts new = old
+ if(oldFree.toString() !== free.toString()) {
+ console.log('Old free !== New free, which is probably not a problem', oldFree.toString(), free.toString());
+ suspiciousAccounts.push(accountToMigrate);
+ }
+ if(oldFrozen.toString() !== frozen.toString()) {
+ console.log('Old frozen !== New frozen, which is probably not a problem', oldFrozen.toString(), frozen.toString());
+ suspiciousAccounts.push(accountToMigrate);
+ }
+ if(oldReserved.toString() !== reserved.toString()) {
+ console.log('Old reserved !== New reserved, which is probably not a problem', oldReserved.toString(), reserved.toString());
+ suspiciousAccounts.push(accountToMigrate);
+ }
+
+ // 7.2 balances.locks: no id appstake
+ const locks = await helper.balance.getLocked(accountToMigrate);
+ const appPromoLocks = locks.filter(lock => lock.id === 'appstake');
+ if(appPromoLocks.length !== 0) {
+ console.log('Account still has app-promo lock');
+ accountMigrated = false;
+ }
+
+ // 7.3 balances.freezes set...
+ let freezes = await api.query.balances.freezes(accountToMigrate) as any;
+ freezes = freezes.map((freez: any) => ({id: freez.id.toString(), amount: freez.amount.toString()}));
+ if(!freezes) {
+ console.log('Account does not have freezes');
+ accountMigrated = false;
+ } else {
+ const oldAppPromoLocks = oldAccount.locks.filter(l => l.id === '0x6170707374616b65'); // get app promo locks
+ // should be only one freez for each account
+ if(freezes.length !== 1) {
+ console.log('freezes.length !== 1 and old appPromoLocks.length', freezes.length, oldAppPromoLocks.length);
+ accountMigrated = false;
+ } else {
+ const appPromoFreez = freezes[0];
+ // freez-amount should be equal to migrated lock amount
+ if(appPromoFreez.amount.toString() !== oldAppPromoLocks[0].amount.toString()) {
+ console.log('freezes amount !== old appPromoLocks amount', appPromoFreez.amount.toString(), oldAppPromoLocks[0].amount.toString());
+ accountMigrated = false;
+ }
+ // freez id should be correct
+ if(appPromoFreez.id !== '0x6170707374616b656170707374616b65') {
+ console.log('Got freez with incorrect id:', appPromoFreez.id);
+ accountMigrated = false;
+ }
+ }
+ }
+
+ // 7.4 Stakes number the same
+ const stakesNumber = await helper.staking.getStakesNumber({Substrate: accountToMigrate});
+ const oldStakesNumber = oldAccount.stakes ? Object.keys(oldAccount.stakes).length : 0;
+ if(stakesNumber.toString() !== oldStakesNumber.toString()) {
+ console.log('Old stakes number !== New stakes number', oldStakesNumber, stakesNumber);
+ accountMigrated = false;
+ }
+
+ // 7.5 Total pendingUnstake + total staked = old locked
+ const pendingUnstakes = await helper.staking.getPendingUnstake({Substrate: accountToMigrate});
+ const totalStaked = await helper.staking.getTotalStaked({Substrate: accountToMigrate});
+ const totalBalanceInAppPromo = pendingUnstakes + totalStaked;
+ if(totalBalanceInAppPromo.toString() !== oldAccount.balance.toString()) {
+ console.log('totalBalanceInAppPromo !== old locked in app promo', totalBalanceInAppPromo.toString(), oldAccount.balance.toString());
+ accountMigrated = false;
+ }
+
+ // 8 Add to not-migrated
+ if(!accountMigrated) {
+ console.log('Add to not migrated:', accountToMigrate);
+ _notMigrated.push(accountToMigrate);
+ }
+ }
+
+ blocksLeft--;
+ notMigrated = _notMigrated;
+ await helper.wait.newBlocks(1);
+ } while(blocksLeft > 0 && notMigrated.length !== 0);
+
+ console.log('Not migrated accounts...', notMigrated.length);
+ if(suspiciousAccounts.length > 0) {
+ console.log('Saving suspicious accounts to suspicious.json:');
+ fs.writeFileSync('./suspicious.json', JSON.stringify(suspiciousAccounts));
+ }
+ if(notMigrated.length > 0) {
+ console.log('Saving not migrated list to failed.json:');
+ notMigrated.forEach(console.log);
+ fs.writeFileSync('./failed.json', JSON.stringify(notMigrated));
+ process.exit(1);
+ } else {
+ console.log('Migration success');
+ }
+ }, options.wsEndpoint);
+};
+
+const chunk = <T>(arr: T[], size: number) =>
+ Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
+ arr.slice(i * size, i * size + size));
+
+const testChainqlData = (data: any) => {
+ const wrongData = [];
+ for(const account of data) {
+ try {
+ if(account.address == null) throw Error('no address in data');
+ if(account.balance == null) throw Error('no balance in data');
+ if(account.account == null) throw Error('no account in data');
+ if(account.account.fee_frozen == null) throw Error('no account.fee_frozen in data');
+ if(account.account.misc_frozen == null) throw Error('no account.misc_frozen in data');
+ if(account.account.free == null) throw Error('no account.free in data');
+ if(account.account.reserved == null) throw Error('no account.reserved in data');
+ if(account.locks == null) throw Error('no locks in data');
+ if(account.locks[0].amount == null) throw Error('no locks.amount in data');
+ if(account.locks[0].id == null) throw Error('no locks.id in data');
+ } catch (error) {
+ wrongData.push(account.address);
+ console.log((error as Error).message, account.address);
+ }
+ if(wrongData.length > 0) {
+ console.log(data);
+ throw Error('Chainql data not correct');
+ }
+ }
+ console.log('Chainql data correct');
+};
js-packages/tests/migrations/942057-appPromotion/stakersParser.jsonnetdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/942057-appPromotion/stakersParser.jsonnet
@@ -0,0 +1,29 @@
+function(chainUrl)
+
+ local
+ state = cql.chain(chainUrl).latest,
+ locked_balances = state.Balances.Locks._preloadKeys,
+ accountsRaw = state.System.Account._preloadKeys,
+ stakers = state.AppPromotion.Staked._preloadKeys,
+ unstakes = state.AppPromotion.PendingUnstake._preloadKeys,
+ locks = [
+ { [k]: std.filter(function(l) l.id == '0x6170707374616b65', locked_balances[k]) }
+ for k in std.objectFields(locked_balances)
+ ],
+ unstakersData = [
+ { [pair[0]]: { block: block, value: pair[1] } }
+
+ for block in std.objectFields(unstakes)
+ for pair in unstakes[block]
+ ],
+ non_empty_locks = std.prune(locks)
+ ;
+
+ std.map(function(a) {
+ address: std.objectFields(a)[0],
+ balance: a[std.objectFields(a)[0]][0].amount,
+ account: accountsRaw[std.objectFields(a)[0]].data,
+ locks: locked_balances[std.objectFields(a)[0]],
+ stakes: if std.objectHas(stakers, std.objectFields(a)[0]) then stakers[std.objectFields(a)[0]] else null,
+ unstakes: std.filterMap(function(b) std.objectHas(b, std.objectFields(a)[0]), function(c) std.objectValues(c)[0], unstakersData),
+ }, non_empty_locks)
js-packages/tests/migrations/correctStateAfterMaintenance.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/correctStateAfterMaintenance.ts
@@ -0,0 +1,69 @@
+import config from '../config.js';
+import {usingPlaygrounds} from '../util/index.js';
+import type {u32} from '@polkadot/types-codec';
+
+const WS_ENDPOINT = config.substrateUrl;
+const DONOR_SEED = '//Alice';
+
+export const main = async(options: { wsEndpoint: string; donorSeed: string } = {
+ wsEndpoint: WS_ENDPOINT,
+ donorSeed: DONOR_SEED,
+}) => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const api = helper.getApi();
+
+ if((await api.query.maintenance.enabled()).valueOf()) {
+ throw Error('The network is still in maintenance mode');
+ }
+
+ const pendingBlocks = (
+ await api.query.appPromotion.pendingUnstake.entries()
+ ).map(([k, _v]) =>
+ (k.args[0] as u32).toNumber());
+
+ const currentBlock = (await api.query.system.number() as u32).toNumber();
+
+ const filteredBlocks = pendingBlocks.filter(b => currentBlock > b);
+
+ if(filteredBlocks.length != 0) {
+ console.log(`During maintenance mode, ${filteredBlocks.length} block(s) were not processed. Number(s): ${filteredBlocks}`);
+ } else {
+ console.log('Nothing to change');
+ return;
+ }
+
+ const skippedBlocks = chunk(filteredBlocks, 10);
+
+ const signer = await privateKey(options.donorSeed);
+
+ const txs = skippedBlocks.map((b) =>
+ api.tx.sudo.sudo(api.tx.appPromotion.forceUnstake(b)));
+
+
+ const promises = txs.map((tx) => () => helper.signTransaction(signer, tx));
+
+ await Promise.allSettled(promises.map((p) => p()));
+
+ const failedBlocks: number[] = [];
+ let isSuccess = true;
+
+ for(const b of filteredBlocks) {
+ if(((await api.query.appPromotion.pendingUnstake(b)).toJSON() as any[]).length != 0) {
+ failedBlocks.push(b);
+ isSuccess = false;
+ }
+ }
+
+ if(isSuccess) {
+ console.log('Done. %d block(s) were processed.', filteredBlocks.length);
+ } else {
+ throw new Error(`Something went wrong. Block(s) have not been processed: ${failedBlocks}`);
+ }
+
+
+ }, options.wsEndpoint);
+};
+
+const chunk = <T>(arr: T[], size: number) =>
+ Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
+ arr.slice(i * size, i * size + size));
js-packages/tests/migrations/runCheckState.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/migrations/runCheckState.ts
@@ -0,0 +1,10 @@
+import {main} from './correctStateAfterMaintenance.js';
+
+main({
+ wsEndpoint: process.env.WS_RPC!,
+ donorSeed: process.env.SUPERUSER_SEED!,
+}).then(() => process.exit(0))
+ .catch((e) => {
+ console.error(e);
+ process.exit(1);
+ });
js-packages/tests/nativeFungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nativeFungible.test.ts
@@ -0,0 +1,221 @@
+// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from './util/index.js';
+
+describe('Native fungible', () => {
+ let root: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ root = await privateKey('//Alice');
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+ });
+ });
+
+ itSub('destroy_collection()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.burn(alice)).to.be.rejectedWith('common.UnsupportedOperation');
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.destroyCollection', [0])).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('add_to_allow_list()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.addToAllowList(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('remove_from_allow_list()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.removeFromAllowList(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('change_collection_owner()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.changeOwner(alice, bob.address)).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('add_collection_admin()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.addAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('remove_collection_admin()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.removeAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('set_collection_sponsor()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.setSponsor(alice, bob.address)).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('confirm_sponsorship()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.confirmSponsorship(alice)).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('remove_collection_sponsor()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.removeSponsor(alice)).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('create_item()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.mint(alice, 100n, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('set_collection_properties()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.setProperties(alice, [{key: 'value'}])).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('delete_collection_properties()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.deleteProperties(alice, ['key'])).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('set_token_properties()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.setTokenProperties',
+ [0, 0, [{key: 'value'}]],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('delete_token_properties()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.deleteTokenProperties',
+ [0, 0, ['key']],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('set_transfers_enabled_flag()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.setTransfersEnabledFlag',
+ [0, true],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('burn_item()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.burnItem',
+ [0, 0, 100n],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('burn_from()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.burnTokens(alice, 100n)).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('transfer()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ const balanceAliceBefore = await helper.balance.getSubstrate(alice.address);
+ const balanceBobBefore = await helper.balance.getSubstrate(bob.address);
+ await collection.transfer(alice, {Substrate: bob.address}, 100n);
+ const balanceAliceAfter = await helper.balance.getSubstrate(alice.address);
+ const balanceBobAfter = await helper.balance.getSubstrate(bob.address);
+ expect(balanceAliceBefore - balanceAliceAfter > 100n).to.be.true;
+ expect(balanceBobAfter - balanceBobBefore === 100n).to.be.true;
+ });
+
+ itSub('transfer_from()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ const balanceAliceBefore = await helper.balance.getSubstrate(alice.address);
+ const balanceBobBefore = await helper.balance.getSubstrate(bob.address);
+
+ await collection.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address}, 100n);
+
+ const balanceAliceAfter = await helper.balance.getSubstrate(alice.address);
+ const balanceBobAfter = await helper.balance.getSubstrate(bob.address);
+ expect(balanceAliceBefore - balanceAliceAfter > 100n).to.be.true;
+ expect(balanceBobAfter - balanceBobBefore === 100n).to.be.true;
+
+ await expect(collection.transferFrom(alice, {Substrate: bob.address}, {Substrate: alice.address}, 100n)).to.be.rejectedWith('common.ApprovedValueTooLow');
+ });
+
+ itSub('approve()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.approveTokens(alice, {Substrate: bob.address}, 100n)).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('approve_from()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.approveFrom',
+ [{Substrate: alice.address}, {Substrate: bob.address}, 0, 0, 100n],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('set_collection_limits()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.setLimits(alice, {accountTokenOwnershipLimit: 1})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('set_collection_permissions()', async ({helper}) => {
+ const collection = helper.ft.getCollectionObject(0);
+ await expect(collection.setPermissions(alice, {access: 'AllowList'})).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('repartition()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.repartition',
+ [0, 0, 100n],
+ true,
+ )).to.be.rejectedWith('unique.RepartitionCalledOnNonRefungibleCollection');
+ });
+
+ itSub('force_repair_collection()', async ({helper}) => {
+ await expect(helper.executeExtrinsic(
+ alice,
+ 'api.tx.unique.forceRepairCollection',
+ [0],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('force_repair_item()', async ({helper}) => {
+ await expect(helper.getSudo().executeExtrinsic(
+ root,
+ 'api.tx.unique.forceRepairItem',
+ [0, 0],
+ true,
+ )).to.be.rejectedWith('common.UnsupportedOperation');
+ });
+
+ itSub('Nest into NFT token()', async ({helper}) => {
+ const nftCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await nftCollection.mintToken(alice);
+
+ const collection = helper.ft.getCollectionObject(0);
+ await collection.transfer(alice, targetToken.nestingAccount(), 100n);
+
+ await collection.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 100n);
+ });
+});
\ No newline at end of file
js-packages/tests/nesting/collectionProperties.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/collectionProperties.seqtest.ts
@@ -0,0 +1,61 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
+
+describe('Integration Test: Collection Properties with sudo', () => {
+ let superuser: IKeyringPair;
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ superuser = await privateKey('//Alice');
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'ft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+ before(async function() {
+ // eslint-disable-next-line require-await
+ await usingPlaygrounds(async helper => {
+ requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+ });
+ });
+
+ itSub('Repairing an unbroken collection\'s properties preserves the consumed space', async({helper}) => {
+ const properties = [
+ {key: 'sea-creatures', value: 'mermaids'},
+ {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
+ ];
+ const collection = await helper[testSuite.mode].mintCollection(alice, {properties});
+
+ const newProperty = {key: 'space', value: ' '.repeat(4096)};
+ await collection.setProperties(alice, [newProperty]);
+ const originalSpace = await collection.getPropertiesConsumedSpace();
+ expect(originalSpace).to.be.equal(sizeOfProperty(properties[0]) + sizeOfProperty(properties[1]) + sizeOfProperty(newProperty));
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true);
+ const recomputedSpace = await collection.getPropertiesConsumedSpace();
+ expect(recomputedSpace).to.be.equal(originalSpace);
+ });
+ }));
+});
js-packages/tests/nesting/collectionProperties.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/collectionProperties.test.ts
@@ -0,0 +1,326 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
+
+describe('Integration Test: Collection Properties', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor);
+ });
+ });
+
+ itSub('Properties are initially empty', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ expect(await collection.getProperties()).to.be.empty;
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'ft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+ before(async function() {
+ // eslint-disable-next-line require-await
+ await usingPlaygrounds(async helper => {
+ requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+ });
+ });
+
+ itSub('Sets properties for a collection', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ // As owner
+ await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;
+
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ // As administrator
+ await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled;
+
+ const properties = await collection.getProperties();
+ expect(properties).to.include.deep.members([
+ {key: 'electron', value: 'come bond'},
+ {key: 'black_hole', value: ''},
+ ]);
+ });
+
+ itSub('Check valid names for collection properties keys', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ // alpha symbols
+ await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;
+
+ // numeric symbols
+ await expect(collection.setProperties(alice, [{key: '451'}])).to.be.fulfilled;
+
+ // underscore symbol
+ await expect(collection.setProperties(alice, [{key: 'black_hole'}])).to.be.fulfilled;
+
+ // dash symbol
+ await expect(collection.setProperties(alice, [{key: '-'}])).to.be.fulfilled;
+
+ // dot symbol
+ await expect(collection.setProperties(alice, [{key: 'once.in.a.long.long.while...', value: 'you get a little lost'}])).to.be.fulfilled;
+
+ const properties = await collection.getProperties();
+ expect(properties).to.include.deep.members([
+ {key: 'answer', value: ''},
+ {key: '451', value: ''},
+ {key: 'black_hole', value: ''},
+ {key: '-', value: ''},
+ {key: 'once.in.a.long.long.while...', value: 'you get a little lost'},
+ ]);
+ });
+
+ itSub('Changes properties of a collection', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;
+
+ // Mutate the properties
+ await expect(collection.setProperties(alice, [{key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
+
+ const properties = await collection.getProperties();
+ expect(properties).to.include.deep.members([
+ {key: 'electron', value: 'come bond'},
+ {key: 'black_hole', value: 'LIGO'},
+ ]);
+ });
+
+ itSub('Deletes properties of a collection', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
+
+ await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled;
+
+ const properties = await collection.getProperties(['black_hole', 'electron']);
+ expect(properties).to.be.deep.equal([
+ {key: 'black_hole', value: 'LIGO'},
+ ]);
+ });
+
+ itSub('Allows modifying a collection property multiple times with the same size', async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ const maxCollectionPropertiesSize = 40960;
+
+ const propDataSize = 4096;
+
+ let propDataChar = 'a';
+ const makeNewPropData = () => {
+ propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
+ return `${propDataChar}`.repeat(propDataSize);
+ };
+
+ const property = {key: propKey, value: makeNewPropData()};
+ await collection.setProperties(alice, [property]);
+ const originalSpace = await collection.getPropertiesConsumedSpace();
+ expect(originalSpace).to.be.equal(sizeOfProperty(property));
+
+ const sameSizePropertiesPossibleNum = maxCollectionPropertiesSize / propDataSize;
+
+ // It is possible to modify a property as many times as needed.
+ // It will not consume any additional space.
+ for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
+ await collection.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
+ const consumedSpace = await collection.getPropertiesConsumedSpace();
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }
+ });
+
+ itSub('Adding then removing a collection property doesn\'t change the consumed space', async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+ const originalSpace = await collection.getPropertiesConsumedSpace();
+
+ const propDataSize = 4096;
+ const propData = 'a'.repeat(propDataSize);
+
+ const property = {key: propKey, value: propData};
+ await collection.setProperties(alice, [property]);
+ let consumedSpace = await collection.getPropertiesConsumedSpace();
+ expect(consumedSpace).to.be.equal(sizeOfProperty(property));
+
+ await collection.deleteProperties(alice, [propKey]);
+ consumedSpace = await collection.getPropertiesConsumedSpace();
+ expect(consumedSpace).to.be.equal(originalSpace);
+ });
+
+ itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+ const originalSpace = await collection.getPropertiesConsumedSpace();
+
+ const initProp = {key: propKey, value: 'a'.repeat(4096)};
+ const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
+ const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
+
+ let consumedSpace;
+ let expectedConsumedSpaceDiff;
+
+ await collection.setProperties(alice, [initProp]);
+ consumedSpace = await collection.getPropertiesConsumedSpace();
+ expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
+ expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
+
+ await collection.setProperties(alice, [biggerProp]);
+ consumedSpace = await collection.getPropertiesConsumedSpace();
+ expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
+ expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
+
+ await collection.setProperties(alice, [smallerProp]);
+ consumedSpace = await collection.getPropertiesConsumedSpace();
+ expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
+ expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
+ });
+ }));
+});
+
+describe('Negative Integration Test: Collection Properties', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([1000n, 100n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'ft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+ before(async function() {
+ // eslint-disable-next-line require-await
+ await usingPlaygrounds(async helper => {
+ requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+ });
+ });
+
+ itSub('Fails to set properties in a collection if not its onwer/administrator', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))
+ .to.be.rejectedWith(/common\.NoPermission/);
+
+ expect(await collection.getProperties()).to.be.empty;
+ });
+
+ itSub('Fails to set properties that exceed the limits', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ const spaceLimit = (helper.getApi().consts.unique.maxCollectionPropertiesSize as any).toNumber();
+
+ // Mute the general tx parsing error, too many bytes to process
+ {
+ console.error = () => {};
+ await expect(collection.setProperties(alice, [
+ {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))},
+ ])).to.be.rejected;
+ }
+
+ expect(await collection.getProperties(['electron'])).to.be.empty;
+
+ await expect(collection.setProperties(alice, [
+ {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))},
+ {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))},
+ ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+ expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty;
+ });
+
+ itSub('Fails to set more properties than it is allowed', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ const propertiesToBeSet = [];
+ for(let i = 0; i < 65; i++) {
+ propertiesToBeSet.push({
+ key: 'electron_' + i,
+ value: Math.random() > 0.5 ? 'high' : 'low',
+ });
+ }
+
+ await expect(collection.setProperties(alice, propertiesToBeSet)).
+ to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+ expect(await collection.getProperties()).to.be.empty;
+ });
+
+ itSub('Fails to set properties with invalid names', async ({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice);
+
+ const invalidProperties = [
+ [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
+ [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
+ [{key: 'déjà vu', value: 'hmm...'}],
+ ];
+
+ for(let i = 0; i < invalidProperties.length; i++) {
+ await expect(
+ collection.setProperties(alice, invalidProperties[i]),
+ `on rejecting the new badly-named property #${i}`,
+ ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
+ }
+
+ await expect(
+ collection.setProperties(alice, [{key: '', value: 'nothing must not exist'}]),
+ 'on rejecting an unnamed property',
+ ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
+
+ await expect(
+ collection.setProperties(alice, [{key: 'CRISPR-Cas9', value: 'rewriting nature!'}]),
+ 'on setting the correctly-but-still-badly-named property',
+ ).to.be.fulfilled;
+
+ const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');
+
+ const properties = await collection.getProperties(keys);
+ expect(properties).to.be.deep.equal([
+ {key: 'CRISPR-Cas9', value: 'rewriting nature!'},
+ ]);
+
+ for(let i = 0; i < invalidProperties.length; i++) {
+ await expect(
+ collection.deleteProperties(alice, invalidProperties[i].map(propertySet => propertySet.key)),
+ `on trying to delete the non-existent badly-named property #${i}`,
+ ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
+ }
+ });
+
+ itSub('Forbids to repair a collection if called with non-sudo', async({helper}) => {
+ const collection = await helper[testSuite.mode].mintCollection(alice, {properties: [
+ {key: 'sea-creatures', value: 'mermaids'},
+ {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
+ ]});
+
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true))
+ .to.be.rejectedWith(/BadOrigin/);
+ });
+ }));
+});
js-packages/tests/nesting/graphs.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/graphs.test.ts
@@ -0,0 +1,86 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from '../util/index.js';
+import {UniqueHelper, UniqueNFTCollection, UniqueNFToken} from '@unique/playgrounds/unique.js';
+
+/**
+ * ```dot
+ * 4 -> 3 -> 2 -> 1
+ * 7 -> 6 -> 5 -> 2
+ * 8 -> 5
+ * ```
+ */
+async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<[UniqueNFTCollection,UniqueNFToken[]]> {
+ const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
+ const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
+
+ await tokens[7].nest(sender, tokens[4]);
+ await tokens[6].nest(sender, tokens[5]);
+ await tokens[5].nest(sender, tokens[4]);
+ await tokens[4].nest(sender, tokens[1]);
+ await tokens[3].nest(sender, tokens[2]);
+ await tokens[2].nest(sender, tokens[1]);
+ await tokens[1].nest(sender, tokens[0]);
+
+ return [collection, tokens];
+}
+
+describe('Graphs', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([10n], donor);
+ });
+ });
+
+ itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {
+ const [collection, tokens] = await buildComplexObjectGraph(helper, alice);
+
+ await collection.setPermissions(alice, {nesting: {collectionAdmin: false, tokenOwner: true}});
+
+ // [token owner] to self
+ await expect(
+ tokens[0].nest(alice, tokens[0]),
+ '[token owner] self-nesting is forbidden',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+ // [token owner] to nested part of graph
+ await expect(
+ tokens[0].nest(alice, tokens[4]),
+ '[token owner] cannot nest the root node into an internal node',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+ await expect(
+ tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),
+ '[token owner] cannot nest higher internal node into lower internal node',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+
+ await collection.setPermissions(alice, {nesting: {collectionAdmin: true, tokenOwner: false}});
+
+ // [collection owner] to self
+ await expect(
+ tokens[0].nest(alice, tokens[0]),
+ '[collection owner] self-nesting is forbidden',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+ // [collection owner] to nested part of graph
+ await expect(
+ tokens[0].nest(alice, tokens[4]),
+ '[collection owner] cannot nest the root node into an internal node',
+ ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+ });
+});
js-packages/tests/nesting/propertyPermissions.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/propertyPermissions.test.ts
@@ -0,0 +1,198 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect} from '../util/index.js';
+import {UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/unique.js';
+
+describe('Integration Test: Access Rights to Token Properties', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+ });
+ });
+
+ itSub('Reads access rights to properties of a collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ const propertyRights = (await helper.callRpc('api.query.common.collectionPropertyPermissions', [collection.collectionId])).toJSON();
+ expect(propertyRights).to.be.empty;
+ });
+
+ async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
+ await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}]))
+ .to.be.fulfilled;
+
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ await expect(collection.setTokenPropertyPermissions(bob, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]))
+ .to.be.fulfilled;
+
+ const propertyRights = await collection.getPropertyPermissions(['skullduggery', 'mindgame']);
+ expect(propertyRights).to.include.deep.members([
+ {key: 'skullduggery', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}},
+ {key: 'mindgame', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
+ ]);
+ }
+
+ itSub('Sets access rights to properties of a collection (NFT)', async ({helper}) => {
+ await testSetsAccessRightsToProperties(await helper.nft.mintCollection(alice));
+ });
+
+ itSub.ifWithPallets('Sets access rights to properties of a collection (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice));
+ });
+
+ async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) {
+ await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]))
+ .to.be.fulfilled;
+
+ await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
+ .to.be.fulfilled;
+
+ const propertyRights = await collection.getPropertyPermissions();
+ expect(propertyRights).to.be.deep.equal([
+ {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
+ ]);
+ }
+
+ itSub('Changes access rights to properties of a NFT collection', async ({helper}) => {
+ await testChangesAccessRightsToProperty(await helper.nft.mintCollection(alice));
+ });
+
+ itSub.ifWithPallets('Changes access rights to properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
+ await testChangesAccessRightsToProperty(await helper.rft.mintCollection(alice));
+ });
+});
+
+describe('Negative Integration Test: Access Rights to Token Properties', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+ });
+ });
+
+ async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) {
+ await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]))
+ .to.be.rejectedWith(/common\.NoPermission/);
+
+ const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
+ expect(propertyRights).to.be.empty;
+ }
+
+ itSub('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async ({helper}) => {
+ await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.nft.mintCollection(alice));
+ });
+
+ itSub.ifWithPallets('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', [Pallets.ReFungible], async ({helper}) => {
+ await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice));
+ });
+
+ async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
+ const constitution = [];
+ for(let i = 0; i < 65; i++) {
+ constitution.push({
+ key: 'property_' + i,
+ permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
+ });
+ }
+
+ await expect(collection.setTokenPropertyPermissions(alice, constitution))
+ .to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+ const propertyRights = await collection.getPropertyPermissions();
+ expect(propertyRights).to.be.empty;
+ }
+
+ itSub('Prevents from adding too many possible properties (NFT)', async ({helper}) => {
+ await testPreventFromAddingTooManyPossibleProperties(await helper.nft.mintCollection(alice));
+ });
+
+ itSub.ifWithPallets('Prevents from adding too many possible properties (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice));
+ });
+
+ async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) {
+ await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
+ .to.be.fulfilled;
+
+ await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {collectionAdmin: true}}]))
+ .to.be.rejectedWith(/common\.NoPermission/);
+
+ const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
+ expect(propertyRights).to.deep.equal([
+ {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
+ ]);
+ }
+
+ itSub('Prevents access rights to be modified if constant (NFT)', async ({helper}) => {
+ await testPreventAccessRightsModifiedIfConstant(await helper.nft.mintCollection(alice));
+ });
+
+ itSub.ifWithPallets('Prevents access rights to be modified if constant (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice));
+ });
+
+ async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) {
+ const invalidProperties = [
+ [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
+ [{key: 'G#4', permission: {tokenOwner: true}}],
+ [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],
+ ];
+
+ for(let i = 0; i < invalidProperties.length; i++) {
+ await expect(
+ collection.setTokenPropertyPermissions(alice, invalidProperties[i]),
+ `on setting the new badly-named property #${i}`,
+ ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
+ }
+
+ await expect(
+ collection.setTokenPropertyPermissions(alice, [{key: '', permission: {}}]),
+ 'on rejecting an unnamed property',
+ ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
+
+ const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string
+ await expect(
+ collection.setTokenPropertyPermissions(alice, [
+ {key: correctKey, permission: {collectionAdmin: true}},
+ ]),
+ 'on setting the correctly-but-still-badly-named property',
+ ).to.be.fulfilled;
+
+ const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');
+
+ const propertyRights = await collection.getPropertyPermissions(keys);
+ expect(propertyRights).to.be.deep.equal([
+ {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
+ ]);
+ }
+
+ itSub('Prevents adding properties with invalid names (NFT)', async ({helper}) => {
+ await testPreventsAddingPropertiesWithInvalidNames(await helper.nft.mintCollection(alice));
+ });
+
+ itSub.ifWithPallets('Prevents adding properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ await testPreventsAddingPropertiesWithInvalidNames(await helper.rft.mintCollection(alice));
+ });
+});
js-packages/tests/nesting/tokenProperties.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/tokenProperties.seqtest.ts
@@ -0,0 +1,71 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
+
+describe('Integration Test: Token Properties with sudo', () => {
+ let superuser: IKeyringPair;
+ let alice: IKeyringPair; // collection owner
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ superuser = await privateKey('//Alice');
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, pieces: undefined, requiredPallets: []} as const,
+ {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
+ ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+ before(async function() {
+ // eslint-disable-next-line require-await
+ await usingPlaygrounds(async helper => {
+ requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+ });
+ });
+
+ itSub('force_repair_item preserves valid consumed space', async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testSuite.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [
+ {
+ key: propKey,
+ permission: {mutable: true, tokenOwner: true},
+ },
+ ],
+ });
+ const token = await (
+ testSuite.pieces
+ ? collection.mintToken(alice, testSuite.pieces as any)
+ : collection.mintToken(alice)
+ );
+
+ const prop = {key: propKey, value: 'a'.repeat(4096)};
+
+ await token.setProperties(alice, [prop]);
+ const originalSpace = await token.getTokenPropertiesConsumedSpace();
+ expect(originalSpace).to.be.equal(sizeOfProperty(prop));
+
+ await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true);
+ const recomputedSpace = await token.getTokenPropertiesConsumedSpace();
+ expect(recomputedSpace).to.be.equal(originalSpace);
+ });
+ }));
+});
js-packages/tests/nesting/tokenProperties.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/tokenProperties.test.ts
@@ -0,0 +1,816 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect, sizeOfProperty} from '../util/index.js';
+import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/unique.js';
+
+describe('Integration Test: Token Properties', () => {
+ let alice: IKeyringPair; // collection owner
+ let bob: IKeyringPair; // collection admin
+ let charlie: IKeyringPair; // token owner
+
+ let permissions: {permission: any, signers: IKeyringPair[]}[];
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);
+ });
+
+ permissions = [
+ {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},
+ {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},
+ {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},
+ {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},
+ {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
+ {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
+ ];
+ });
+
+ async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
+ const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
+ tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+ signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+ });
+ return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
+ }
+
+ async function testReadsYetEmptyProperties(token: UniqueNFToken | UniqueRFToken) {
+ const properties = await token.getProperties();
+ expect(properties).to.be.empty;
+
+ const tokenData = await token.getData();
+ expect(tokenData!.properties).to.be.empty;
+ }
+
+ itSub('Reads yet empty properties of a token (NFT)', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ const token = await collection.mintToken(alice);
+ await testReadsYetEmptyProperties(token);
+ });
+
+ itSub.ifWithPallets('Reads yet empty properties of a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice);
+ const token = await collection.mintToken(alice);
+ await testReadsYetEmptyProperties(token);
+ });
+
+ async function testAssignPropertiesAccordingToPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ await token.collection.addAdmin(alice, {Substrate: bob.address});
+ await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+ const propertyKeys: string[] = [];
+ let i = 0;
+ for(const permission of permissions) {
+ i++;
+ let j = 0;
+ for(const signer of permission.signers) {
+ j++;
+ const key = i + '_' + signer.address;
+ propertyKeys.push(key);
+
+ await expect(
+ token.setProperties(signer, [{key: key, value: 'Serotonin increase'}]),
+ `on adding property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+ }
+ }
+
+ const properties = await token.getProperties(propertyKeys);
+ const tokenData = await token.getData();
+ for(let i = 0; i < properties.length; i++) {
+ expect(properties[i].value).to.be.equal('Serotonin increase');
+ expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
+ }
+ }
+
+ itSub('Assigns properties to a token according to permissions (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testAssignPropertiesAccordingToPermissions(token, amount);
+ });
+
+ itSub.ifWithPallets('Assigns properties to a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testAssignPropertiesAccordingToPermissions(token, amount);
+ });
+
+ async function testChangesPropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ await token.collection.addAdmin(alice, {Substrate: bob.address});
+ await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+ const propertyKeys: string[] = [];
+ let i = 0;
+ for(const permission of permissions) {
+ i++;
+ if(!permission.permission.mutable) continue;
+
+ let j = 0;
+ for(const signer of permission.signers) {
+ j++;
+ const key = i + '_' + signer.address;
+ propertyKeys.push(key);
+
+ await expect(
+ token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+ `on adding property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+
+ await expect(
+ token.setProperties(signer, [{key, value: 'Serotonin stable'}]),
+ `on changing property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+ }
+ }
+
+ const properties = await token.getProperties(propertyKeys);
+ const tokenData = await token.getData();
+ for(let i = 0; i < properties.length; i++) {
+ expect(properties[i].value).to.be.equal('Serotonin stable');
+ expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
+ }
+ }
+
+ itSub('Changes properties of a token according to permissions (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testChangesPropertiesAccordingPermission(token, amount);
+ });
+
+ itSub.ifWithPallets('Changes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testChangesPropertiesAccordingPermission(token, amount);
+ });
+
+ async function testDeletePropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ await token.collection.addAdmin(alice, {Substrate: bob.address});
+ await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+ const propertyKeys: string[] = [];
+ let i = 0;
+
+ for(const permission of permissions) {
+ i++;
+ if(!permission.permission.mutable) continue;
+
+ let j = 0;
+ for(const signer of permission.signers) {
+ j++;
+ const key = i + '_' + signer.address;
+ propertyKeys.push(key);
+
+ await expect(
+ token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+ `on adding property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+
+ await expect(
+ token.deleteProperties(signer, [key]),
+ `on deleting property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+ }
+ }
+
+ expect(await token.getProperties(propertyKeys)).to.be.empty;
+ expect((await token.getData())!.properties).to.be.empty;
+ }
+
+ itSub('Deletes properties of a token according to permissions (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testDeletePropertiesAccordingPermission(token, amount);
+ });
+
+ itSub.ifWithPallets('Deletes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testDeletePropertiesAccordingPermission(token, amount);
+ });
+
+ itSub('Assigns properties to a nested token according to permissions', async ({helper}) => {
+ const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const collectionB = await helper.nft.mintCollection(alice, {
+ tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+ signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+ });
+ const targetToken = await collectionA.mintToken(alice);
+ const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
+
+ await collectionB.addAdmin(alice, {Substrate: bob.address});
+ await targetToken.transfer(alice, {Substrate: charlie.address});
+
+ const propertyKeys: string[] = [];
+ let i = 0;
+ for(const permission of permissions) {
+ i++;
+ let j = 0;
+ for(const signer of permission.signers) {
+ j++;
+ const key = i + '_' + signer.address;
+ propertyKeys.push(key);
+
+ await expect(
+ nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+ `on adding property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+ }
+ }
+
+ const properties = await nestedToken.getProperties(propertyKeys);
+ const tokenData = await nestedToken.getData();
+ for(let i = 0; i < properties.length; i++) {
+ expect(properties[i].value).to.be.equal('Serotonin increase');
+ expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
+ }
+ expect(await targetToken.getProperties()).to.be.empty;
+ });
+
+ itSub('Changes properties of a nested token according to permissions', async ({helper}) => {
+ const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const collectionB = await helper.nft.mintCollection(alice, {
+ tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+ signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+ });
+ const targetToken = await collectionA.mintToken(alice);
+ const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
+
+ await collectionB.addAdmin(alice, {Substrate: bob.address});
+ await targetToken.transfer(alice, {Substrate: charlie.address});
+
+ const propertyKeys: string[] = [];
+ let i = 0;
+ for(const permission of permissions) {
+ i++;
+ if(!permission.permission.mutable) continue;
+
+ let j = 0;
+ for(const signer of permission.signers) {
+ j++;
+ const key = i + '_' + signer.address;
+ propertyKeys.push(key);
+
+ await expect(
+ nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+ `on adding property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+
+ await expect(
+ nestedToken.setProperties(signer, [{key, value: 'Serotonin stable'}]),
+ `on changing property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+ }
+ }
+
+ const properties = await nestedToken.getProperties(propertyKeys);
+ const tokenData = await nestedToken.getData();
+ for(let i = 0; i < properties.length; i++) {
+ expect(properties[i].value).to.be.equal('Serotonin stable');
+ expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
+ }
+ expect(await targetToken.getProperties()).to.be.empty;
+ });
+
+ itSub('Deletes properties of a nested token according to permissions', async ({helper}) => {
+ const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const collectionB = await helper.nft.mintCollection(alice, {
+ tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+ signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+ });
+ const targetToken = await collectionA.mintToken(alice);
+ const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
+
+ await collectionB.addAdmin(alice, {Substrate: bob.address});
+ await targetToken.transfer(alice, {Substrate: charlie.address});
+
+ const propertyKeys: string[] = [];
+ let i = 0;
+ for(const permission of permissions) {
+ i++;
+ if(!permission.permission.mutable) continue;
+
+ let j = 0;
+ for(const signer of permission.signers) {
+ j++;
+ const key = i + '_' + signer.address;
+ propertyKeys.push(key);
+
+ await expect(
+ nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+ `on adding property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+
+ await expect(
+ nestedToken.deleteProperties(signer, [key]),
+ `on deleting property #${i} by signer #${j}`,
+ ).to.be.fulfilled;
+ }
+ }
+
+ expect(await nestedToken.getProperties(propertyKeys)).to.be.empty;
+ expect((await nestedToken.getData())!.properties).to.be.empty;
+ expect(await targetToken.getProperties()).to.be.empty;
+ });
+
+ [
+ {mode: 'nft' as const, storage: 'nonfungible' as const, pieces: undefined, requiredPallets: []} as const,
+ {mode: 'rft' as const, storage: 'refungible' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
+ ].map(testCase =>
+ itSub.ifWithPallets(`Allows modifying a token property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [
+ {
+ key: propKey,
+ permission: {mutable: true, tokenOwner: true},
+ },
+ ],
+ });
+
+ const maxTokenPropertiesSize = 32768;
+
+ const propDataSize = 4096;
+
+ let propDataChar = 'a';
+ const makeNewPropData = () => {
+ propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
+ return `${propDataChar}`.repeat(propDataSize);
+ };
+
+ const token = await (
+ testCase.pieces
+ ? collection.mintToken(alice, testCase.pieces as any)
+ : collection.mintToken(alice)
+ );
+
+ const property = {key: propKey, value: makeNewPropData()};
+ await token.setProperties(alice, [property]);
+ const originalSpace = await token.getTokenPropertiesConsumedSpace();
+ expect(originalSpace).to.be.equal(sizeOfProperty(property));
+
+ const sameSizePropertiesPossibleNum = maxTokenPropertiesSize / propDataSize;
+
+ // It is possible to modify a property as many times as needed.
+ // It will not consume any additional space.
+ for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
+ await token.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
+ const consumedSpace = await token.getTokenPropertiesConsumedSpace();
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }
+ }));
+
+ [
+ {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+ {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itSub.ifWithPallets(`Adding then removing a token property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [
+ {
+ key: propKey,
+ permission: {mutable: true, tokenOwner: true},
+ },
+ ],
+ });
+ const token = await (
+ testCase.pieces
+ ? collection.mintToken(alice, testCase.pieces as any)
+ : collection.mintToken(alice)
+ );
+ const originalSpace = await token.getTokenPropertiesConsumedSpace();
+
+ const propDataSize = 4096;
+ const propData = 'a'.repeat(propDataSize);
+
+ const property = {key: propKey, value: propData};
+ await token.setProperties(alice, [property]);
+ let consumedSpace = await token.getTokenPropertiesConsumedSpace();
+ expect(consumedSpace).to.be.equal(sizeOfProperty(property));
+
+ await token.deleteProperties(alice, [propKey]);
+ consumedSpace = await token.getTokenPropertiesConsumedSpace();
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }));
+
+ [
+ {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+ {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itSub.ifWithPallets(`Modifying a token property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [
+ {
+ key: propKey,
+ permission: {mutable: true, tokenOwner: true},
+ },
+ ],
+ });
+ const token = await (
+ testCase.pieces
+ ? collection.mintToken(alice, testCase.pieces as any)
+ : collection.mintToken(alice)
+ );
+ const originalSpace = await token.getTokenPropertiesConsumedSpace();
+
+ const initProp = {key: propKey, value: 'a'.repeat(4096)};
+ const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
+ const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
+
+ let consumedSpace;
+ let expectedConsumedSpaceDiff;
+
+ await token.setProperties(alice, [initProp]);
+ consumedSpace = await token.getTokenPropertiesConsumedSpace();
+ expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
+ expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
+
+ await token.setProperties(alice, [biggerProp]);
+ consumedSpace = await token.getTokenPropertiesConsumedSpace();
+ expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
+ expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
+
+ await token.setProperties(alice, [smallerProp]);
+ consumedSpace = await token.getTokenPropertiesConsumedSpace();
+ expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
+ expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
+ }));
+
+ itSub('Set sponsored properties', async({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true}}]});
+
+ await collection.setSponsor(alice, alice.address);
+ await collection.confirmSponsorship(alice);
+ await collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
+ await collection.addToAllowList(alice, {Substrate: bob.address});
+ await collection.setLimits(alice, {sponsoredDataRateLimit: {blocks: 30}});
+
+ const token = await collection.mintToken(alice, {Substrate: bob.address});
+
+ const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+ const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ await token.setProperties(bob, [{key: 'k', value: 'val'}]);
+
+ const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+ const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobBalanceAfter).to.be.equal(bobBalanceBefore);
+ expect(aliceBalanceBefore > aliceBalanceAfter).to.be.true;
+ });
+});
+
+describe('Negative Integration Test: Token Properties', () => {
+ let alice: IKeyringPair; // collection owner
+ let bob: IKeyringPair; // collection admin
+ let charlie: IKeyringPair; // token owner
+
+ let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ let dave: IKeyringPair;
+ [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
+
+ // todo:playgrounds probably separate these tests later
+ constitution = [
+ {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
+ {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
+ {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},
+ {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},
+ {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
+ {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
+ ];
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: [Pallets.NFT]},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itSub.ifWithPallets(`Forbids adding/deleting properties of a token if token doesn't exist (${testCase.mode.toLocaleUpperCase})`, testCase.requiredPallets, async({helper}) => {
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: constitution.slice(0, 1).map(({permission}) => ({key: '1', permission})),
+ });
+ const nonExistentToken = collection.getTokenObject(1);
+
+ await expect(
+ nonExistentToken.setProperties(alice, [{key: '1', value: 'Serotonin increase'}]),
+ 'on expecting failure whilst adding a property by alice',
+ ).to.be.rejectedWith(/common\.TokenNotFound/);
+
+ await expect(
+ nonExistentToken.deleteProperties(alice, ['1']),
+ 'on expecting failure whilst deleting a property by alice',
+ ).to.be.rejectedWith(/common\.TokenNotFound/);
+ }));
+
+ async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
+ const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
+ tokenPropertyPermissions: constitution.map(({permission}, i) => ({key: `${i+1}`, permission})),
+ });
+ return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
+ }
+
+ async function getConsumedSpace(api: any, collectionId: number, tokenId: number, mode: 'NFT' | 'RFT'): Promise<number> {
+ return (await (mode == 'NFT' ? api.query.nonfungible : api.query.refungible).tokenProperties(collectionId, tokenId)).toJSON().consumedSpace;
+ }
+
+ async function prepare(token: UniqueNFToken | UniqueRFToken, pieces: bigint): Promise<number> {
+ await token.collection.addAdmin(alice, {Substrate: bob.address});
+ await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+ let i = 0;
+ for(const passage of constitution) {
+ i++;
+ const signer = passage.signers[0];
+ await expect(
+ token.setProperties(signer, [{key: `${i}`, value: 'Serotonin increase'}]),
+ `on adding property ${i} by ${signer.address}`,
+ ).to.be.fulfilled;
+ }
+
+ const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+ return originalSpace;
+ }
+
+ async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ const originalSpace = await prepare(token, pieces);
+
+ let i = 0;
+ for(const forbiddance of constitution) {
+ i++;
+ if(!forbiddance.permission.mutable) continue;
+
+ await expect(
+ token.setProperties(forbiddance.sinner, [{key: `${i}`, value: 'Serotonin down'}]),
+ `on failing to change property ${i} by the malefactor`,
+ ).to.be.rejectedWith(/common\.NoPermission/);
+
+ await expect(
+ token.deleteProperties(forbiddance.sinner, [`${i}`]),
+ `on failing to delete property ${i} by the malefactor`,
+ ).to.be.rejectedWith(/common\.NoPermission/);
+ }
+
+ const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }
+
+ itSub('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
+ });
+
+ itSub.ifWithPallets('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
+ });
+
+ async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ const originalSpace = await prepare(token, pieces);
+
+ let i = 0;
+ for(const permission of constitution) {
+ i++;
+ if(permission.permission.mutable) continue;
+
+ await expect(
+ token.setProperties(permission.signers[0], [{key: `${i}`, value: 'Serotonin down'}]),
+ `on failing to change property ${i} by signer #0`,
+ ).to.be.rejectedWith(/common\.NoPermission/);
+
+ await expect(
+ token.deleteProperties(permission.signers[0], [i.toString()]),
+ `on failing to delete property ${i} by signer #0`,
+ ).to.be.rejectedWith(/common\.NoPermission/);
+ }
+
+ const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }
+
+ itSub('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
+ });
+
+ itSub.ifWithPallets('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
+ });
+
+ async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ const originalSpace = await prepare(token, pieces);
+
+ await expect(
+ token.setProperties(alice, [{key: 'non-existent', value: 'I exist!'}]),
+ 'on failing to add a previously non-existent property',
+ ).to.be.rejectedWith(/common\.NoPermission/);
+
+ await expect(
+ token.collection.setTokenPropertyPermissions(alice, [{key: 'now-existent', permission: {}}]),
+ 'on setting a new non-permitted property',
+ ).to.be.fulfilled;
+
+ await expect(
+ token.setProperties(alice, [{key: 'now-existent', value: 'I exist!'}]),
+ 'on failing to add a property forbidden by the \'None\' permission',
+ ).to.be.rejectedWith(/common\.NoPermission/);
+
+ expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty;
+
+ const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }
+
+ itSub('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
+ });
+
+ itSub.ifWithPallets('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
+ });
+
+ async function testForbidsAddingTooLargeProperties(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+ const originalSpace = await prepare(token, pieces);
+
+ await expect(
+ token.collection.setTokenPropertyPermissions(alice, [
+ {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}},
+ {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},
+ ]),
+ 'on setting new permissions for properties',
+ ).to.be.fulfilled;
+
+ // Mute the general tx parsing error
+ {
+ console.error = () => {};
+ await expect(token.setProperties(alice, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]))
+ .to.be.rejected;
+ }
+
+ await expect(token.setProperties(alice, [
+ {key: 'a_holy_book', value: 'word '.repeat(3277)},
+ {key: 'young_years', value: 'neverending'.repeat(1490)},
+ ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+ expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty;
+ const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+ expect(consumedSpace).to.be.equal(originalSpace);
+ }
+
+ itSub('Forbids adding too large properties to a token (NFT)', async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+ await testForbidsAddingTooLargeProperties(token, amount);
+ });
+
+ itSub.ifWithPallets('Forbids adding too large properties to a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+ const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+ await testForbidsAddingTooLargeProperties(token, amount);
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itSub.ifWithPallets(`Forbids adding too many propeties to a token (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+ const collection = await helper[testCase.mode].mintCollection(alice);
+ const maxPropertiesPerItem = 64;
+
+ for(let i = 0; i < maxPropertiesPerItem; i++) {
+ await collection.setTokenPropertyPermissions(alice, [{
+ key: `${i+1}`,
+ permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+ }]);
+ }
+
+ await expect(collection.setTokenPropertyPermissions(alice, [{
+ key: `${maxPropertiesPerItem}-th`,
+ permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+ }])).to.be.rejectedWith(/common\.PropertyLimitReached/);
+ }));
+
+ [
+ {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+ {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase =>
+ itSub.ifWithPallets(`Forbids force_repair_item from non-sudo (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+ const propKey = 'tok-prop';
+
+ const collection = await helper[testCase.mode].mintCollection(alice, {
+ tokenPropertyPermissions: [
+ {
+ key: propKey,
+ permission: {mutable: true, tokenOwner: true},
+ },
+ ],
+ });
+ const token = await (
+ testCase.pieces
+ ? collection.mintToken(alice, testCase.pieces as any)
+ : collection.mintToken(alice)
+ );
+
+ const propDataSize = 4096;
+ const propData = 'a'.repeat(propDataSize);
+ await token.setProperties(alice, [{key: propKey, value: propData}]);
+
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true))
+ .to.be.rejectedWith(/BadOrigin/);
+ }));
+});
+
+describe('ReFungible token properties permissions tests', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ async function prepare(helper: UniqueHelper): Promise<UniqueRFToken> {
+ const collection = await helper.rft.mintCollection(alice);
+ const token = await collection.mintToken(alice, 100n);
+
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable: true, tokenOwner: true}}]);
+
+ return token;
+ }
+
+ itSub('Forbids adding token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) => {
+ const token = await prepare(helper);
+
+ await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+ await expect(token.setProperties(alice, [
+ {key: 'fractals', value: 'multiverse'},
+ ])).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Forbids mutating token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) => {
+ const token = await prepare(helper);
+
+ await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, tokenOwner: true}}]))
+ .to.be.fulfilled;
+
+ await expect(token.setProperties(alice, [
+ {key: 'fractals', value: 'multiverse'},
+ ])).to.be.fulfilled;
+
+ await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+ await expect(token.setProperties(alice, [
+ {key: 'fractals', value: 'want to rule the world'},
+ ])).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Forbids deleting token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) => {
+ const token = await prepare(helper);
+
+ await expect(token.setProperties(alice, [
+ {key: 'fractals', value: 'one headline - why believe it'},
+ ])).to.be.fulfilled;
+
+ await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+ await expect(token.deleteProperties(alice, ['fractals'])).
+ to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Allows token property mutation with collectionOwner==true when admin doesn\'t have all pieces', async ({helper}) => {
+ const token = await prepare(helper);
+
+ await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+ await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, collectionAdmin: true}}]))
+ .to.be.fulfilled;
+
+ await expect(token.setProperties(alice, [
+ {key: 'fractals', value: 'multiverse'},
+ ])).to.be.fulfilled;
+ });
+});
js-packages/tests/nesting/unnest.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nesting/unnest.test.ts
@@ -0,0 +1,325 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from '../util/index.js';
+import {CrossAccountId, UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/unique.js';
+
+describe('Integration Test: Unnesting', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);
+ });
+ });
+
+ itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ // Create a nested token
+ const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+
+ // Unnest
+ await expect(nestedToken.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}), 'while unnesting').to.be.fulfilled;
+ expect(await nestedToken.getOwner()).to.be.deep.equal({Substrate: alice.address});
+
+ // Nest and burn
+ await nestedToken.nest(alice, targetToken);
+ await expect(nestedToken.burnFrom(alice, targetToken.nestingAccount()), 'while burning').to.be.fulfilled;
+ await expect(nestedToken.getOwner()).to.be.rejected;
+ });
+
+ itSub('NativeFungible: allows the owner to successfully unnest a token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ const collectionFT = helper.ft.getCollectionObject(0);
+
+ // Nest
+ await collectionFT.transfer(alice, targetToken.nestingAccount(), 10n);
+ // Unnest
+ await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
+
+ expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+ });
+
+ itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ const collectionFT = await helper.ft.mintCollection(alice);
+
+ // Nest and unnest
+ await collectionFT.mint(alice, 10n, targetToken.nestingAccount());
+ await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
+ expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(9n);
+ expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+
+ // Nest and burn
+ await collectionFT.transfer(alice, targetToken.nestingAccount(), 5n);
+ await expect(collectionFT.burnTokensFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
+ expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(4n);
+ expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
+ expect(await targetToken.getChildren()).to.be.length(0);
+ });
+
+ itSub.ifWithPallets('ReFungible: allows the owner to successfully unnest a token', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ const collectionRFT = await helper.rft.mintCollection(alice);
+
+ // Nest and unnest
+ const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());
+ await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);
+ expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+
+ // Nest and burn
+ await token.transfer(alice, targetToken.nestingAccount(), 5n);
+ await expect(token.burnFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(4n);
+ expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
+ expect(await targetToken.getChildren()).to.be.length(0);
+ });
+
+ async function checkNestedAmountState({
+ expectedBalance,
+ childrenShouldPresent,
+ nested,
+ targetNft,
+ }: {
+ expectedBalance: bigint,
+ childrenShouldPresent: boolean,
+ nested: UniqueFTCollection | UniqueRFToken,
+ targetNft: UniqueNFToken,
+ }) {
+ const balance = await nested.getBalance(targetNft.nestingAccount());
+ expect(balance).to.be.equal(expectedBalance);
+
+ const children = await targetNft.getChildren();
+
+ if(childrenShouldPresent) {
+ expect(children[0]).to.be.deep.equal({
+ collectionId: nested.collectionId,
+ tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,
+ });
+ } else {
+ expect(children.length).to.be.equal(0);
+ }
+ }
+
+ function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {
+ mode: 'ft' | 'nft' | 'rft',
+ sender: string,
+ op: 'transfer' | 'burn',
+ requiredPallets: Pallets[],
+ }[] {
+ const senders = ['owner', 'admin'];
+ const ops = ['transfer', 'burn'];
+
+ const cases = [];
+ for(const mode of modes) {
+ const requiredPallets = (mode === 'rft')
+ ? [Pallets.ReFungible]
+ : [];
+
+ for(const sender of senders) {
+ for(const op of ops) {
+ cases.push({
+ mode: mode as 'ft' | 'nft' | 'rft',
+ sender,
+ op: op as 'transfer' | 'burn',
+ requiredPallets,
+ });
+ }
+ }
+ }
+
+ return cases;
+ }
+
+ ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>
+ itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {
+ const owner = alice;
+ const admin = bob;
+
+ const unnester = (testCase.sender === 'owner')
+ ? owner
+ : admin;
+
+ const collectionNFT = await helper.nft.mintCollection(owner);
+ await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
+
+ const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ await collectionNested.addAdmin(owner, {Substrate: admin.address});
+
+ const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
+
+ let nested: UniqueFTCollection | UniqueRFToken;
+ const totalAmount = 5n;
+ const firstUnnestAmount = 2n;
+ const restUnnestAmount = totalAmount - firstUnnestAmount;
+
+ if(collectionNested instanceof UniqueFTCollection) {
+ await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});
+ nested = collectionNested;
+ } else {
+ nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});
+ }
+
+ // transfer/burn `amount` of nested assets by `unnester`.
+ const doOperationAndCheck = async ({
+ amount,
+ shouldBeNestedAfterOp,
+ }: {
+ amount: bigint,
+ shouldBeNestedAfterOp: boolean,
+ }) => {
+ const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());
+
+ if(testCase.op === 'transfer') {
+ const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});
+
+ await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);
+ expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);
+ } else {
+ if(nested instanceof UniqueFTCollection) {
+ await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);
+ } else {
+ await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);
+ }
+ }
+
+ await checkNestedAmountState({
+ expectedBalance: nestedBalanceBeforeOp - amount,
+ childrenShouldPresent: shouldBeNestedAfterOp,
+ nested,
+ targetNft,
+ });
+ };
+
+ // Initial setup: nest (fungibles/rft parts).
+ // Check NFT's balance of nested assets and NFT's children.
+ await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);
+ await checkNestedAmountState({
+ expectedBalance: totalAmount,
+ childrenShouldPresent: true,
+ nested,
+ targetNft,
+ });
+
+ // Transfer/burn only a part of nested assets.
+ // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.
+ await doOperationAndCheck({
+ amount: firstUnnestAmount,
+ shouldBeNestedAfterOp: true,
+ });
+
+ // Transfer/burn all remaining nested assets.
+ // Check that NFT's balance of the nested assets is 0 and NFT has no more children.
+ await doOperationAndCheck({
+ amount: restUnnestAmount,
+ shouldBeNestedAfterOp: false,
+ });
+ }));
+
+ ownerOrAdminUnnestCases(['nft']).map(testCase =>
+ itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {
+ const owner = alice;
+ const admin = bob;
+
+ const unnester = (testCase.sender === 'owner')
+ ? owner
+ : admin;
+
+ const collectionNFT = await helper.nft.mintCollection(owner);
+ await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
+
+ const collectionNested = await helper.nft.mintCollection(owner, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ await collectionNested.addAdmin(owner, {Substrate: admin.address});
+
+ const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
+ const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});
+
+ await nested.transfer(charlie, targetNft.nestingAccount());
+ expect(await targetNft.getChildren()).to.be.deep.equal([{
+ collectionId: nested.collectionId,
+ tokenId: nested.tokenId,
+ }]);
+
+ if(testCase.op === 'transfer') {
+ await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});
+ } else {
+ await nested.burnFrom(unnester, targetNft.nestingAccount());
+ }
+
+ expect((await targetNft.getChildren()).length).to.be.equal(0);
+ }));
+});
+
+describe('Negative Test: Unnesting', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+ });
+ });
+
+ itSub('Disallows a non-owner to unnest/burn a token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ // Create a nested token
+ const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+
+ // Try to unnest
+ await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+
+ // Try to burn
+ await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+ });
+
+ // todo another test for creating excessive depth matryoshka with Ethereum?
+
+ // Recursive nesting
+ itSub('Prevents Ouroboros creation', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ // Fail to create a nested token ouroboros
+ const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+ await expect(targetToken.nest(alice, nestedToken)).to.be.rejectedWith(/^structure\.OuroborosDetected$/);
+ });
+});
js-packages/tests/nextSponsoring.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/nextSponsoring.test.ts
@@ -0,0 +1,97 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from './util/index.js';
+
+const SPONSORING_TIMEOUT = 5;
+
+describe('Integration Test getNextSponsored(collection_id, owner, item_id):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
+ });
+ });
+
+ itSub('NFT', async ({helper}) => {
+ // Non-existing collection
+ expect(await helper.collection.getTokenNextSponsored(0, 0, {Substrate: alice.address})).to.be.null;
+
+ const collection = await helper.nft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice);
+
+ // Check with Disabled sponsoring state
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null;
+
+ // Check with Unconfirmed sponsoring state
+ await collection.setSponsor(alice, bob.address);
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null;
+
+ // Check with Confirmed sponsoring state
+ await collection.confirmSponsorship(bob);
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.equal(0);
+
+ // Check after transfer
+ await token.transfer(alice, {Substrate: bob.address});
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
+
+ // Non-existing token
+ expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
+ });
+
+ itSub('Fungible', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {});
+ await collection.mint(alice, 10n);
+
+ // Check with Disabled sponsoring state
+ expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
+
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+
+ // Check with Confirmed sponsoring state
+ expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.equal(0);
+
+ // Check after transfer
+ await collection.transfer(alice, {Substrate: bob.address});
+ expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
+ });
+
+ itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {});
+ const token = await collection.mintToken(alice, 10n);
+
+ // Check with Disabled sponsoring state
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null;
+
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+
+ // Check with Confirmed sponsoring state
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.equal(0);
+
+ // Check after transfer
+ await token.transfer(alice, {Substrate: bob.address});
+ expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
+
+ // Non-existing token
+ expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
+ });
+});
js-packages/tests/package.jsondiffbeforeafterboth--- a/js-packages/tests/package.json
+++ b/js-packages/tests/package.json
@@ -20,13 +20,12 @@
"typescript": "^5.1.6"
},
"scripts": {
- "setup": "ts-node --esm ./src/util/globalSetup.ts",
- "setIdentities": "ts-node --esm ./src/util/identitySetter.ts",
- "checkRelayIdentities": "ts-node --esm ./src/util/relayIdentitiesChecker.ts",
- "frankenstein": "ts-node --esm ./src/util/frankenstein.ts",
+ "setup": "ts-node --esm ./util/globalSetup.ts",
+ "setIdentities": "ts-node --esm ./util/identitySetter.ts",
+ "checkRelayIdentities": "ts-node --esm ./util/relayIdentitiesChecker.ts",
"_test": "yarn setup && mocha --timeout 9999999 --loader=ts-node/esm.mjs",
"_testParallel": "yarn setup && mocha --timeout 9999999 --parallel --loader=ts-node/esm.mjs",
- "test": "yarn _test './src/**/*.*test.ts'",
+ "test": "yarn _test './**/*.*test.ts'",
"load": "yarn _test './**/*.load.ts'"
}
}
js-packages/tests/pallet-presence.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/pallet-presence.test.ts
@@ -0,0 +1,130 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+
+// Pallets that must always be present
+const requiredPallets = [
+ 'balances',
+ 'balancesadapter',
+ 'common',
+ 'timestamp',
+ 'transactionpayment',
+ 'treasury',
+ 'statetriemigration',
+ 'structure',
+ 'system',
+ 'utility',
+ 'vesting',
+ 'parachainsystem',
+ 'parachaininfo',
+ 'evm',
+ 'evmcodersubstrate',
+ 'evmcontracthelpers',
+ 'evmmigration',
+ 'evmtransactionpayment',
+ 'ethereum',
+ 'fungible',
+ 'xcmpqueue',
+ 'polkadotxcm',
+ 'cumulusxcm',
+ 'dmpqueue',
+ 'inflation',
+ 'unique',
+ 'nonfungible',
+ 'charging',
+ 'configuration',
+ 'tokens',
+ 'xtokens',
+ 'maintenance',
+];
+
+// Pallets that depend on consensus and governance configuration
+const consensusPallets = [
+ 'sudo',
+ 'aura',
+ 'auraext',
+];
+
+describe('Pallet presence', () => {
+ before(async () => {
+ await usingPlaygrounds(async helper => {
+ const runtimeVersion = await helper.callRpc('api.rpc.state.getRuntimeVersion', []);
+ const chain = runtimeVersion.specName;
+
+ const refungible = 'refungible';
+ const foreignAssets = 'foreignassets';
+ const appPromotion = 'apppromotion';
+ const collatorSelection = ['authorship', 'session', 'collatorselection'];
+ const preimage = ['preimage'];
+ const governance = [
+ 'council',
+ 'councilmembership',
+ 'democracy',
+ 'fellowshipcollective',
+ 'fellowshipreferenda',
+ 'origins',
+ 'scheduler',
+ 'technicalcommittee',
+ 'technicalcommitteemembership',
+ 'identity',
+ ];
+ const testUtils = 'testutils';
+
+ if(chain.eq('opal')) {
+ requiredPallets.push(
+ refungible,
+ foreignAssets,
+ appPromotion,
+ testUtils,
+ ...collatorSelection,
+ ...preimage,
+ ...governance,
+ );
+ } else if(chain.eq('quartz') || chain.eq('sapphire')) {
+ requiredPallets.push(
+ refungible,
+ appPromotion,
+ foreignAssets,
+ ...collatorSelection,
+ ...preimage,
+ ...governance,
+ );
+ } else if(chain.eq('unique')) {
+ // Insert Unique additional pallets here
+ requiredPallets.push(
+ refungible,
+ foreignAssets,
+ appPromotion,
+ ...preimage,
+ ...governance,
+ );
+ }
+ });
+ });
+
+ itSub('Required pallets are present', ({helper}) => {
+ expect(helper.fetchAllPalletNames()).to.contain.members([...requiredPallets].sort());
+ });
+
+ itSub('Governance and consensus pallets are present', ({helper}) => {
+ expect(helper.fetchAllPalletNames()).to.contain.members([...consensusPallets].sort());
+ });
+
+ itSub('No extra pallets are included', ({helper}) => {
+ expect(helper.fetchAllPalletNames().sort()).to.be.deep.equal([...requiredPallets, ...consensusPallets].sort());
+ });
+});
js-packages/tests/performance.seq.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/performance.seq.test.ts
@@ -0,0 +1,125 @@
+// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {ApiPromise} from '@polkadot/api';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from './util/index.js';
+import type {ICrossAccountId, IProperty} from '@unique/playgrounds/types.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+
+describe('Performace tests', () => {
+ let alice: IKeyringPair;
+ const MAX_TOKENS_TO_MINT = 120;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([100_000n], donor);
+ });
+ });
+
+ itSub('NFT tokens minting', async ({helper}) => {
+ const propertyKey = 'prop-a';
+ const collection = await helper.nft.mintCollection(alice, {
+ name: 'test properties',
+ description: 'test properties collection',
+ tokenPrefix: 'TPC',
+ tokenPropertyPermissions: [
+ {key: propertyKey, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
+ ],
+ });
+
+ const step = 1_000;
+ const sizeOfKey = sizeOfEncodedStr(propertyKey);
+ let currentSize = step;
+ let startCount = 0;
+ let minterFunc = tryMintUnsafeRPC;
+ try {
+ startCount = await tryMintUnsafeRPC(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});
+ }
+ catch (e) {
+ startCount = await tryMintExplicit(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});
+ minterFunc = tryMintExplicit;
+ }
+
+ expect(startCount).to.be.equal(MAX_TOKENS_TO_MINT);
+
+ while(currentSize <= 32_000) {
+ const property = {key: propertyKey, value: 'A'.repeat(currentSize - sizeOfKey - sizeOfInt(currentSize))};
+ const tokens = await minterFunc(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address}, property);
+ expect(tokens).to.be.equal(MAX_TOKENS_TO_MINT);
+
+ currentSize += step;
+ await helper.wait.newBlocks(2);
+ }
+ });
+});
+
+
+const dryRun = async (api: ApiPromise, signer: IKeyringPair, tx: any) => {
+ const signed = await tx.signAsync(signer);
+ const dryRun = await api.rpc.system.dryRun(signed.toHex());
+ return dryRun.isOk && dryRun.asOk.isOk;
+};
+
+const getTokens = (tokensCount: number, owner: ICrossAccountId, property?: IProperty) => (new Array(tokensCount)).fill(0).map(() => {
+ const token = {owner} as {owner: ICrossAccountId, properties?: IProperty[]};
+ if(property) token.properties = [property];
+ return token;
+});
+
+const tryMintUnsafeRPC = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {
+ if(tokensCount < 10) console.log('try mint', tokensCount, 'tokens');
+ const tokens = getTokens(tokensCount, owner, property);
+ const tx = helper.constructApiCall('api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
+ if(!(await dryRun(helper.getApi(), signer, tx))) {
+ if(tokensCount < 2) return 0;
+ return await tryMintUnsafeRPC(helper, signer, tokensCount - 1, collectionId, owner, property);
+ }
+ await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
+ return tokensCount;
+};
+
+const tryMintExplicit = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {
+ const tokens = getTokens(tokensCount, owner, property);
+ try {
+ await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
+ }
+ catch (e) {
+ if(tokensCount < 2) return 0;
+ return await tryMintExplicit(helper, signer, tokensCount - 1, collectionId, owner, property);
+ }
+ return tokensCount;
+};
+
+function sizeOfInt(i: number) {
+ if(i < 0 || i > 0xffffffff) throw new Error('out of range');
+ if(i < 0b11_1111) {
+ return 1;
+ } else if(i < 0b11_1111_1111_1111) {
+ return 2;
+ } else if(i < 0b11_1111_1111_1111_1111_1111_1111_1111) {
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+const UTF8_ENCODER = new TextEncoder();
+function sizeOfEncodedStr(v: string) {
+ const encoded = UTF8_ENCODER.encode(v);
+ return sizeOfInt(encoded.length) + encoded.length;
+}
js-packages/tests/refungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/refungible.test.ts
@@ -0,0 +1,132 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from './util/index.js';
+
+const MAX_REFUNGIBLE_PIECES = 1_000_000_000_000_000_000_000n;
+
+describe('integration test: Refungible functionality:', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+ });
+ });
+
+ itSub('Create refungible collection and token', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const itemCountBefore = await collection.getLastTokenId();
+ const token = await collection.mintToken(alice, 100n);
+
+ const itemCountAfter = await collection.getLastTokenId();
+
+ // What to expect
+ expect(token?.tokenId).to.be.gte(itemCountBefore);
+ expect(itemCountAfter).to.be.equal(itemCountBefore + 1);
+ expect(itemCountAfter.toString()).to.be.equal(token?.tokenId.toString());
+ });
+
+ itSub('Checking RPC methods when interacting with maximum allowed values (MAX_REFUNGIBLE_PIECES)', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const token = await collection.mintToken(alice, MAX_REFUNGIBLE_PIECES);
+
+ expect(await collection.getTokenBalance(token.tokenId, {Substrate: alice.address})).to.be.equal(MAX_REFUNGIBLE_PIECES);
+
+ await collection.transferToken(alice, token.tokenId, {Substrate: bob.address}, MAX_REFUNGIBLE_PIECES);
+ expect(await collection.getTokenBalance(token.tokenId, {Substrate: bob.address})).to.be.equal(MAX_REFUNGIBLE_PIECES);
+ expect(await token.getTotalPieces()).to.be.equal(MAX_REFUNGIBLE_PIECES);
+
+ await expect(collection.mintToken(alice, MAX_REFUNGIBLE_PIECES + 1n))
+ .to.eventually.be.rejectedWith(/refungible\.WrongRefungiblePieces/);
+ });
+
+ itSub('RPC method tokenOwners for refungible collection and token', async ({helper}) => {
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const facelessCrowd = (await helper.arrange.createAccounts(Array(7).fill(0n), donor)).map(keyring => ({Substrate: keyring.address}));
+
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+ const token = await collection.mintToken(alice, 10_000n);
+
+ await token.transfer(alice, {Substrate: bob.address}, 1000n);
+ await token.transfer(alice, ethAcc, 900n);
+
+ for(let i = 0; i < 7; i++) {
+ await token.transfer(alice, facelessCrowd[i], 50n * BigInt(i + 1));
+ }
+
+ const owners = await token.getTop10Owners();
+
+ // What to expect
+ expect(owners).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]);
+ expect(owners.length).to.be.equal(10);
+
+ const [eleven] = await helper.arrange.createAccounts([0n], donor);
+ expect(await token.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true;
+ expect((await token.getTop10Owners()).length).to.be.equal(10);
+ });
+
+ itSub('Create multiple tokens', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ // TODO: fix mintMultipleTokens
+ // await collection.mintMultipleTokens(alice, [
+ // {owner: {Substrate: alice.address}, pieces: 1n},
+ // {owner: {Substrate: alice.address}, pieces: 2n},
+ // {owner: {Substrate: alice.address}, pieces: 100n},
+ // ]);
+ await helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, [
+ {pieces: 1n},
+ {pieces: 2n},
+ {pieces: 100n},
+ ]);
+ const lastTokenId = await collection.getLastTokenId();
+ expect(lastTokenId).to.be.equal(3);
+ expect(await collection.getTokenBalance(lastTokenId, {Substrate: alice.address})).to.be.equal(100n);
+ });
+
+ itSub('Set allowance for token', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n);
+
+ expect(await token.approve(alice, {Substrate: bob.address}, 60n)).to.be.true;
+ expect(await token.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(60n);
+
+ expect(await token.transferFrom(bob, {Substrate: alice.address}, {Substrate: bob.address}, 20n)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(80n);
+ expect(await token.getBalance({Substrate: bob.address})).to.be.equal(20n);
+ expect(await token.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(40n);
+ });
+
+ itSub('Create new collection with properties', async ({helper}) => {
+ const properties = [{key: 'key1', value: 'val1'}];
+ const tokenPropertyPermissions = [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}];
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test', properties, tokenPropertyPermissions});
+ const info = await collection.getData();
+ expect(info?.raw.properties).to.be.deep.equal(properties);
+ expect(info?.raw.tokenPropertyPermissions).to.be.deep.equal(tokenPropertyPermissions);
+ });
+});
js-packages/tests/removeCollectionAdmin.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/removeCollectionAdmin.test.ts
@@ -0,0 +1,113 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test removeCollectionAdmin(collection_id, account_id):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
+ });
+ });
+
+ itSub('Remove collection admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-1', tokenPrefix: 'RCA'});
+ const collectionInfo = await collection.getData();
+ expect(collectionInfo?.raw.owner.toString()).to.be.deep.eq(alice.address);
+ // first - add collection admin Bob
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ const adminListAfterAddAdmin = await collection.getAdmins();
+ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
+
+ // then remove bob from admins of collection
+ await collection.removeAdmin(alice, {Substrate: bob.address});
+
+ const adminListAfterRemoveAdmin = await collection.getAdmins();
+ expect(adminListAfterRemoveAdmin).not.to.be.deep.contains({Substrate: bob.address});
+ });
+
+ itSub('Remove admin from collection that has no admins', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-2', tokenPrefix: 'RCA'});
+
+ const adminListBeforeAddAdmin = await collection.getAdmins();
+ expect(adminListBeforeAddAdmin).to.have.lengthOf(0);
+
+ await expect(collection.removeAdmin(alice, {Substrate: alice.address})).to.be.rejectedWith('common.UserIsNotCollectionAdmin');
+ });
+});
+
+describe('Negative Integration Test removeCollectionAdmin(collection_id, account_id):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('Can\'t remove collection admin from not existing collection', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+
+ await expect(helper.collection.removeAdmin(alice, collectionId, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Can\'t remove collection admin from deleted collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-2', tokenPrefix: 'RCA'});
+
+ expect(await collection.burn(alice)).to.be.true;
+
+ await expect(helper.collection.removeAdmin(alice, collection.collectionId, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Regular user can\'t remove collection admin', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-3', tokenPrefix: 'RCA'});
+
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ await expect(collection.removeAdmin(charlie, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('Admin can\'t remove collection admin.', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-4', tokenPrefix: 'RCA'});
+
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await collection.addAdmin(alice, {Substrate: charlie.address});
+
+ const adminListAfterAddAdmin = await collection.getAdmins();
+ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
+ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: charlie.address});
+
+ await expect(collection.removeAdmin(charlie, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.NoPermission/);
+
+ const adminListAfterRemoveAdmin = await collection.getAdmins();
+ expect(adminListAfterRemoveAdmin).to.be.deep.contains({Substrate: bob.address});
+ expect(adminListAfterRemoveAdmin).to.be.deep.contains({Substrate: charlie.address});
+ });
+});
js-packages/tests/removeCollectionSponsor.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/removeCollectionSponsor.test.ts
@@ -0,0 +1,126 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('integration test: ext. removeCollectionSponsor():', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('Removing NFT collection sponsor stops sponsorship', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-1', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ await collection.removeSponsor(alice);
+
+ // Find unused address
+ const [zeroBalance] = await helper.arrange.createAccounts([0n], donor);
+
+ // Mint token for unused address
+ const token = await collection.mintToken(alice, {Substrate: zeroBalance.address});
+
+ // Transfer this tokens from unused address to Alice - should fail
+ const sponsorBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ await expect(token.transfer(zeroBalance, {Substrate: alice.address}))
+ .to.be.rejectedWith('Inability to pay some fees');
+ const sponsorBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);
+ });
+
+ itSub('Remove a sponsor after it was already removed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-2', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ await expect(collection.removeSponsor(alice)).to.not.be.rejected;
+ await expect(collection.removeSponsor(alice)).to.not.be.rejected;
+ });
+
+ itSub('Remove sponsor in a collection that never had the sponsor set', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-3', tokenPrefix: 'RCS'});
+ await expect(collection.removeSponsor(alice)).to.not.be.rejected;
+ });
+
+ itSub('Remove sponsor for a collection that had the sponsor set, but not confirmed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-4', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await expect(collection.removeSponsor(alice)).to.not.be.rejected;
+ });
+
+ itSub('Remove a sponsor from a collection with collection admin permissions', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-1', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.addAdmin(alice, {Substrate: charlie.address});
+ await expect(collection.removeSponsor(charlie)).not.to.be.rejected;
+ });
+});
+
+describe('(!negative test!) integration test: ext. removeCollectionSponsor():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('(!negative test!) Remove sponsor for a collection that never existed', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ await expect(helper.collection.removeSponsor(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('(!negative test!) Remove sponsor for a collection by regular user', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-2', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await expect(collection.removeSponsor(charlie)).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('(!negative test!) Remove sponsor in a destroyed collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-3', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.burn(alice);
+ await expect(collection.removeSponsor(alice)).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('Set - remove - confirm: fails', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-4', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.removeSponsor(alice);
+ await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ });
+
+ itSub('Set - confirm - remove - confirm: Sponsor cannot come back', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-5', tokenPrefix: 'RCS'});
+ await collection.setSponsor(alice, bob.address);
+ await collection.confirmSponsorship(bob);
+ await collection.removeSponsor(alice);
+ await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
+ });
+});
js-packages/tests/rpc.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/rpc.test.ts
@@ -0,0 +1,68 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect} from './util/index.js';
+import {ICrossAccountId} from '@unique/playgrounds/types.js';
+
+describe('integration test: RPC methods', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
+ });
+ });
+
+ itSub('returns None for fungible collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'RPC-1', tokenPrefix: 'RPC'});
+ const owner = (await helper.callRpc('api.rpc.unique.tokenOwner', [collection.collectionId, 0])).toJSON() as any;
+ expect(owner).to.be.null;
+ });
+
+ itSub('RPC method tokenOwners for fungible collection and token', async ({helper}) => {
+ // Set-up a few token owners of all stripes
+ const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+ const facelessCrowd = (await helper.arrange.createAccounts([0n, 0n, 0n, 0n, 0n, 0n, 0n], donor))
+ .map(i => ({Substrate: i.address}));
+
+ const collection = await helper.ft.mintCollection(alice, {name: 'RPC-2', tokenPrefix: 'RPC'});
+ // mint some maximum (u128) amounts of tokens possible
+ await collection.mint(alice, (1n << 128n) - 1n);
+
+ await collection.transfer(alice, {Substrate: bob.address}, 1000n);
+ await collection.transfer(alice, ethAcc, 900n);
+
+ for(let i = 0; i < facelessCrowd.length; i++) {
+ await collection.transfer(alice, facelessCrowd[i], 1n);
+ }
+ // Set-up over
+
+ const owners = await helper.callRpc('api.rpc.unique.tokenOwners', [collection.collectionId, 0]);
+ const ids = owners.toHuman() as ICrossAccountId[];
+
+ expect(ids).to.have.deep.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]);
+ expect(owners.length == 10).to.be.true;
+
+ // Make sure only 10 results are returned with this RPC
+ const [eleven] = await helper.arrange.createAccounts([0n], donor);
+ expect(await collection.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true;
+ expect((await helper.callRpc('api.rpc.unique.tokenOwners', [collection.collectionId, 0])).length).to.be.equal(10);
+ });
+});
js-packages/tests/scheduler.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/scheduler.seqtest.ts
@@ -0,0 +1,796 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util/index.js';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
+
+describe('Scheduling token and balance transfers', () => {
+ let superuser: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.UniqueScheduler]);
+
+ superuser = await privateKey('//Alice');
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+
+ await helper.testUtils.enable(Pallets.TestUtils);
+ });
+ });
+
+ beforeEach(async () => {
+ await usingPlaygrounds(async (helper) => {
+ await helper.wait.noScheduledTasks();
+ });
+ });
+
+ itSched('Can delay a transfer of an owned token', async (scheduleKind, {helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(alice);
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const blocksBeforeExecution = 4;
+ await helper.scheduler.scheduleAfter(blocksBeforeExecution, {scheduledId})
+ .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
+ const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ });
+
+ itSched('Can transfer funds periodically', async (scheduleKind, {helper}) => {
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const waitForBlocks = 1;
+
+ const amount = 1n * helper.balance.getOneTokenNominal();
+ const periodic = {
+ period: 2,
+ repetitions: 2,
+ };
+
+ const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic})
+ .balance.transferToSubstrate(alice, bob.address, amount);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);
+ expect(bobsBalanceAfterFirst)
+ .to.be.equal(
+ bobsBalanceBefore + 1n * amount,
+ '#1 Balance of the recipient should be increased by 1 * amount',
+ );
+
+ await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
+
+ const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);
+ expect(bobsBalanceAfterSecond)
+ .to.be.equal(
+ bobsBalanceBefore + 2n * amount,
+ '#2 Balance of the recipient should be increased by 2 * amount',
+ );
+ });
+
+ itSub('Can cancel a scheduled operation which has not yet taken effect', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(alice);
+
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 4;
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
+ .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.scheduler.cancelScheduled(alice, scheduledId);
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('Can cancel a periodic operation (transfer of funds)', async ({helper}) => {
+ const waitForBlocks = 1;
+ const periodic = {
+ period: 3,
+ repetitions: 2,
+ };
+
+ const scheduledId = helper.arrange.makeScheduledId();
+
+ const amount = 1n * helper.balance.getOneTokenNominal();
+
+ const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic})
+ .balance.transferToSubstrate(alice, bob.address, amount);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);
+
+ expect(bobsBalanceAfterFirst)
+ .to.be.equal(
+ bobsBalanceBefore + 1n * amount,
+ '#1 Balance of the recipient should be increased by 1 * amount',
+ );
+
+ await helper.scheduler.cancelScheduled(alice, scheduledId);
+ await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
+
+ const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);
+ expect(bobsBalanceAfterSecond)
+ .to.be.equal(
+ bobsBalanceAfterFirst,
+ '#2 Balance of the recipient should not be changed',
+ );
+ });
+
+ itSched('scheduler will not insert more tasks than allowed', async (scheduleKind, {helper}) => {
+ const maxScheduledPerBlock = 50;
+ let fillScheduledIds = new Array(maxScheduledPerBlock);
+ let extraScheduledId = undefined;
+
+ if(scheduleKind == 'named') {
+ const scheduledIds = helper.arrange.makeScheduledIds(maxScheduledPerBlock + 1);
+ fillScheduledIds = scheduledIds.slice(0, maxScheduledPerBlock);
+ extraScheduledId = scheduledIds[maxScheduledPerBlock];
+ }
+
+ // Since the dev node has Instant Seal,
+ // we need a larger gap between the current block and the target one.
+ //
+ // We will schedule `maxScheduledPerBlock` transaction into the target block,
+ // so we need at least `maxScheduledPerBlock`-wide gap.
+ // We add some additional blocks to this gap to mitigate possible PolkadotJS delays.
+ const waitForBlocks = await helper.arrange.isDevNode() ? maxScheduledPerBlock + 5 : 5;
+
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks;
+
+ const amount = 1n * helper.balance.getOneTokenNominal();
+
+ const balanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ // Fill the target block
+ for(let i = 0; i < maxScheduledPerBlock; i++) {
+ await helper.scheduler.scheduleAt(executionBlock, {scheduledId: fillScheduledIds[i]})
+ .balance.transferToSubstrate(superuser, bob.address, amount);
+ }
+
+ // Try to schedule a task into a full block
+ await expect(helper.scheduler.scheduleAt(executionBlock, {scheduledId: extraScheduledId})
+ .balance.transferToSubstrate(superuser, bob.address, amount))
+ .to.be.rejectedWith(/scheduler\.AgendaIsExhausted/);
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const balanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(balanceAfter > balanceBefore).to.be.true;
+
+ const diff = balanceAfter - balanceBefore;
+ expect(diff).to.be.equal(amount * BigInt(maxScheduledPerBlock));
+ });
+
+ itSched.ifWithPallets('Scheduled tasks are transactional', [Pallets.TestUtils], async (scheduleKind, {helper}) => {
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const waitForBlocks = 4;
+
+ const initTestVal = 42;
+ const changedTestVal = 111;
+
+ await helper.testUtils.setTestValue(alice, initTestVal);
+
+ await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId})
+ .testUtils.setTestValueAndRollback(alice, changedTestVal);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const testVal = await helper.testUtils.testValue();
+ expect(testVal, 'The test value should NOT be commited')
+ .to.be.equal(initTestVal);
+ });
+
+ itSched.ifWithPallets('Scheduled tasks should take correct fees', [Pallets.TestUtils], async function(scheduleKind, {helper}) {
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const waitForBlocks = 4;
+ const periodic = {
+ period: 2,
+ repetitions: 2,
+ };
+
+ const dummyTx = helper.constructApiCall('api.tx.testUtils.justTakeFee', []);
+ const scheduledLen = dummyTx.callIndex.length;
+
+ const expectedScheduledFee = (await helper.getPaymentInfo(alice, dummyTx, scheduledLen))
+ .partialFee.toBigInt();
+
+ await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId, periodic})
+ .testUtils.justTakeFee(alice);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ const aliceInitBalance = await helper.balance.getSubstrate(alice.address);
+ let diff;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const aliceBalanceAfterFirst = await helper.balance.getSubstrate(alice.address);
+ expect(
+ aliceBalanceAfterFirst < aliceInitBalance,
+ '[after execution #1] Scheduled task should take a fee',
+ ).to.be.true;
+
+ diff = aliceInitBalance - aliceBalanceAfterFirst;
+ expect(diff).to.be.equal(
+ expectedScheduledFee,
+ 'Scheduled task should take the right amount of fees',
+ );
+
+ await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
+
+ const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);
+ expect(
+ aliceBalanceAfterSecond < aliceBalanceAfterFirst,
+ '[after execution #2] Scheduled task should take a fee',
+ ).to.be.true;
+
+ diff = aliceBalanceAfterFirst - aliceBalanceAfterSecond;
+ expect(diff).to.be.equal(
+ expectedScheduledFee,
+ 'Scheduled task should take the right amount of fees',
+ );
+ });
+
+ // Check if we can cancel a scheduled periodic operation
+ // in the same block in which it is running
+ itSub.ifWithPallets('Can cancel the periodic sheduled tx when the tx is running', [Pallets.TestUtils], async ({helper}) => {
+ const currentBlockNumber = await helper.chain.getLatestBlockNumber();
+ const blocksBeforeExecution = 10;
+ const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
+
+ const [
+ scheduledId,
+ scheduledCancelId,
+ ] = helper.arrange.makeScheduledIds(2);
+
+ const periodic = {
+ period: 5,
+ repetitions: 5,
+ };
+
+ const initTestVal = 0;
+ const incTestVal = initTestVal + 1;
+ const finalTestVal = initTestVal + 2;
+
+ await helper.testUtils.setTestValue(alice, initTestVal);
+
+ await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {scheduledId, periodic})
+ .testUtils.incTestValue(alice);
+
+ // Cancel the inc tx after 2 executions
+ // *in the same block* in which the second execution is scheduled
+ await helper.scheduler.scheduleAt(
+ firstExecutionBlockNumber + periodic.period,
+ {scheduledId: scheduledCancelId},
+ ).scheduler.cancelScheduled(alice, scheduledId);
+
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
+
+ // execution #0
+ expect(await helper.testUtils.testValue())
+ .to.be.equal(incTestVal);
+
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);
+
+ // execution #1
+ expect(await helper.testUtils.testValue())
+ .to.be.equal(finalTestVal);
+
+ for(let i = 1; i < periodic.repetitions; i++) {
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period * (i + 1));
+ expect(await helper.testUtils.testValue())
+ .to.be.equal(finalTestVal);
+ }
+ });
+
+ itSub.ifWithPallets('A scheduled operation can cancel itself', [Pallets.TestUtils], async ({helper}) => {
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 4;
+ const periodic = {
+ period: 2,
+ repetitions: 5,
+ };
+
+ const initTestVal = 0;
+ const maxTestVal = 2;
+
+ await helper.testUtils.setTestValue(alice, initTestVal);
+
+ await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId, periodic})
+ .testUtils.selfCancelingInc(alice, scheduledId, maxTestVal);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ // execution #0
+ expect(await helper.testUtils.testValue())
+ .to.be.equal(initTestVal + 1);
+
+ await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
+
+ // execution #1
+ expect(await helper.testUtils.testValue())
+ .to.be.equal(initTestVal + 2);
+
+ await helper.wait.forParachainBlockNumber(executionBlock + 2 * periodic.period);
+
+ // <canceled>
+ expect(await helper.testUtils.testValue())
+ .to.be.equal(initTestVal + 2);
+ });
+
+ itSub('Root can cancel any scheduled operation', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(bob);
+
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 4;
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
+ .nft.transferToken(bob, collection.collectionId, token.tokenId, {Substrate: alice.address});
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.getSudo().scheduler.cancelScheduled(superuser, scheduledId);
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ });
+
+ itSched('Root can set prioritized scheduled operation', async (scheduleKind, {helper}) => {
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const waitForBlocks = 4;
+
+ const amount = 42n * helper.balance.getOneTokenNominal();
+
+ const balanceBefore = await helper.balance.getSubstrate(charlie.address);
+
+ await helper.getSudo()
+ .scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42})
+ .balance.forceTransferToSubstrate(superuser, bob.address, charlie.address, amount);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const balanceAfter = await helper.balance.getSubstrate(charlie.address);
+
+ expect(balanceAfter > balanceBefore).to.be.true;
+
+ const diff = balanceAfter - balanceBefore;
+ expect(diff).to.be.equal(amount);
+ });
+
+ itSub("Root can change scheduled operation's priority", async ({helper}) => {
+ const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(bob);
+
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 6;
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
+ .nft.transferToken(bob, collection.collectionId, token.tokenId, {Substrate: alice.address});
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ const priority = 112;
+ await helper.getSudo().scheduler.changePriority(superuser, scheduledId, priority);
+
+ const priorityChanged = await helper.wait.expectEvent(waitForBlocks, Event.UniqueScheduler.PriorityChanged);
+
+ const [blockNumber, index] = priorityChanged.task();
+ expect(blockNumber).to.be.equal(executionBlock);
+ expect(index).to.be.equal(0);
+
+ expect(priorityChanged.priority().toString()).to.be.equal(priority.toString());
+ });
+
+ itSub('Prioritized operations execute in valid order', async ({helper}) => {
+ const [
+ scheduledFirstId,
+ scheduledSecondId,
+ ] = helper.arrange.makeScheduledIds(2);
+
+ const currentBlockNumber = await helper.chain.getLatestBlockNumber();
+ const blocksBeforeExecution = 6;
+ const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
+
+ const prioHigh = 0;
+ const prioLow = 255;
+
+ const periodic = {
+ period: 6,
+ repetitions: 2,
+ };
+
+ const amount = 1n * helper.balance.getOneTokenNominal();
+
+ // Scheduler a task with a lower priority first, then with a higher priority
+ await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, {
+ scheduledId: scheduledFirstId,
+ priority: prioLow,
+ periodic,
+ }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);
+
+ await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, {
+ scheduledId: scheduledSecondId,
+ priority: prioHigh,
+ periodic,
+ }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);
+
+ const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');
+
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
+
+ // Flip priorities
+ await helper.getSudo().scheduler.changePriority(superuser, scheduledFirstId, prioHigh);
+ await helper.getSudo().scheduler.changePriority(superuser, scheduledSecondId, prioLow);
+
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);
+
+ const dispatchEvents = capture.extractCapturedEvents();
+ expect(dispatchEvents.length).to.be.equal(4);
+
+ const dispatchedIds = dispatchEvents.map(r => r.event.data[1].toString());
+
+ const firstExecuctionIds = [dispatchedIds[0], dispatchedIds[1]];
+ const secondExecuctionIds = [dispatchedIds[2], dispatchedIds[3]];
+
+ expect(firstExecuctionIds[0]).to.be.equal(scheduledSecondId);
+ expect(firstExecuctionIds[1]).to.be.equal(scheduledFirstId);
+
+ expect(secondExecuctionIds[0]).to.be.equal(scheduledFirstId);
+ expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);
+ });
+
+ itSched('Periodic operations always can be rescheduled', async (scheduleKind, {helper}) => {
+ const maxScheduledPerBlock = 50;
+ const numFilledBlocks = 3;
+ const ids = helper.arrange.makeScheduledIds(numFilledBlocks * maxScheduledPerBlock + 1);
+ const periodicId = scheduleKind == 'named' ? ids[0] : undefined;
+ const fillIds = ids.slice(1);
+
+ const fillScheduleFn = scheduleKind == 'named' ? 'scheduleNamed' : 'schedule';
+
+ const initTestVal = 0;
+ const firstExecTestVal = 1;
+ const secondExecTestVal = 2;
+ await helper.testUtils.setTestValue(alice, initTestVal);
+
+ const currentBlockNumber = await helper.chain.getLatestBlockNumber();
+ const blocksBeforeExecution = 8;
+ const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
+
+ const period = 5;
+
+ const periodic = {
+ period,
+ repetitions: 2,
+ };
+
+ // Fill `numFilledBlocks` blocks beginning from the block in which the second execution should occur
+ const txs = [];
+ for(let offset = 0; offset < numFilledBlocks; offset ++) {
+ for(let i = 0; i < maxScheduledPerBlock; i++) {
+
+ const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]);
+
+ const when = firstExecutionBlockNumber + period + offset;
+ const mandatoryArgs = [when, null, null, scheduledTx];
+ const scheduleArgs = scheduleKind == 'named'
+ ? [fillIds[i + offset * maxScheduledPerBlock], ...mandatoryArgs]
+ : mandatoryArgs;
+
+ const tx = helper.constructApiCall(`api.tx.scheduler.${fillScheduleFn}`, scheduleArgs);
+
+ txs.push(tx);
+ }
+ }
+ await helper.executeExtrinsic(alice, 'api.tx.testUtils.batchAll', [txs], true);
+
+ await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {
+ scheduledId: periodicId,
+ periodic,
+ }).testUtils.incTestValue(alice);
+
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
+ expect(await helper.testUtils.testValue()).to.be.equal(firstExecTestVal);
+
+ await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + period + numFilledBlocks);
+
+ // The periodic operation should be postponed by `numFilledBlocks`
+ for(let i = 0; i < numFilledBlocks; i++) {
+ expect(await helper.testUtils.testValue(firstExecutionBlockNumber + period + i)).to.be.equal(firstExecTestVal);
+ }
+
+ // After the `numFilledBlocks` the periodic operation will eventually be executed
+ expect(await helper.testUtils.testValue()).to.be.equal(secondExecTestVal);
+ });
+
+ itSched('scheduled operations does not change nonce', async (scheduleKind, {helper}) => {
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const blocksBeforeExecution = 4;
+
+ await helper.scheduler
+ .scheduleAfter<DevUniqueHelper>(blocksBeforeExecution, {scheduledId})
+ .balance.transferToSubstrate(alice, bob.address, 1n);
+ const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;
+
+ const initNonce = await helper.chain.getNonce(alice.address);
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const finalNonce = await helper.chain.getNonce(alice.address);
+
+ expect(initNonce).to.be.equal(finalNonce);
+ });
+});
+
+describe('Negative Test: Scheduling', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.UniqueScheduler]);
+
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+
+ await helper.testUtils.enable(Pallets.TestUtils);
+ });
+ });
+
+ itSub("Can't overwrite a scheduled ID", async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(alice);
+
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 4;
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
+ .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId});
+ await expect(scheduled.balance.transferToSubstrate(alice, bob.address, 1n * helper.balance.getOneTokenNominal()))
+ .to.be.rejectedWith(/scheduler\.FailedToSchedule/);
+
+ const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(bobsBalanceBefore).to.be.equal(bobsBalanceAfter);
+ });
+
+ itSub("Can't cancel an operation which is not scheduled", async ({helper}) => {
+ const scheduledId = helper.arrange.makeScheduledId();
+ await expect(helper.scheduler.cancelScheduled(alice, scheduledId))
+ .to.be.rejectedWith(/scheduler\.NotFound/);
+ });
+
+ itSub("Can't cancel a non-owned scheduled operation", async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(alice);
+
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 4;
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
+ .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await expect(helper.scheduler.cancelScheduled(bob, scheduledId))
+ .to.be.rejectedWith(/BadOrigin/);
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ });
+
+ itSched("Regular user can't set prioritized scheduled operation", async (scheduleKind, {helper}) => {
+ const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
+ const waitForBlocks = 4;
+
+ const amount = 42n * helper.balance.getOneTokenNominal();
+
+ const balanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42});
+
+ await expect(scheduled.balance.transferToSubstrate(alice, bob.address, amount))
+ .to.be.rejectedWith(/BadOrigin/);
+
+ const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
+
+ await helper.wait.forParachainBlockNumber(executionBlock);
+
+ const balanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(balanceAfter).to.be.equal(balanceBefore);
+ });
+
+ itSub("Regular user can't change scheduled operation's priority", async ({helper}) => {
+ const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});
+ const token = await collection.mintToken(bob);
+
+ const scheduledId = helper.arrange.makeScheduledId();
+ const waitForBlocks = 4;
+
+ await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
+ .nft.transferToken(bob, collection.collectionId, token.tokenId, {Substrate: alice.address});
+
+ const priority = 112;
+ await expect(helper.scheduler.changePriority(alice, scheduledId, priority))
+ .to.be.rejectedWith(/BadOrigin/);
+
+ await helper.wait.expectEvent(waitForBlocks, Event.UniqueScheduler.PriorityChanged);
+ });
+});
+
+// Implementation of the functionality tested here was postponed/shelved
+describe.skip('Sponsoring scheduling', () => {
+ // let alice: IKeyringPair;
+ // let bob: IKeyringPair;
+
+ // before(async() => {
+ // await usingApi(async (_, privateKey) => {
+ // alice = privateKey('//Alice');
+ // bob = privateKey('//Bob');
+ // });
+ // });
+
+ it('Can sponsor scheduling a transaction', async () => {
+ // const collectionId = await createCollectionExpectSuccess();
+ // await setCollectionSponsorExpectSuccess(collectionId, bob.address);
+ // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
+
+ // await usingApi(async api => {
+ // const scheduledId = await makeScheduledId();
+ // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
+
+ // const bobBalanceBefore = await getFreeBalance(bob);
+ // const waitForBlocks = 4;
+ // // no need to wait to check, fees must be deducted on scheduling, immediately
+ // await scheduleTransferExpectSuccess(api, collectionId, tokenId, alice, bob, 0, waitForBlocks, scheduledId);
+ // const bobBalanceAfter = await getFreeBalance(bob);
+ // // expect(aliceBalanceAfter == aliceBalanceBefore).to.be.true;
+ // expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
+ // // wait for sequentiality matters
+ // await waitNewBlocks(waitForBlocks - 1);
+ // });
+ });
+
+ it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => {
+ // await usingApi(async (api, privateKey) => {
+ // // Find an empty, unused account
+ // const zeroBalance = await findUnusedAddress(api, privateKey);
+
+ // const collectionId = await createCollectionExpectSuccess();
+
+ // // Add zeroBalance address to allow list
+ // await enablePublicMintingExpectSuccess(alice, collectionId);
+ // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
+
+ // // Grace zeroBalance with money, enough to cover future transactions
+ // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
+ // await submitTransactionAsync(alice, balanceTx);
+
+ // // Mint a fresh NFT
+ // const tokenId = await createItemExpectSuccess(zeroBalance, collectionId, 'NFT');
+ // const scheduledId = await makeScheduledId();
+
+ // // Schedule transfer of the NFT a few blocks ahead
+ // const waitForBlocks = 5;
+ // await scheduleTransferExpectSuccess(api, collectionId, tokenId, zeroBalance, alice, 1, waitForBlocks, scheduledId);
+
+ // // Get rid of the account's funds before the scheduled transaction takes place
+ // const balanceTx2 = api.tx.balances.transfer(alice.address, UNIQUE * 68n / 100n);
+ // const events = await submitTransactionAsync(zeroBalance, balanceTx2);
+ // expect(getGenericResult(events).success).to.be.true;
+ // /*const emptyBalanceTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); // do not null reserved?
+ // const sudoTx = api.tx.sudo.sudo(emptyBalanceTx as any);
+ // const events = await submitTransactionAsync(alice, sudoTx);
+ // expect(getGenericResult(events).success).to.be.true;*/
+
+ // // Wait for a certain number of blocks, discarding the ones that already happened while accepting the late transactions
+ // await waitNewBlocks(waitForBlocks - 3);
+
+ // expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(alice.address));
+ // });
+ });
+
+ it('Sponsor going bankrupt does not impact a scheduled transaction', async () => {
+ // const collectionId = await createCollectionExpectSuccess();
+
+ // await usingApi(async (api, privateKey) => {
+ // const zeroBalance = await findUnusedAddress(api, privateKey);
+ // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
+ // await submitTransactionAsync(alice, balanceTx);
+
+ // await setCollectionSponsorExpectSuccess(collectionId, zeroBalance.address);
+ // await confirmSponsorshipByKeyExpectSuccess(collectionId, zeroBalance);
+
+ // const scheduledId = await makeScheduledId();
+ // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
+
+ // const waitForBlocks = 5;
+ // await scheduleTransferExpectSuccess(api, collectionId, tokenId, alice, zeroBalance, 1, waitForBlocks, scheduledId);
+
+ // const emptyBalanceSponsorTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0);
+ // const sudoTx = api.tx.sudo.sudo(emptyBalanceSponsorTx as any);
+ // const events = await submitTransactionAsync(alice, sudoTx);
+ // expect(getGenericResult(events).success).to.be.true;
+
+ // // Wait for a certain number of blocks, save for the ones that already happened while accepting the late transactions
+ // await waitNewBlocks(waitForBlocks - 3);
+
+ // expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(zeroBalance.address));
+ // });
+ });
+
+ it('Exceeding sponsor rate limit without having enough funds prevents scheduling a periodic transaction', async () => {
+ // const collectionId = await createCollectionExpectSuccess();
+ // await setCollectionSponsorExpectSuccess(collectionId, bob.address);
+ // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
+
+ // await usingApi(async (api, privateKey) => {
+ // const zeroBalance = await findUnusedAddress(api, privateKey);
+
+ // await enablePublicMintingExpectSuccess(alice, collectionId);
+ // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
+
+ // const bobBalanceBefore = await getFreeBalance(bob);
+
+ // const createData = {nft: {const_data: [], variable_data: []}};
+ // const creationTx = api.tx.unique.createItem(collectionId, normalizeAccountId(zeroBalance), createData as any);
+ // const scheduledId = await makeScheduledId();
+
+ // /*const badTransaction = async function () {
+ // await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);
+ // };
+ // await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');*/
+
+ // await expect(scheduleAfter(api, creationTx, zeroBalance, 3, scheduledId, 1, 3)).to.be.rejectedWith(/Inability to pay some fees/);
+
+ // expect(await getFreeBalance(bob)).to.be.equal(bobBalanceBefore);
+ // });
+ });
+});
js-packages/tests/setCollectionLimits.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/setCollectionLimits.test.ts
@@ -0,0 +1,201 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+const accountTokenOwnershipLimit = 0;
+const sponsoredDataSize = 0;
+const sponsorTransferTimeout = 1;
+const tokenLimit = 10;
+
+describe('setCollectionLimits positive', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
+ });
+ });
+
+ itSub('execute setCollectionLimits with predefined params', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-1', tokenPrefix: 'SCL'});
+
+ await collection.setLimits(
+ alice,
+ {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: true,
+ ownerCanDestroy: true,
+ },
+ );
+
+ // get collection limits defined previously
+ const collectionInfo = await collection.getEffectiveLimits();
+
+ expect(collectionInfo.accountTokenOwnershipLimit).to.be.equal(accountTokenOwnershipLimit);
+ expect(collectionInfo.sponsoredDataSize).to.be.equal(sponsoredDataSize);
+ expect(collectionInfo.tokenLimit).to.be.equal(tokenLimit);
+ expect(collectionInfo.sponsorTransferTimeout).to.be.equal(sponsorTransferTimeout);
+ expect(collectionInfo.ownerCanTransfer).to.be.true;
+ expect(collectionInfo.ownerCanDestroy).to.be.true;
+ });
+
+ itSub('Set the same token limit twice', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-2', tokenPrefix: 'SCL'});
+
+ const collectionLimits = {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: true,
+ ownerCanDestroy: true,
+ };
+
+ await collection.setLimits(alice, collectionLimits);
+
+ const collectionInfo1 = await collection.getEffectiveLimits();
+
+ expect(collectionInfo1.tokenLimit).to.be.equal(tokenLimit);
+
+ await collection.setLimits(alice, collectionLimits);
+ const collectionInfo2 = await collection.getEffectiveLimits();
+ expect(collectionInfo2.tokenLimit).to.be.equal(tokenLimit);
+ });
+
+ itSub('execute setCollectionLimits from admin collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-3', tokenPrefix: 'SCL'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ const collectionLimits = {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ // sponsoredMintSize,
+ tokenLimit,
+ };
+
+ await expect(collection.setLimits(alice, collectionLimits)).to.not.be.rejected;
+ });
+});
+
+describe('setCollectionLimits negative', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
+ });
+ });
+
+ itSub('execute setCollectionLimits for not exists collection', async ({helper}) => {
+ const nonExistentCollectionId = NON_EXISTENT_COLLECTION_ID;
+ await expect(helper.collection.setLimits(
+ alice,
+ nonExistentCollectionId,
+ {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ // sponsoredMintSize,
+ tokenLimit,
+ },
+ )).to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('execute setCollectionLimits from user who is not owner of this collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-1', tokenPrefix: 'SCL'});
+
+ await expect(collection.setLimits(bob, {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ // sponsoredMintSize,
+ tokenLimit,
+ })).to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('fails when trying to enable OwnerCanTransfer after it was disabled', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-2', tokenPrefix: 'SCL'});
+
+ await collection.setLimits(alice, {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: false,
+ ownerCanDestroy: true,
+ });
+
+ await expect(collection.setLimits(alice, {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: true,
+ ownerCanDestroy: true,
+ })).to.be.rejectedWith(/common\.OwnerPermissionsCantBeReverted/);
+ });
+
+ itSub('fails when trying to enable OwnerCanDestroy after it was disabled', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-3', tokenPrefix: 'SCL'});
+
+ await collection.setLimits(alice, {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: true,
+ ownerCanDestroy: false,
+ });
+
+ await expect(collection.setLimits(alice, {
+ accountTokenOwnershipLimit,
+ sponsoredDataSize,
+ tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: true,
+ ownerCanDestroy: true,
+ })).to.be.rejectedWith(/common\.OwnerPermissionsCantBeReverted/);
+ });
+
+ itSub('Setting the higher token limit fails', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-4', tokenPrefix: 'SCL'});
+
+ const collectionLimits = {
+ accountTokenOwnershipLimit: accountTokenOwnershipLimit,
+ sponsoredMintSize: sponsoredDataSize,
+ tokenLimit: tokenLimit,
+ sponsorTransferTimeout,
+ ownerCanTransfer: true,
+ ownerCanDestroy: true,
+ };
+
+ // The first time
+ await collection.setLimits(alice, collectionLimits);
+
+ // The second time - higher token limit
+ collectionLimits.tokenLimit += 1;
+ await expect(collection.setLimits(alice, collectionLimits)).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
+ });
+});
js-packages/tests/setCollectionSponsor.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/setCollectionSponsor.test.ts
@@ -0,0 +1,120 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect, Pallets} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('integration test: ext. setCollectionSponsor():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('Set NFT collection sponsor', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-1-NFT', tokenPrefix: 'SCS'});
+ await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
+ Unconfirmed: bob.address,
+ });
+ });
+
+ itSub('Set Fungible collection sponsor', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'SetCollectionSponsor-1-FT', tokenPrefix: 'SCS'});
+ await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
+ Unconfirmed: bob.address,
+ });
+ });
+
+ itSub.ifWithPallets('Set ReFungible collection sponsor', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'SetCollectionSponsor-1-RFT', tokenPrefix: 'SCS'});
+ await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
+ Unconfirmed: bob.address,
+ });
+ });
+
+ itSub('Set the same sponsor repeatedly', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-2', tokenPrefix: 'SCS'});
+ await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
+ await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
+ Unconfirmed: bob.address,
+ });
+ });
+
+ itSub('Replace collection sponsor', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-3', tokenPrefix: 'SCS'});
+ await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
+ await expect(collection.setSponsor(alice, charlie.address)).to.be.not.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
+ Unconfirmed: charlie.address,
+ });
+ });
+
+ itSub('Collection admin add sponsor', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-4', tokenPrefix: 'SCS'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await expect(collection.setSponsor(bob, charlie.address)).to.be.not.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
+ Unconfirmed: charlie.address,
+ });
+ });
+});
+
+describe('(!negative test!) integration test: ext. setCollectionSponsor():', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([10n, 5n], donor);
+ });
+ });
+
+ itSub('(!negative test!) Add sponsor with a non-owner', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-Neg-1', tokenPrefix: 'SCS'});
+ await expect(collection.setSponsor(bob, bob.address))
+ .to.be.rejectedWith(/common\.NoPermission/);
+ });
+
+ itSub('(!negative test!) Add sponsor to a collection that never existed', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ await expect(helper.collection.setSponsor(alice, collectionId, bob.address))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('(!negative test!) Add sponsor to a collection that was destroyed', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-Neg-2', tokenPrefix: 'SCS'});
+ await collection.burn(alice);
+ await expect(collection.setSponsor(alice, bob.address))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+});
js-packages/tests/setPermissions.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/setPermissions.test.ts
@@ -0,0 +1,108 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test: Set Permissions', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+ });
+ });
+
+ itSub('can all be enabled twice', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-1', tokenPrefix: 'SP'});
+ expect((await collection.getData())?.raw.permissions.access).to.not.equal('AllowList');
+
+ await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}});
+ await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}});
+
+ const permissions = (await collection.getData())?.raw.permissions;
+ expect(permissions).to.be.deep.equal({
+ access: 'AllowList',
+ mintMode: true,
+ nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]},
+ });
+ });
+
+ itSub('can all be disabled twice', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-2', tokenPrefix: 'SP'});
+ expect((await collection.getData())?.raw.permissions.access).to.equal('Normal');
+
+ await collection.setPermissions(alice, {access: 'AllowList', nesting: {collectionAdmin: false, tokenOwner: true, restricted: [1, 2]}});
+ expect((await collection.getData())?.raw.permissions).to.be.deep.equal({
+ access: 'AllowList',
+ mintMode: false,
+ nesting: {collectionAdmin: false, tokenOwner: true, restricted: [1, 2]},
+ });
+
+ await collection.setPermissions(alice, {access: 'Normal', mintMode: false, nesting: {}});
+ await collection.setPermissions(alice, {access: 'Normal', mintMode: false, nesting: {}});
+ expect((await collection.getData())?.raw.permissions).to.be.deep.equal({
+ access: 'Normal',
+ mintMode: false,
+ nesting: {collectionAdmin: false, tokenOwner: false, restricted: null},
+ });
+ });
+
+ itSub('collection admin can set permissions', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-2', tokenPrefix: 'SP'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ await collection.setPermissions(bob, {access: 'AllowList', mintMode: true});
+
+ expect((await collection.getData())?.raw.permissions.access).to.equal('AllowList');
+ expect((await collection.getData())?.raw.permissions.mintMode).to.equal(true);
+ });
+});
+
+describe('Negative Integration Test: Set Permissions', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+ });
+ });
+
+ itSub('fails on not existing collection', async ({helper}) => {
+ const collectionId = NON_EXISTENT_COLLECTION_ID;
+ await expect(helper.collection.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('fails on removed collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-Neg-1', tokenPrefix: 'SP'});
+ await collection.burn(alice);
+
+ await expect(collection.setPermissions(alice, {access: 'AllowList', mintMode: true}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('fails when non-owner tries to set permissions', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-Neg-2', tokenPrefix: 'SP'});
+
+ await expect(collection.setPermissions(bob, {access: 'AllowList', mintMode: true}))
+ .to.be.rejectedWith(/common\.NoPermission/);
+ });
+});
js-packages/tests/src/addCollectionAdmin.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/addCollectionAdmin.test.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
- let donor: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itSub('Add collection admin.', async ({helper}) => {
- const [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
-
- const collection = await helper.collection.getData(collectionId);
- expect(collection!.normalizedOwner!).to.be.equal(helper.address.normalizeSubstrate(alice.address));
-
- await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});
-
- const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId);
- expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
- });
-});
-
-describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
- let donor: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itSub("Not owner can't add collection admin.", async ({helper}) => {
- const [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
-
- const collection = await helper.collection.getData(collectionId);
- expect(collection?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address));
-
- await expect(helper.collection.addAdmin(bob, collectionId, {Substrate: charlie.address})).to.be.rejectedWith(/common\.NoPermission/);
- await expect(helper.collection.addAdmin(bob, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.NoPermission/);
-
- const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId);
- expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: charlie.address});
- expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: bob.address});
- });
-
- itSub("Admin can't add collection admin.", async ({helper}) => {
- const [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
-
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- const adminListAfterAddAdmin = await collection.getAdmins();
- expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
-
- await expect(collection.addAdmin(bob, {Substrate: charlie.address})).to.be.rejectedWith(/common\.NoPermission/);
-
- const adminListAfterAddNewAdmin = await collection.getAdmins();
- expect(adminListAfterAddNewAdmin).to.be.deep.contains({Substrate: bob.address});
- expect(adminListAfterAddNewAdmin).to.be.not.deep.contains({Substrate: charlie.address});
- });
-
- itSub("Can't add collection admin of not existing collection.", async ({helper}) => {
- const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- const collectionId = NON_EXISTENT_COLLECTION_ID;
-
- await expect(helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/);
-
- // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
- await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
- });
-
- itSub("Can't add an admin to a destroyed collection.", async ({helper}) => {
- const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
-
- await collection.burn(alice);
- await expect(collection.addAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/);
-
- // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
- await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
- });
-
- itSub('Add an admin to a collection that has reached the maximum number of admins limit', async ({helper}) => {
- const [alice, ...accounts] = await helper.arrange.createAccounts([10n, 0n, 0n, 0n, 0n, 0n, 0n, 0n], donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
-
- const chainAdminLimit = (helper.getApi().consts.common.collectionAdminsLimit as any).toNumber();
- expect(chainAdminLimit).to.be.equal(5);
-
- for(let i = 0; i < chainAdminLimit; i++) {
- await collection.addAdmin(alice, {Substrate: accounts[i].address});
- const adminListAfterAddAdmin = await collection.getAdmins();
- expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: accounts[i].address});
- }
-
- await expect(collection.addAdmin(alice, {Substrate: accounts[chainAdminLimit].address})).to.be.rejectedWith(/common\.CollectionAdminCountExceeded/);
- });
-});
js-packages/tests/src/adminTransferAndBurn.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/adminTransferAndBurn.test.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from './util/index.js';
-
-describe('Integration Test: ownerCanTransfer allows admins to use only transferFrom/burnFrom:', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itSub('admin transfers other user\'s token', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
- await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
- const limits = await helper.collection.getEffectiveLimits(collectionId);
- expect(limits.ownerCanTransfer).to.be.true;
-
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
- await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})).to.be.rejected;
-
- await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address});
- const newTokenOwner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(newTokenOwner).to.be.deep.equal({Substrate: charlie.address});
- });
-
- itSub('admin burns other user\'s token', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
-
- await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
- const limits = await helper.collection.getEffectiveLimits(collectionId);
- expect(limits.ownerCanTransfer).to.be.true;
-
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
-
- await expect(helper.nft.burnToken(alice, collectionId, tokenId)).to.be.rejected;
-
- await helper.nft.burnToken(bob, collectionId, tokenId);
- const token = await helper.nft.getToken(collectionId, tokenId);
- expect(token).to.be.null;
- });
-});
js-packages/tests/src/allowLists.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/allowLists.test.ts
+++ /dev/null
@@ -1,361 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from './util/index.js';
-import type {ICollectionPermissions} from '@unique/playgrounds/src/types.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test ext. Allow list tests', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);
- });
- });
-
- describe('Positive', () => {
- itSub('Owner can add address to allow list', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- // allow list does not need to be enabled to add someone in advance
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
- const allowList = await helper.nft.getAllowList(collectionId);
- expect(allowList).to.deep.contain({Substrate: bob.address});
- });
-
- itSub('Admin can add address to allow list', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});
-
- // allow list does not need to be enabled to add someone in advance
- await helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address});
- const allowList = await helper.nft.getAllowList(collectionId);
- expect(allowList).to.deep.contain({Substrate: charlie.address});
- });
-
- itSub('If address is already added to allow list, nothing happens', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
- const allowList = await helper.nft.getAllowList(collectionId);
- expect(allowList).to.deep.contain({Substrate: bob.address});
- });
- });
-
- describe('Negative', () => {
- itSub('Nobody can add address to allow list of non-existing collection', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Nobody can add address to allow list of destroyed collection', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.collection.burn(alice, collectionId);
- await expect(helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Non-privileged user cannot add address to allow list', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.NoPermission/);
- });
- });
-});
-
-describe('Integration Test ext. Remove from Allow List', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);
- });
- });
-
- describe('Positive', () => {
- itSub('Owner can remove address from allow list', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
-
- await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
-
- const allowList = await helper.nft.getAllowList(collectionId);
-
- expect(allowList).to.not.deep.contain({Substrate: bob.address});
- });
-
- itSub('Admin can remove address from allow list', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addAdmin(alice, collectionId, {Substrate: charlie.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
- await helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: bob.address});
-
- const allowList = await helper.nft.getAllowList(collectionId);
- expect(allowList).to.not.deep.contain({Substrate: bob.address});
- });
-
- itSub('If address is already removed from allow list, nothing happens', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
- await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
- const allowListBefore = await helper.nft.getAllowList(collectionId);
- expect(allowListBefore).to.not.deep.contain({Substrate: bob.address});
-
- await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
-
- const allowListAfter = await helper.nft.getAllowList(collectionId);
- expect(allowListAfter).to.not.deep.contain({Substrate: bob.address});
- });
- });
-
- describe('Negative', () => {
- itSub('Non-privileged user cannot remove address from allow list', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
- await expect(helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.NoPermission/);
-
- const allowList = await helper.nft.getAllowList(collectionId);
- expect(allowList).to.deep.contain({Substrate: charlie.address});
- });
-
- itSub('Nobody can remove address from allow list of non-existing collection', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- await expect(helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Nobody can remove address from allow list of deleted collection', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
- await helper.collection.burn(alice, collectionId);
-
- await expect(helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
- });
-});
-
-describe('Integration Test ext. Transfer if included in Allow List', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([30n, 10n, 10n], donor);
- });
- });
-
- describe('Positive', () => {
- itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transfer.', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
- await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
- const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner).to.be.deep.equal({Substrate: charlie.address});
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transferFrom.', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
- await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
-
- await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});
- const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner).to.be.deep.equal({Substrate: charlie.address});
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
-
- await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
- const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner).to.be.deep.equal({Substrate: charlie.address});
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transferFrom', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
- await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
-
- await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});
- const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner).to.be.deep.equal({Substrate: charlie.address});
- });
- });
-
- describe('Negative', () => {
- itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
-
- await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
- await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
- await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});
-
- await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
-
- await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
- await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
-
- await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
- await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});
-
- await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
- });
-
- itSub('If Public Access mode is set to AllowList, tokens can\'t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await expect(helper.nft.burnToken(bob, collectionId, tokenId))
- .to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('If Public Access mode is set to AllowList, token transfers can\'t be Approved by a non-allowlisted address (see Approve method)', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
- await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
- await expect(helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
- });
- });
-});
-
-describe('Integration Test ext. Mint if included in Allow List', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- const permissionSet: ICollectionPermissions[] = [
- {access: 'Normal', mintMode: false},
- {access: 'Normal', mintMode: true},
- {access: 'AllowList', mintMode: false},
- {access: 'AllowList', mintMode: true},
- ];
-
- const testPermissionSuite = (permissions: ICollectionPermissions) => {
- const allowlistedMintingShouldFail = !permissions.mintMode!;
-
- const appropriateRejectionMessage = permissions.mintMode! ? /common\.AddressNotInAllowlist/ : /common\.PublicMintingNotAllowed/;
-
- const allowlistedMintingTest = () => itSub(
- `With the condtions above, tokens can${allowlistedMintingShouldFail ? '\'t' : ''} be created by allow-listed addresses`,
- async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setPermissions(alice, permissions);
- await collection.addToAllowList(alice, {Substrate: bob.address});
-
- if(allowlistedMintingShouldFail)
- await expect(collection.mintToken(bob, {Substrate: bob.address})).to.be.rejectedWith(appropriateRejectionMessage);
- else
- await expect(collection.mintToken(bob, {Substrate: bob.address})).to.not.be.rejected;
- },
- );
-
-
- describe(`Public Access Mode = ${permissions.access}, Mint Mode = ${permissions.mintMode}`, () => {
- describe('Positive', () => {
- itSub('With the condtions above, tokens can be created by owner', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setPermissions(alice, permissions);
- await expect(collection.mintToken(alice, {Substrate: alice.address})).to.not.be.rejected;
- });
-
- itSub('With the condtions above, tokens can be created by admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setPermissions(alice, permissions);
- await collection.addAdmin(alice, {Substrate: bob.address});
- await expect(collection.mintToken(bob, {Substrate: bob.address})).to.not.be.rejected;
- });
-
- if(!allowlistedMintingShouldFail) allowlistedMintingTest();
- });
-
- describe('Negative', () => {
- itSub('With the condtions above, tokens can\'t be created by non-priviliged non-allow-listed address', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setPermissions(alice, permissions);
- await expect(collection.mintToken(bob, {Substrate: bob.address}))
- .to.be.rejectedWith(appropriateRejectionMessage);
- });
-
- if(allowlistedMintingShouldFail) allowlistedMintingTest();
- });
- });
- };
-
- for(const permissions of permissionSet) {
- testPermissionSuite(permissions);
- }
-});
js-packages/tests/src/apiConsts.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/apiConsts.test.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {ApiPromise} from '@polkadot/api';
-import {usingPlaygrounds, itSub, expect, COLLECTION_HELPER, CONTRACT_HELPER} from './util/index.js';
-
-
-const MAX_COLLECTION_DESCRIPTION_LENGTH = 256n;
-const MAX_COLLECTION_NAME_LENGTH = 64n;
-const COLLECTION_ADMINS_LIMIT = 5n;
-const MAX_COLLECTION_PROPERTIES_SIZE = 40960n;
-const MAX_TOKEN_PREFIX_LENGTH = 16n;
-const MAX_PROPERTY_KEY_LENGTH = 256n;
-const MAX_PROPERTY_VALUE_LENGTH = 32768n;
-const MAX_PROPERTIES_PER_ITEM = 64n;
-const MAX_TOKEN_PROPERTIES_SIZE = 32768n;
-const NESTING_BUDGET = 5n;
-
-const DEFAULT_COLLETCTION_LIMIT = {
- accountTokenOwnershipLimit: '1,000,000',
- sponsoredDataSize: '2,048',
- sponsoredDataRateLimit: 'SponsoringDisabled',
- tokenLimit: '4,294,967,295',
- sponsorTransferTimeout: '5',
- sponsorApproveTimeout: '5',
- ownerCanTransfer: false,
- ownerCanDestroy: true,
- transfersEnabled: true,
-};
-
-describe('integration test: API UNIQUE consts', () => {
- let api: ApiPromise;
-
- before(async () => {
- await usingPlaygrounds(async (helper) => {
- api = await helper.getApi();
- });
- });
-
- itSub('DEFAULT_NFT_COLLECTION_LIMITS', () => {
- expect(api.consts.unique.nftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
- });
-
- itSub('DEFAULT_RFT_COLLECTION_LIMITS', () => {
- expect(api.consts.unique.rftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
- });
-
- itSub('DEFAULT_FT_COLLECTION_LIMITS', () => {
- expect(api.consts.unique.ftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
- });
-
- itSub('MAX_COLLECTION_NAME_LENGTH', () => {
- checkConst(api.consts.unique.maxCollectionNameLength, MAX_COLLECTION_NAME_LENGTH);
- });
-
- itSub('MAX_COLLECTION_DESCRIPTION_LENGTH', () => {
- checkConst(api.consts.unique.maxCollectionDescriptionLength, MAX_COLLECTION_DESCRIPTION_LENGTH);
- });
-
- itSub('MAX_COLLECTION_PROPERTIES_SIZE', () => {
- checkConst(api.consts.unique.maxCollectionPropertiesSize, MAX_COLLECTION_PROPERTIES_SIZE);
- });
-
- itSub('MAX_TOKEN_PREFIX_LENGTH', () => {
- checkConst(api.consts.unique.maxTokenPrefixLength, MAX_TOKEN_PREFIX_LENGTH);
- });
-
- itSub('MAX_PROPERTY_KEY_LENGTH', () => {
- checkConst(api.consts.unique.maxPropertyKeyLength, MAX_PROPERTY_KEY_LENGTH);
- });
-
- itSub('MAX_PROPERTY_VALUE_LENGTH', () => {
- checkConst(api.consts.unique.maxPropertyValueLength, MAX_PROPERTY_VALUE_LENGTH);
- });
-
- itSub('MAX_PROPERTIES_PER_ITEM', () => {
- checkConst(api.consts.unique.maxPropertiesPerItem, MAX_PROPERTIES_PER_ITEM);
- });
-
- itSub('NESTING_BUDGET', () => {
- checkConst(api.consts.unique.nestingBudget, NESTING_BUDGET);
- });
-
- itSub('MAX_TOKEN_PROPERTIES_SIZE', () => {
- checkConst(api.consts.unique.maxTokenPropertiesSize, MAX_TOKEN_PROPERTIES_SIZE);
- });
-
- itSub('COLLECTION_ADMINS_LIMIT', () => {
- checkConst(api.consts.unique.collectionAdminsLimit, COLLECTION_ADMINS_LIMIT);
- });
-
- itSub('HELPERS_CONTRACT_ADDRESS', () => {
- expect(api.consts.evmContractHelpers.contractAddress.toString().toLowerCase()).to.be.equal(CONTRACT_HELPER.toLowerCase());
- });
-
- itSub('EVM_COLLECTION_HELPERS_ADDRESS', () => {
- expect(api.consts.common.contractAddress.toString().toLowerCase()).to.be.equal(COLLECTION_HELPER.toLowerCase());
- });
-});
-
-function checkConst<T>(constValue: any, expectedValue: T) {
- expect(constValue.toBigInt()).equal(expectedValue);
-}
\ No newline at end of file
js-packages/tests/src/approve.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/approve.test.ts
+++ /dev/null
@@ -1,658 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from './util/index.js';
-import {CrossAccountId} from '@unique/playgrounds/src/unique.js';
-
-
-
-[
- {method: 'approveToken', account: (account: IKeyringPair) => CrossAccountId.fromKeyring(account).toICrossAccountId()},
- {method: 'approveTokenFromEth', account: (account: IKeyringPair) => CrossAccountId.fromKeyring(account).toEthereum().toICrossAccountId()},
-].map(testCase => {
- describe(`Integration Test ${testCase.method}(spender, collection_id, item_id, amount):`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('[nft] Execute the extrinsic and check approvedList', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
- await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
- });
-
- itSub('[fungible] Execute the extrinsic and check approvedList', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
- expect(amount).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('[refungible] Execute the extrinsic and check approvedList', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
- await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
- expect(amount).to.be.equal(1n);
- });
-
- itSub('[nft] Remove approval by using 0 amount', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const collectionId = collection.collectionId;
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
- await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
- await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
- });
-
- itSub('[fungible] Remove approval by using 0 amount', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
- expect(amountBefore).to.be.equal(1n);
-
- await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
- const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
- expect(amountAfter).to.be.equal(0n);
- });
-
- itSub.ifWithPallets('[refungible] Remove approval by using 0 amount', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
- await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
- expect(amountBefore).to.be.equal(1n);
-
- await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
- const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));
- expect(amountAfter).to.be.equal(0n);
- });
-
- itSub('can`t be called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
- const result = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});
- await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
- });
-
- describe(`[${testCase.method}] Normal user can approve other users to transfer:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('NFT', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
- await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.true;
- });
-
- itSub('Fungible up to an approved amount', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, testCase.account(bob));
- expect(amount).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});
- await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);
- const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, testCase.account(bob));
- expect(amount).to.be.equal(100n);
- });
- });
-
- describe(`[${testCase.method}] Approved users can transferFrom up to approved amount:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('NFT', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
- await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});
- const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('Fungible up to an approved amount', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
- await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
- const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
- expect(after - before).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});
- await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
- await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
- const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
- expect(after - before).to.be.equal(1n);
- });
- });
-
- describe(`[${testCase.method}] Approved users cannot use transferFrom to repeat transfers if approved amount was already transferred:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('NFT', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
- await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});
- const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner).to.be.deep.equal({Substrate: alice.address});
- const transferTokenFromTx = () => helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});
- await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
-
- itSub('Fungible up to an approved amount', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
- await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
- const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
- expect(after - before).to.be.equal(1n);
-
- const transferTokenFromTx = () => helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);
- await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
-
- itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});
- await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);
- const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
- await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);
- const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
- expect(after - before).to.be.equal(100n);
- const transferTokenFromTx = () => helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);
- await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
- });
-
- describe(`[${testCase.method}] Approved amount decreases by the transferred amount:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
- let dave: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
- });
- });
-
- itSub('If a user B is approved to transfer 10 Fungible tokens from user A, they can transfer 2 tokens to user C, which will result in decreasing approval from 10 to 8. Then user B can transfer 8 tokens to user D.', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 10n);
-
- const charlieBefore = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
- await helper.ft.transferTokenFrom(bob, collectionId, tokenId, testCase.account(alice), {Substrate: charlie.address}, 2n);
- const charlieAfter = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
- expect(charlieAfter - charlieBefore).to.be.equal(2n);
-
- const daveBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
- await helper.ft.transferTokenFrom(bob, collectionId, tokenId, testCase.account(alice), {Substrate: dave.address}, 8n);
- const daveAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
- expect(daveAfter - daveBefore).to.be.equal(8n);
- });
- });
-
- describe(`[${testCase.method}] User may clear the approvals to approving for 0 amount:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('NFT', async ({helper}) => {
- const owner = testCase.account(alice);
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: owner});
-
- await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
-
- await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
-
- const transferTokenFromTx = helper.nft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: bob.address});
- await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
-
- itSub('Fungible', async ({helper}) => {
- const owner = testCase.account(alice);
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, owner);
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
- expect(amountBefore).to.be.equal(1n);
-
- await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
- const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
- expect(amountAfter).to.be.equal(0n);
-
- const transferTokenFromTx = helper.ft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: charlie.address}, 1n);
- await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
-
- itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {
- const owner = testCase.account(alice);
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner, pieces: 100n});
- await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});
- const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
- expect(amountBefore).to.be.equal(1n);
-
- await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
- const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);
- expect(amountAfter).to.be.equal(0n);
-
- const transferTokenFromTx = helper.rft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: charlie.address}, 1n);
- await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
- });
-
- describe(`[${testCase.method}] User cannot approve for the amount greater than they own:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('1 for NFT', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
- const result = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 2n);
- await expect(result).to.be.rejectedWith('nonfungible.NonfungibleItemsHaveNoAmount');
- expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;
- });
-
- itSub('Fungible', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- const result = (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 11n);
- await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
-
- itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
- const result = (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 101n);
- await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
- });
-
- describe(`[${testCase.method}] Integration Test approve(spender, collection_id, item_id, amount) with collection admin permissions:`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('cannot be called by collection admin on non-owned item', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
- await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
- const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
- });
-
- describe(`[${testCase.method}] Negative Integration Test approve(spender, collection_id, item_id, amount):`, () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
- const NONEXISTENT_COLLECTION = (2 ** 32) - 1;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('[nft] Approve for a collection that does not exist', async ({helper}) => {
- const approveTx = (helper.nft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});
- await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
- });
-
- itSub('[fungible] Approve for a collection that does not exist', async ({helper}) => {
- const approveTx = (helper.ft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});
- await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
- });
-
- itSub.ifWithPallets('[refungible] Approve for a collection that does not exist', [Pallets.ReFungible], async ({helper}) => {
- const approveTx = (helper.rft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});
- await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
- });
-
- itSub('[nft] Approve for a collection that was destroyed', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.nft.burn(alice, collectionId);
- const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});
- await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
- });
-
- itSub('[fungible] Approve for a collection that was destroyed', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.ft.burn(alice, collectionId);
- const approveTx = (helper.ft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});
- await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
- });
-
- itSub.ifWithPallets('[refungible] Approve for a collection that was destroyed', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.rft.burn(alice, collectionId);
- const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});
- await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');
- });
-
- itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});
- await expect(approveTx).to.be.rejectedWith('common.TokenNotFound');
- });
-
- itSub.ifWithPallets('[refungible] Approve transfer of a token that does not exist', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned'); // TODO: why the error is not common.TokenNotFound
- });
-
- itSub('[nft] Approve using the address that does not own the approved token', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});
- const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
-
- itSub('[fungible] Approve using the address that does not own the approved token', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));
- const tokenId = await helper.ft.getLastTokenId(collectionId);
- const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
-
- itSub.ifWithPallets('[refungible] Approve using the address that does not own the approved token', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});
- const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
-
- itSub.ifWithPallets('should fail if approved more ReFungibles than owned', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
- await helper.rft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 100n);
- await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 100n);
-
- const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 101n);
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
-
- itSub('should fail if approved more Fungibles than owned', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.ft.mintTokens(alice, collectionId, 10n, alice.address);
- const tokenId = await helper.ft.getLastTokenId(collectionId);
-
- await helper.ft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 10n);
- await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 10n);
- const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 11n);
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
-
- itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});
- await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});
-
- const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});
- await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');
- });
- });
-});
-
-describe('Normal user can approve other users to be wallet operator:', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('[nft] Enable and disable approval', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
-
- const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
- expect(checkBeforeApproval).to.be.false;
-
- await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);
- const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
- expect(checkAfterApproval).to.be.true;
-
- await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);
- const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
- expect(checkAfterDisapproval).to.be.false;
- });
-
- itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
-
- const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
- expect(checkBeforeApproval).to.be.false;
-
- await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);
- const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
- expect(checkAfterApproval).to.be.true;
-
- await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);
- const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
- expect(checkAfterDisapproval).to.be.false;
- });
-});
-
-describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
- let dave: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
- });
- });
-
- itSub('NFT', async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
- const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});
-
- await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});
- const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner1).to.be.deep.equal({Substrate: dave.address});
-
- await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
- await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});
- const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);
- expect(owner2).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('Fungible up to an approved amount', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
- await helper.ft.mintTokens(alice, collectionId, 10n, charlie.address);
- const tokenId = await helper.ft.getLastTokenId(collectionId);
-
- const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
- await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);
- const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
- expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(1n);
-
- await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});
-
- const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
- await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);
- const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
- expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
- const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});
-
- const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});
- await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);
- const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});
- expect(daveAfter - daveBefore).to.be.equal(1n);
-
- await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
-
- const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
- await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);
- const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
- expect(aliceAfter - aliceBefore).to.be.equal(1n);
- });
-});
-
-describe('Repeated approvals add up', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
- let dave: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
- });
- });
-
- itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {});
- await collection.mint(alice, 10n);
- await collection.approveTokens(alice, {Substrate: bob.address}, 1n);
- await collection.approveTokens(alice, {Substrate: charlie.address}, 1n);
- // const allowances1 = await getAllowance(collectionId, 0, Alice.address, Bob.address);
- // const allowances2 = await getAllowance(collectionId, 0, Alice.address, Charlie.address);
- // expect(allowances1 + allowances2).to.be.eq(2n);
- });
-
- itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. ReFungible', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- const token = await collection.mintToken(alice, 10n);
- await token.approve(alice, {Substrate: bob.address}, 1n);
- await token.approve(alice, {Substrate: charlie.address}, 1n);
- // const allowances1 = await getAllowance(collectionId, itemId, Alice.address, Bob.address);
- // const allowances2 = await getAllowance(collectionId, itemId, Alice.address, Charlie.address);
- // expect(allowances1 + allowances2).to.be.eq(2n);
- });
-
- // Canceled by changing approve logic
- itSub.skip('Cannot approve for more than total user\'s amount (owned: 10, approval 1: 5 - should succeed, approval 2: 6 - should fail). Fungible', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {});
- await collection.mint(alice, 10n, {Substrate: dave.address});
- await collection.approveTokens(dave, {Substrate: bob.address}, 5n);
- await expect(collection.approveTokens(dave, {Substrate: charlie.address}, 6n))
- .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');
- });
-
- // Canceled by changing approve logic
- itSub.skip('Cannot approve for more than total user\'s amount (owned: 100, approval 1: 50 - should succeed, approval 2: 51 - should fail). ReFungible', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- const token = await collection.mintToken(alice, 100n, {Substrate: dave.address});
- await token.approve(dave, {Substrate: bob.address}, 50n);
- await expect(token.approve(dave, {Substrate: charlie.address}, 51n))
- .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');
- });
-});
js-packages/tests/src/burnItem.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/burnItem.test.ts
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from './util/index.js';
-
-
-describe('integration test: ext. burnItem():', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- itSub('Burn item in NFT collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- const token = await collection.mintToken(alice);
-
- await token.burn(alice);
- expect(await token.doesExist()).to.be.false;
- });
-
- itSub('Burn item in Fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {}, 10);
- await collection.mint(alice, 10n);
-
- await collection.burnTokens(alice, 1n);
- expect(await collection.getBalance({Substrate: alice.address})).to.eq(9n);
- });
-});
-
-describe('integration test: ext. burnItem() with admin permissions:', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Burn item in NFT collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- await collection.setLimits(alice, {ownerCanTransfer: true});
- await collection.addAdmin(alice, {Substrate: bob.address});
- const token = await collection.mintToken(alice);
-
- await token.burnFrom(bob, {Substrate: alice.address});
- expect(await token.doesExist()).to.be.false;
- });
-
- itSub('Burn item in Fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {}, 0);
- await collection.setLimits(alice, {ownerCanTransfer: true});
- await collection.addAdmin(alice, {Substrate: bob.address});
- await collection.mint(alice, 10n);
-
- await collection.burnTokensFrom(bob, {Substrate: alice.address}, 1n);
- expect(await collection.getBalance({Substrate: alice.address})).to.eq(9n);
- });
-});
-
-describe('Negative integration test: ext. burnItem():', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Burn a token that was never created', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- await expect(collection.burnToken(alice, 10)).to.be.rejectedWith('common.TokenNotFound');
- });
-
- itSub('Burn a token using the address that does not own it', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- const token = await collection.mintToken(alice);
-
- await expect(token.burn(bob)).to.be.rejectedWith('common.NoPermission');
- });
-
- itSub('Transfer a burned token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- const token = await collection.mintToken(alice);
- await token.burn(alice);
-
- await expect(token.transfer(alice, {Substrate: bob.address})).to.be.rejectedWith('common.TokenNotFound');
- });
-
- itSub('Burn more than owned in Fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {}, 0);
- await collection.mint(alice, 10n);
-
- await expect(collection.burnTokens(alice, 11n)).to.be.rejectedWith('common.TokenValueTooLow');
- expect(await collection.getBalance({Substrate: alice.address})).to.eq(10n);
- });
-
- itSub('Zero burn NFT', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Coll', description: 'Desc', tokenPrefix: 'T'});
- const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});
- const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});
-
- // 1. Zero burn of own tokens allowed:
- await helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenAlice.tokenId, 0]);
- // 2. Zero burn of non-owned tokens not allowed:
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');
- // 3. Zero burn of non-existing tokens not allowed:
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, 9999, 0])).to.be.rejectedWith('common.TokenNotFound');
- expect(await tokenAlice.doesExist()).to.be.true;
- expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});
- expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});
- // 4. Storage is not corrupted:
- await tokenAlice.transfer(alice, {Substrate: bob.address});
- await tokenBob.transfer(bob, {Substrate: alice.address});
- expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});
- expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});
- });
-
- itSub('zero burnFrom NFT', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Zero', description: 'Zero transfer', tokenPrefix: 'TF'});
- const notApprovedNft = await collection.mintToken(alice, {Substrate: bob.address});
- const approvedNft = await collection.mintToken(alice, {Substrate: bob.address});
- await approvedNft.approve(bob, {Substrate: alice.address});
-
- // 1. Zero burnFrom of non-existing tokens not allowed:
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, 9999, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
- // 2. Zero burnFrom of not approved tokens not allowed:
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, notApprovedNft.tokenId, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
- // 3. Zero burnFrom of approved tokens allowed:
- await helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, approvedNft.tokenId, 0]);
-
- // 4.1 approvedNft still approved:
- expect(await approvedNft.isApproved({Substrate: alice.address})).to.be.true;
- // 4.2 bob is still the owner:
- expect(await approvedNft.getOwner()).to.deep.eq({Substrate: bob.address});
- expect(await notApprovedNft.getOwner()).to.deep.eq({Substrate: bob.address});
- // 4.3 Alice can burn approved nft:
- await approvedNft.burnFrom(alice, {Substrate: bob.address});
- expect(await approvedNft.doesExist()).to.be.false;
- });
-});
js-packages/tests/src/change-collection-owner.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/change-collection-owner.test.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test changeCollectionOwner(collection_id, new_owner):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Changing owner changes owner address', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const beforeChanging = await helper.collection.getData(collection.collectionId);
- expect(beforeChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address));
-
- await collection.changeOwner(alice, bob.address);
- const afterChanging = await helper.collection.getData(collection.collectionId);
- expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
- });
-});
-
-describe('Integration Test changeCollectionOwner(collection_id, new_owner) special checks for exOwner:', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('Changing the owner of the collection is not allowed for the former owner', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
-
- await collection.changeOwner(alice, bob.address);
-
- const changeOwnerTx = () => collection.changeOwner(alice, alice.address);
- await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
-
- const afterChanging = await helper.collection.getData(collection.collectionId);
- expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
- });
-
- itSub('New collectionOwner has access to sponsorship management operations in the collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.changeOwner(alice, bob.address);
-
- const afterChanging = await helper.collection.getData(collection.collectionId);
- expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
-
- await collection.setSponsor(bob, charlie.address);
- await collection.confirmSponsorship(charlie);
- await collection.removeSponsor(bob);
- const limits = {
- accountTokenOwnershipLimit: 1,
- tokenLimit: 1,
- sponsorTransferTimeout: 1,
- ownerCanDestroy: true,
- ownerCanTransfer: true,
- };
-
- await collection.setLimits(bob, limits);
- const gotLimits = await collection.getEffectiveLimits();
- expect(gotLimits).to.be.deep.contains(limits);
-
- await collection.setPermissions(bob, {access: 'AllowList', mintMode: true});
-
- await collection.burn(bob);
- const collectionData = await helper.collection.getData(collection.collectionId);
- expect(collectionData).to.be.null;
- });
-
- itSub('New collectionOwner has access to changeCollectionOwner', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.changeOwner(alice, bob.address);
- await collection.changeOwner(bob, charlie.address);
- const collectionData = await collection.getData();
- expect(collectionData?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(charlie.address));
- });
-});
-
-describe('Negative Integration Test changeCollectionOwner(collection_id, new_owner):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('Not owner can\'t change owner.', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const changeOwnerTx = () => collection.changeOwner(bob, bob.address);
- await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Collection admin can\'t change owner.', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.addAdmin(alice, {Substrate: bob.address});
- const changeOwnerTx = () => collection.changeOwner(bob, bob.address);
- await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Can\'t change owner of a non-existing collection.', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- const changeOwnerTx = () => helper.collection.changeOwner(bob, collectionId, bob.address);
- await expect(changeOwnerTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Former collectionOwner not allowed to sponsorship management operations in the collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.changeOwner(alice, bob.address);
-
- const changeOwnerTx = () => collection.changeOwner(alice, alice.address);
- await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/);
-
- const afterChanging = await helper.collection.getData(collection.collectionId);
- expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address));
-
- const setSponsorTx = () => collection.setSponsor(alice, charlie.address);
- const confirmSponsorshipTx = () => collection.confirmSponsorship(alice);
- const removeSponsorTx = () => collection.removeSponsor(alice);
- await expect(setSponsorTx()).to.be.rejectedWith(/common\.NoPermission/);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- await expect(removeSponsorTx()).to.be.rejectedWith(/common\.NoPermission/);
-
- const limits = {
- accountTokenOwnershipLimit: 1,
- tokenLimit: 1,
- sponsorTransferTimeout: 1,
- ownerCanDestroy: true,
- ownerCanTransfer: true,
- };
-
- const setLimitsTx = () => collection.setLimits(alice, limits);
- await expect(setLimitsTx()).to.be.rejectedWith(/common\.NoPermission/);
-
- const setPermissionTx = () => collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
- await expect(setPermissionTx()).to.be.rejectedWith(/common\.NoPermission/);
-
- const burnTx = () => collection.burn(alice);
- await expect(burnTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-});
js-packages/tests/src/check-event/burnItemEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/burnItemEvent.test.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-
-describe('Burn Item event ', () => {
- let alice: IKeyringPair;
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
- itSub('Check event from burnItem(): ', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- await token.burn(alice);
- await helper.wait.newBlocks(1);
-
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.ItemDestroyed');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/check-event/createCollectionEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/createCollectionEvent.test.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-describe('Create collection event ', () => {
- let alice: IKeyringPair;
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
- itSub('Check event from createCollection(): ', async ({helper}) => {
- await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- await helper.wait.newBlocks(1);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.CollectionCreated');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/check-event/createItemEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/createItemEvent.test.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-describe('Create Item event ', () => {
- let alice: IKeyringPair;
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
- itSub('Check event from createItem(): ', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- await collection.mintToken(alice, {Substrate: alice.address});
- await helper.wait.newBlocks(1);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.ItemCreated');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/check-event/createMultipleItemsEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/createMultipleItemsEvent.test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-describe('Create Multiple Items Event event ', () => {
- let alice: IKeyringPair;
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
- itSub('Check event from createMultipleItems(): ', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- await collection.mintMultipleTokens(alice, [
- {owner: {Substrate: alice.address}},
- {owner: {Substrate: alice.address}},
- ]);
-
- await helper.wait.newBlocks(1);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.ItemCreated');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/check-event/destroyCollectionEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/destroyCollectionEvent.test.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-describe('Destroy collection event ', () => {
- let alice: IKeyringPair;
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itSub('Check event from destroyCollection(): ', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- await collection.burn(alice);
- await helper.wait.newBlocks(1);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.CollectionDestroyed');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/check-event/transferEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/transferEvent.test.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-describe('Transfer event ', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
- });
- });
-
- itSub('Check event from transfer(): ', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- await token.transfer(alice, {Substrate: bob.address});
- await helper.wait.newBlocks(1);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.Transfer');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/check-event/transferFromEvent.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/check-event/transferFromEvent.test.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-
-describe('Transfer event ', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
- });
- });
-
- itSub('Check event from transfer(): ', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});
- await helper.wait.newBlocks(1);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contains('common.Transfer');
- expect(eventStrings).to.contains('treasury.Deposit');
- expect(eventStrings).to.contains('system.ExtrinsicSuccess');
- });
-});
js-packages/tests/src/collator-selection/collatorSelection.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/collator-selection/collatorSelection.seqtest.ts
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util/index.js';
-
-async function nodeAddress(name: string) {
- // eslint-disable-next-line require-await
- return await usingPlaygrounds(async (helper) => {
- const envNodeStash = `RELAY_UNIQUE_NODE_${name.toUpperCase()}_STASH`;
-
- const nodeStash = process.env[envNodeStash];
- if(nodeStash) {
- return helper.address.normalizeSubstrateToChainFormat(nodeStash);
- } else {
- throw Error(`"${envNodeStash}" env var is not set`);
- }
- });
-}
-
-async function getInitialInvulnerables() {
- return await Promise.all([
- nodeAddress('alpha'),
- nodeAddress('beta'),
- nodeAddress('gamma'),
- nodeAddress('delta'),
- ]);
-}
-
-async function resetInvulnerables() {
- await usingPlaygrounds(async (helper, privateKey) => {
- const superuser = await privateKey('//Alice');
- const initialInvulnerables = await getInitialInvulnerables();
-
- const invulnerables = await helper.collatorSelection.getInvulnerables();
-
- // Remove all invulnerables but the first one
- const firstInvulnerable = invulnerables[0];
-
- let nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(invulnerables.slice(1).map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++})));
-
- // Add the initial invulnerables
- await Promise.all(initialInvulnerables.map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [invulnerable], true, {nonce: nonce++})));
-
- // Remove the first invulnerable if it's not an initial one
- if(!initialInvulnerables.includes(firstInvulnerable)) {
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [firstInvulnerable]);
- }
- });
-}
-
-// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).
-describe('Integration Test: Collator Selection', () => {
- let superuser: IKeyringPair;
- let previousLicenseBond = 0n;
- let licenseBond = 0n;
-
- before(async function() {
- if(!process.env.RUN_COLLATOR_TESTS) this.skip();
-
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);
- superuser = await privateKey('//Alice');
-
- previousLicenseBond = await helper.collatorSelection.getLicenseBond();
- licenseBond = 10n * helper.balance.getOneTokenNominal();
- await helper.getSudo().collatorSelection.setLicenseBond(superuser, licenseBond);
- });
- });
-
- describe('Dynamic shuffling of collators', () => {
- // These two are the default invulnerables, and should return to be invulnerables after this suite.
- let alphaNode: string;
- let betaNode: string;
-
- let gammaNode: string;
- let deltaNode: string;
-
- before(async function() {
- await usingPlaygrounds(async (helper) => {
- // todo:collator see again if blocks start to be finalized in dev mode
- // Skip the collator block production in dev mode, since the blocks are sealed automatically.
- if(await helper.arrange.isDevNode()) this.skip();
-
- [alphaNode, betaNode, gammaNode, deltaNode] = await getInitialInvulnerables();
-
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- expect(invulnerables.length, 'Invalid initial invulnerables number').to.be.equal(4);
- expect(invulnerables, 'Invalid initial invulnerables').containSubset([alphaNode, betaNode, gammaNode, deltaNode]);
- });
- });
-
- itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {
- let nonce = await helper.chain.getNonce(superuser.address);
-
- nonce = await helper.chain.getNonce(superuser.address);
- await expect(Promise.all([
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alphaNode], true, {nonce: nonce++}),
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [betaNode], true, {nonce: nonce++}),
- ])).to.be.fulfilled;
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
-
- await helper.wait.newSessions(2);
-
- const newValidators = await helper.callRpc('api.query.session.validators');
- expect(newValidators).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
-
- const lastBlockNumber = await helper.chain.getLatestBlockNumber();
- await helper.wait.newBlocks(1);
- const lastGammaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [gammaNode])).toNumber();
- const lastDeltaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [deltaNode])).toNumber();
- expect(lastGammaBlock >= lastBlockNumber || lastDeltaBlock >= lastBlockNumber).to.be.true;
- });
-
- after(async () => {
- await resetInvulnerables();
- });
- });
-
- describe('Getting and releasing licenses to collate', () => {
- let crowd: IKeyringPair[];
-
- before(async function() {
- await usingPlaygrounds(async (helper) => {
- crowd = await helper.arrange.createCrowd(20, 100n, superuser);
-
- // set session keys for everyone
- await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
- });
- });
-
- describe('Positive', () => {
- itSub('Can lease and release a license', async ({helper}) => {
- const account = crowd.pop()!;
-
- // make sure it does not have any reserved funds
- expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(0n);
-
- // getting a license reserves a license bond cost
- await helper.collatorSelection.obtainLicense(account);
- expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
- expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(licenseBond);
-
- // releasing a license un-reserves the license bond cost
- await helper.collatorSelection.releaseLicense(account);
- expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
-
- const balance = await helper.balance.getSubstrateFull(account.address);
- expect(balance.reserved).to.be.equal(0n);
- expect(balance.free > 100n - licenseBond);
- });
-
- itSub('Can force revoke a license', async ({helper}) => {
- const account = crowd.pop()!;
-
- // getting a license reserves a license bond cost
- const previousBalance = await helper.balance.getSubstrateFull(account.address);
- await helper.collatorSelection.obtainLicense(account);
- expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
-
- // force-releasing a license un-reserves the license bond cost as well
- await helper.getSudo().collatorSelection.forceReleaseLicense(superuser, account.address);
- expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(previousBalance.reserved);
-
- const balance = await helper.balance.getSubstrateFull(account.address);
- expect(balance.reserved).to.be.equal(previousBalance.reserved);
- expect(balance.free > previousBalance.free - licenseBond);
- });
- });
-
- describe('Negative', () => {
- itSub('Cannot get a license without session keys set', async ({helper}) => {
- const [account] = await helper.arrange.createAccounts([100n], superuser);
- await expect(helper.collatorSelection.obtainLicense(account))
- .to.be.rejectedWith(/collatorSelection.ValidatorNotRegistered/);
- });
-
- itSub('Cannot register a license twice', async ({helper}) => {
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await expect(helper.collatorSelection.obtainLicense(account))
- .to.be.rejectedWith(/collatorSelection.AlreadyHoldingLicense/);
- });
-
- itSub('Cannot release a license twice', async ({helper}) => {
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await helper.collatorSelection.releaseLicense(account);
- await expect(helper.collatorSelection.releaseLicense(account))
- .to.be.rejectedWith(/collatorSelection.NoLicense/);
- });
-
- itSub('Cannot force revoke a license as non-sudo', async ({helper}) => {
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await expect(helper.collatorSelection.forceReleaseLicense(superuser, account.address))
- .to.be.rejectedWith(/BadOrigin/);
- });
- });
- });
-
- describe('Onboarding, collating, and offboarding as collator candidates', () => {
- let crowd: IKeyringPair[];
-
- before(async function() {
- await usingPlaygrounds(async (helper) => {
- crowd = await helper.arrange.createCrowd(20, 100n, superuser);
-
- // set session keys for everyone
- await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
- });
- });
-
- describe('Positive', () => {
- itSub('Can onboard and offboard repeatedly', async ({helper}) => {
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await helper.collatorSelection.onboard(account);
- expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
-
- await helper.collatorSelection.offboard(account);
- expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
-
- await helper.collatorSelection.onboard(account);
- expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
-
- await helper.collatorSelection.offboard(account);
- expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
- });
-
- itSub('Penalizes and forfeits license from faulty collators', async ({helper}) => {
- // This one shouldn't even be able to produce blocks.
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await helper.collatorSelection.onboard(account);
- expect(await helper.collatorSelection.getCandidates()).to.contain(account.address);
-
- // Wait for 3 new sessions before checking that the collator will be kicked:
- // one to get collator onboarded, and another two for the collator to fail
- await helper.wait.newSessions(3);
-
- expect(await helper.collatorSelection.getCandidates()).to.not.contain(account.address);
- expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
-
- // The account's reserved funds get slashed as a penalty
- const balance = await helper.balance.getSubstrateFull(account.address);
- expect(balance.reserved).to.be.equal(0n);
- expect(balance.free < 100n - licenseBond);
- });
- });
-
- describe('Negative', () => {
- itSub('Cannot onboard without a license', async ({helper}) => {
- const account = crowd.pop()!;
- await expect(helper.collatorSelection.onboard(account))
- .to.be.rejectedWith(/collatorSelection.NoLicense/);
- });
-
- itSub('Cannot offboard without a license', async ({helper}) => {
- const account = crowd.pop()!;
- await expect(helper.collatorSelection.offboard(account))
- .to.be.rejectedWith(/collatorSelection.NotCandidate/);
- });
-
- itSub('Cannot offboard while not onboarded', async ({helper}) => {
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await expect(helper.collatorSelection.offboard(account))
- .to.be.rejectedWith(/collatorSelection.NotCandidate/);
- });
-
- itSub('Cannot onboard while already onboarded', async ({helper}) => {
- const account = crowd.pop()!;
- await helper.collatorSelection.obtainLicense(account);
- await helper.collatorSelection.onboard(account);
- await expect(helper.collatorSelection.onboard(account))
- .to.be.rejectedWith(/collatorSelection.AlreadyCandidate/);
- });
- });
- });
-
- describe('Addition and removal of invulnerables', () => {
- describe('Positive', () => {
- itSub('Adds an invulnerable', async ({helper}) => {
- const [account] = await helper.arrange.createAccounts([10n], superuser);
- const invulnerables = await helper.collatorSelection.getInvulnerables();
-
- await helper.session.setOwnKeysFromAddress(account);
- await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);
- });
-
- itSub('Removes an invulnerable', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- const lastInvulnerable = invulnerables.pop()!;
-
- await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- // invulnerables had its last element removed, so they should be equal
- expect(newInvulnerables).to.have.all.members(invulnerables);
- });
- });
-
- describe('Negative', () => {
- itSub('Does not duplicate an invulnerable', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- // adding an already invulnerable should not fail, but should not duplicate it either
- await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))
- .to.be.fulfilled;
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.have.all.members(invulnerables);
- });
-
- itSub('Cannot remove a non-existent invulnerable', async ({helper}) => {
- const [account] = await helper.arrange.createAccounts([0n], superuser);
- await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, account.address))
- .to.be.rejectedWith(/collatorSelection.NotInvulnerable/);
- });
-
- itSub('Cannot allow invulnerables to be empty', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- const lastInvulnerable = invulnerables.pop()!;
-
- let nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(invulnerables.map((i: any) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));
-
- await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))
- .to.be.rejectedWith(/collatorSelection.TooFewInvulnerables/);
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);
-
- // restore the invulnerables to the previous state
- nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(invulnerables.map((i: any) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));
- });
-
- itSub('Cannot have too many invulnerables', async ({helper}) => {
- // todo:collator make sure that there is enough session time for a set of tests
- // 28 non-functioning collators, teehee.
-
- const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
- const invulnerablesUntilLimit = (await helper.collatorSelection.getDesiredCollators()) - invulnerablesLength;
- const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
- const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
-
- await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
- helper.session.setOwnKeysFromAddress(i)));
- await helper.session.setOwnKeysFromAddress(lastInvulnerable);
-
- let nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));
-
- await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))
- .to.be.rejectedWith(/collatorSelection.TooManyInvulnerables/);
-
- // restore the invulnerables to the previous state
- nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));
- });
-
- itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {
- const [account] = await helper.arrange.createAccounts([10n], superuser);
- const invulnerables = await helper.collatorSelection.getInvulnerables();
-
- await helper.session.setOwnKeysFromAddress(account);
- await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))
- .to.be.rejectedWith(/BadOrigin/);
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.be.members(invulnerables);
- });
-
- itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))
- .to.be.rejectedWith(/BadOrigin/);
- expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
- });
-
- after(async function() {
- await resetInvulnerables();
- });
- });
- });
-
- after(async function() {
- if(!process.env.RUN_COLLATOR_TESTS) return;
-
- await usingPlaygrounds(async (helper) => {
- if(helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;
-
- await helper.getSudo().collatorSelection.setLicenseBond(superuser, previousLicenseBond);
-
- const candidates = await helper.collatorSelection.getCandidates();
- let nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(candidates.map(candidate =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.forceReleaseLicense', [candidate], true, {nonce: nonce++})));
- });
- });
-});
js-packages/tests/src/collator-selection/identity.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/collator-selection/identity.seqtest.ts
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-
-async function getIdentities(helper: UniqueHelper) {
- const identities: [string, any][] = [];
- for(const [key, value] of await helper.getApi().query.identity.identityOf.entries())
- identities.push([(key as any).toHuman(), (value as any).unwrap()]);
- return identities;
-}
-
-async function getIdentityAccounts(helper: UniqueHelper) {
- return (await getIdentities(helper)).flatMap(([key, _value]) => key);
-}
-
-async function getSubIdentityAccounts(helper: UniqueHelper, address: string) {
- return ((await helper.getApi().query.identity.subsOf(address)).toHuman() as any)[1];
-}
-
-async function getSubIdentityName(helper: UniqueHelper, address: string) {
- return ((await helper.getApi().query.identity.superOf(address)).toHuman() as any);
-}
-
-describe('Integration Test: Identities Manipulation', () => {
- let superuser: IKeyringPair;
-
- before(async function() {
- if(!process.env.RUN_COLLATOR_TESTS) this.skip();
-
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Identity]);
- superuser = await privateKey('//Alice');
- });
- });
-
- itSub('Normal calls do not work', async ({helper}) => {
- // console.error = () => {};
- await expect(helper.executeExtrinsic(superuser, 'api.tx.identity.setIdentity', [{info: {display: {Raw: 'Meowser'}}}] as any))
- .to.be.rejectedWith(/Transaction call is not expected/);
- });
-
- describe('Identities', () => {
- itSub('Sets identities', async ({helper}) => {
- const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
-
- const crowdSize = 10;
- const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
- const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-
- expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + crowdSize);
- });
-
- itSub('Setting identities does not delete existing but does overwrite', async ({helper}) => {
- const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
- const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
-
- // insert a single identity
- let singleIdentity = identities.pop()!;
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [[singleIdentity]] as any);
-
- const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
-
- // change an identity and push it with a few new others
- singleIdentity = [singleIdentity[0], {info: {display: {Raw: 'something special'}}}];
- identities.push(singleIdentity);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-
- // oldIdentitiesCount + 9 because one identity is overwritten, not inserted on top
- expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + 9);
- expect((await helper.callRpc('api.query.identity.identityOf', [singleIdentity[0]])).toHuman().info.display)
- .to.be.deep.equal({Raw: 'something special'});
- });
-
- itSub('Removes identities', async ({helper}) => {
- const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
- const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
- const oldIdentities = await getIdentityAccounts(helper);
-
- // delete a couple, check that they are no longer there
- const scapegoats = [crowd.pop()!.address, crowd.pop()!.address];
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [scapegoats]);
- const newIdentities = await getIdentityAccounts(helper);
- expect(newIdentities.concat(scapegoats)).to.be.have.members(oldIdentities);
- });
- });
-
- describe('Sub-identities', () => {
- itSub('Sets subs', async ({helper}) => {
- const crowdSize = 18;
- const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
- const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
-
- const subsPerSup = crowd.length / supers.length;
- let subCount = 0;
- const subs = [
- crowd.slice(subCount, subCount += subsPerSup + 1),
- crowd.slice(subCount, subCount += subsPerSup),
- crowd.slice(subCount, subCount += subsPerSup - 1),
- ];
-
- const subsInfo = supers.map((acc, i) => [
- acc.address, [
- 1000000n + BigInt(i + 1),
- subs[i].map((sub, j) => [
- sub.address, {Raw: `accounter #${j}`},
- ]),
- ],
- ]);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
-
- for(let i = 0; i < supers.length; i++) {
- // check deposit
- expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
-
- const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
- // check sub-identities as account ids
- expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
-
- for(let j = 0; j < subsAccounts.length; j++) {
- // check sub-identities' names
- expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
- }
- }
- });
-
- itSub('Setting sub-identities does not delete other existing but does overwrite own', async ({helper}) => {
- const crowdSize = 18;
- const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
- const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
-
- const subsPerSup = crowd.length / supers.length;
- let subCount = 0;
- const subs = [
- crowd.slice(subCount, subCount += subsPerSup + 1),
- crowd.slice(subCount, subCount += subsPerSup),
- crowd.slice(subCount, subCount += subsPerSup - 1),
- ];
-
- const subsInfo1 = supers.map((acc, i) => [
- acc.address, [
- 1000000n + BigInt(i + 1),
- subs[i].map((sub, j) => [
- sub.address, {Raw: `accounter #${j}`},
- ]),
- ],
- ]);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
-
- // change some sub-identities...
- subs[2].pop(); subs[2].pop(); subs[2].push(...await helper.arrange.createAccounts([0n], superuser));
-
- // ...and set them
- const subsInfo2 = [[
- supers[2].address, [
- 999999n,
- subs[2].map((sub, j) => [
- sub.address, {Raw: `discounter #${j}`},
- ]),
- ],
- ]];
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
-
- // make sure everything else is the same
- for(let i = 0; i < supers.length - 1; i++) {
- // check deposit
- expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
-
- const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
- // check sub-identities as account ids
- expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
-
- for(let j = 0; j < subsAccounts; j++) {
- // check sub-identities' names
- expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
- }
- }
-
- // check deposit
- expect(((await helper.getApi().query.identity.subsOf(supers[2].address)).toJSON() as any)[0]).to.be.equal(999999);
-
- const subsAccounts = await getSubIdentityAccounts(helper, supers[2].address);
- // check sub-identities as account ids
- expect(subsAccounts).to.include.members(subs[2].map(x => x.address));
-
- for(let j = 0; j < subsAccounts.length; j++) {
- // check sub-identities' names
- expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `discounter #${j}`});
- }
- });
-
- itSub('Removes sub-identities', async ({helper}) => {
- const crowdSize = 3;
- const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
- const sup = crowd.pop()!;
-
- const subsInfo1 = [[
- sup.address, [
- 1000000n,
- crowd.map((sub, j) => [
- sub.address, {Raw: `accounter #${j}`},
- ]),
- ],
- ]];
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
-
- // empty sub-identities should delete the records
- const subsInfo2 = [[
- sup.address, [
- 1000000n,
- [],
- ],
- ]];
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
-
- // check deposit
- expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
-
- for(let j = 0; j < crowd.length; j++) {
- // check sub-identities' names
- expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
- }
- });
-
- itSub('Removing identities deletes associated sub-identities', async ({helper}) => {
- const crowd = await helper.arrange.createCrowd(3, 0n, superuser);
- const sup = crowd.pop()!;
-
- // insert identity
- const identities = [[sup.address, {info: {display: {Raw: 'mental'}}}]];
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-
- // and its sub-identities
- const subsInfo = [[
- sup.address, [
- 1000000n,
- crowd.map((sub, j) => [
- sub.address, {Raw: `accounter #${j}`},
- ]),
- ],
- ]];
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
-
- // delete top identity
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [[sup.address]]);
-
- // check that sub-identities are deleted
- expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
-
- for(let j = 0; j < crowd.length; j++) {
- // check sub-identities' names
- expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
- }
- });
- });
-
- after(async function() {
- if(!process.env.RUN_COLLATOR_TESTS) return;
-
- await usingPlaygrounds(async helper => {
- if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) return;
-
- const identitiesToRemove: string[] = await getIdentityAccounts(helper);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [identitiesToRemove]);
- });
- });
-});
js-packages/tests/src/config.tsdiffbeforeafterboth--- a/js-packages/tests/src/config.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import process from 'process';
-
-const config = {
- relayUrl: process.env.RELAY_URL || 'ws://127.0.0.1:9844',
- substrateUrl: process.env.RELAY_OPAL_URL || process.env.RELAY_QUARTZ_URL || process.env.RELAY_UNIQUE_URL || process.env.RELAY_SAPPHIRE_URL || 'ws://127.0.0.1:9944',
- acalaUrl: process.env.RELAY_ACALA_URL || 'ws://127.0.0.1:9946',
- karuraUrl: process.env.RELAY_KARURA_URL || 'ws://127.0.0.1:9946',
- moonbeamUrl: process.env.RELAY_MOONBEAM_URL || 'ws://127.0.0.1:9947',
- moonriverUrl: process.env.RELAY_MOONRIVER_URL || 'ws://127.0.0.1:9947',
- astarUrl: process.env.RELAY_ASTAR_URL || 'ws://127.0.0.1:9949',
- shidenUrl: process.env.RELAY_SHIDEN_URL || 'ws://127.0.0.1:9949',
- westmintUrl: process.env.RELAY_WESTMINT_URL || 'ws://127.0.0.1:9948',
- statemineUrl: process.env.RELAY_STATEMINE_URL || 'ws://127.0.0.1:9948',
- statemintUrl: process.env.RELAY_STATEMINT_URL || 'ws://127.0.0.1:9948',
- polkadexUrl: process.env.RELAY_POLKADEX_URL || 'ws://127.0.0.1:9950',
-};
-
-export default config;
js-packages/tests/src/config_docker.tsdiffbeforeafterboth--- a/js-packages/tests/src/config_docker.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import process from 'process';
-
-const config = {
- substrateUrl: process.env.substrateUrl || 'ws://blockchain_nodes:9944',
-};
-
-export default config;
js-packages/tests/src/confirmSponsorship.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/confirmSponsorship.test.ts
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-async function setSponsorHelper(collection: any, signer: IKeyringPair, sponsorAddress: string) {
- await collection.setSponsor(signer, sponsorAddress);
- const raw = (await collection.getData())?.raw;
- expect(raw.sponsorship.Unconfirmed).to.be.equal(sponsorAddress);
-}
-
-async function confirmSponsorHelper(collection: any, signer: IKeyringPair) {
- await collection.confirmSponsorship(signer);
- const raw = (await collection.getData())?.raw;
- expect(raw.sponsorship.Confirmed).to.be.equal(signer.address);
-}
-
-describe('integration test: ext. confirmSponsorship():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
- let zeroBalance: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie, zeroBalance] = await helper.arrange.createAccounts([100n, 100n, 100n, 0n], donor);
- });
- });
-
- itSub('Confirm collection sponsorship', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await setSponsorHelper(collection, alice, bob.address);
- await confirmSponsorHelper(collection, bob);
- });
-
- itSub('Add sponsor to a collection after the same sponsor was already added and confirmed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await setSponsorHelper(collection, alice, bob.address);
- await confirmSponsorHelper(collection, bob);
- await setSponsorHelper(collection, alice, bob.address);
- });
- itSub('Add new sponsor to a collection after another sponsor was already added and confirmed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await setSponsorHelper(collection, alice, bob.address);
- await confirmSponsorHelper(collection, bob);
- await setSponsorHelper(collection, alice, charlie.address);
- });
-
- itSub('NFT: Transfer fees are paid by the sponsor after confirmation', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
- const token = await collection.mintToken(alice, {Substrate: zeroBalance.address});
- await token.transfer(zeroBalance, {Substrate: alice.address});
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
- expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
- });
-
- itSub('Fungible: Transfer fees are paid by the sponsor after confirmation', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
- await collection.mint(alice, 100n, {Substrate: zeroBalance.address});
- await collection.transfer(zeroBalance, {Substrate: alice.address}, 1n);
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
- expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
- });
-
- itSub.ifWithPallets('ReFungible: Transfer fees are paid by the sponsor after confirmation', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
- const token = await collection.mintToken(alice, 100n, {Substrate: zeroBalance.address});
- await token.transfer(zeroBalance, {Substrate: alice.address}, 1n);
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
- expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
- });
-
- itSub('CreateItem fees are paid by the sponsor after confirmation', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- await collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
- await collection.addToAllowList(alice, {Substrate: zeroBalance.address});
-
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
- await collection.mintToken(zeroBalance, {Substrate: zeroBalance.address});
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
- });
-
- itSub('NFT: Sponsoring of transfers is rate limited', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
- sponsorTransferTimeout: 1000,
- }});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
-
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- await token.transfer(alice, {Substrate: zeroBalance.address});
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- const transferTx = () => token.transfer(zeroBalance, {Substrate: alice.address});
- await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees');
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
- });
-
- itSub('Fungible: Sponsoring is rate limited', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
- sponsorTransferTimeout: 1000,
- }});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
-
- await collection.mint(alice, 100n, {Substrate: zeroBalance.address});
- await collection.transfer(zeroBalance, {Substrate: zeroBalance.address}, 1n);
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- const transferTx = () => collection.transfer(zeroBalance, {Substrate: zeroBalance.address});
- await expect(transferTx()).to.be.rejected;
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
- });
-
- itSub.ifWithPallets('ReFungible: Sponsoring is rate limited', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
- sponsorTransferTimeout: 1000,
- }});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
-
- const token = await collection.mintToken(alice, 100n, {Substrate: zeroBalance.address});
- await token.transfer(zeroBalance, {Substrate: alice.address});
-
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
- const transferTx = () => token.transfer(zeroBalance, {Substrate: alice.address});
- await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees');
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
- });
-
- itSub('NFT: Sponsoring of createItem is rate limited', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', limits: {
- sponsoredDataRateLimit: {blocks: 1000},
- sponsorTransferTimeout: 1000,
- }});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- await collection.setPermissions(alice, {mintMode: true, access: 'AllowList'});
- await collection.addToAllowList(alice, {Substrate: zeroBalance.address});
-
- await collection.mintToken(zeroBalance, {Substrate: zeroBalance.address});
-
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
- const mintTx = () => collection.mintToken(zeroBalance, {Substrate: zeroBalance.address});
- await expect(mintTx()).to.be.rejectedWith('Inability to pay some fees');
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(bobBalanceAfter === bobBalanceBefore).to.be.true;
- });
-});
-
-describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
- let ownerZeroBalance: IKeyringPair;
- let senderZeroBalance: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie, ownerZeroBalance, senderZeroBalance] = await helper.arrange.createAccounts([100n, 100n, 100n, 0n, 0n], donor);
- });
- });
-
- itSub('(!negative test!) Confirm sponsorship for a collection that never existed', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- const confirmSponsorshipTx = () => helper.collection.confirmSponsorship(bob, collectionId);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('(!negative test!) Confirm sponsorship using a non-sponsor address', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- });
-
- itSub('(!negative test!) Confirm sponsorship using owner address', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- const confirmSponsorshipTx = () => collection.confirmSponsorship(alice);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- });
-
- itSub('(!negative test!) Confirm sponsorship by collection admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- await collection.addAdmin(alice, {Substrate: charlie.address});
- const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- });
-
- itSub('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- });
-
- itSub('(!negative test!) Confirm sponsorship in a collection that was destroyed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.burn(alice);
- const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
- await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- const token = await collection.mintToken(alice, {Substrate: ownerZeroBalance.address});
- const sponsorBalanceBefore = await helper.balance.getSubstrate(bob.address);
- const transferTx = () => token.transfer(senderZeroBalance, {Substrate: alice.address});
- await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees');
- const sponsorBalanceAfter = await helper.balance.getSubstrate(bob.address);
- expect(sponsorBalanceAfter).to.equal(sponsorBalanceBefore);
- });
-});
js-packages/tests/src/connection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/connection.test.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {itSub, expect, usingPlaygrounds} from './util/index.js';
-
-describe('Connection smoke test', () => {
- itSub('Connection can be established', async ({helper}) => {
- const health = (await helper.callRpc('api.rpc.system.health')).toJSON();
- expect(health).to.be.not.empty;
- });
-
- it('Cannot connect to 255.255.255.255', async () => {
- await expect((async () => {
- await usingPlaygrounds(async helper => {
- await helper.callRpc('api.rpc.system.health');
- }, 'ws://255.255.255.255:9944');
- })()).to.be.eventually.rejected;
- });
-});
js-packages/tests/src/createCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/createCollection.test.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets} from './util/index.js';
-import {CollectionFlag} from '@unique/playgrounds/src/types.js';
-import type {ICollectionCreationOptions, IProperty} from '@unique/playgrounds/src/types.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-
-async function mintCollectionHelper(helper: UniqueHelper, signer: IKeyringPair, options: ICollectionCreationOptions, type?: 'nft' | 'fungible' | 'refungible') {
- let collection;
- if(type === 'nft') {
- collection = await helper.nft.mintCollection(signer, options);
- } else if(type === 'fungible') {
- collection = await helper.ft.mintCollection(signer, options, 0);
- } else {
- collection = await helper.rft.mintCollection(signer, options);
- }
- const data = await collection.getData();
- expect(data?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(signer.address));
- expect(data?.name).to.be.equal(options.name);
- expect(data?.description).to.be.equal(options.description);
- expect(data?.raw.tokenPrefix).to.be.equal(options.tokenPrefix);
- if(options.properties) {
- expect(data?.raw.properties).to.be.deep.equal(options.properties);
- }
- if(options.adminList) {
- expect(data?.admins).to.be.deep.equal(options.adminList);
- }
-
- if(options.flags) {
- if((options.flags[0] & 64) != 0)
- expect(data?.raw.flags.erc721metadata).to.be.true;
- if((options.flags[0] & 128) != 0)
- expect(data?.raw.flags.foreign).to.be.false;
- }
-
- if(options.tokenPropertyPermissions) {
- expect(data?.raw.tokenPropertyPermissions).to.be.deep.equal(options.tokenPropertyPermissions);
- }
-
- return collection;
-}
-
-describe('integration test: ext. createCollection():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
- itSub('Create new NFT collection', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 'nft');
- });
- itSub('Create new NFT collection whith collection_name of maximum length (64 bytes)', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {name: 'A'.repeat(64), description: 'descr', tokenPrefix: 'COL'}, 'nft');
- });
- itSub('Create new NFT collection whith collection_description of maximum length (256 bytes)', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {name: 'name', description: 'A'.repeat(256), tokenPrefix: 'COL'}, 'nft');
- });
- itSub('Create new NFT collection whith token_prefix of maximum length (16 bytes)', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(16)}, 'nft');
- });
-
- itSub('Create new Fungible collection', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'fungible');
- });
-
- itSub.ifWithPallets('Create new ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
- await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'refungible');
- });
-
- itSub('create new collection with properties', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {
- name: 'name', description: 'descr', tokenPrefix: 'COL',
- properties: [{key: 'key1', value: 'val1'}],
- tokenPropertyPermissions: [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}],
- }, 'nft');
- });
-
- itSub('create new collection with admin', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {
- name: 'name', description: 'descr', tokenPrefix: 'COL',
- adminList: [{Substrate: bob.address}],
- }, 'nft');
- });
-
- itSub('create new collection with flags', async ({helper}) => {
- await mintCollectionHelper(helper, alice, {
- name: 'name', description: 'descr', tokenPrefix: 'COL',
- flags: [CollectionFlag.Erc721metadata],
- }, 'nft');
-
- // User can not set Foreign flag itself
-
- await expect(mintCollectionHelper(helper, alice, {
- name: 'name', description: 'descr', tokenPrefix: 'COL',
- flags: [CollectionFlag.Foreign],
- }, 'nft')).to.be.rejectedWith(/common.NoPermission/);
-
- await expect(mintCollectionHelper(helper, alice, {
- name: 'name', description: 'descr', tokenPrefix: 'COL',
- flags: [CollectionFlag.Erc721metadata, CollectionFlag.Foreign],
- }, 'nft')).to.be.rejectedWith(/common.NoPermission/);
- });
-
- itSub('Create new collection with extra fields', async ({helper}) => {
- const collection = await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'fungible');
- await collection.setPermissions(alice, {access: 'AllowList'});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 3});
- const data = await collection.getData();
- const limits = await collection.getEffectiveLimits();
- const raw = data?.raw;
-
- expect(data?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address));
- expect(data?.name).to.be.equal('name');
- expect(data?.description).to.be.equal('descr');
- expect(raw.permissions.access).to.be.equal('AllowList');
- expect(raw.mode).to.be.deep.equal({Fungible: '0'});
- expect(limits.accountTokenOwnershipLimit).to.be.equal(3);
- });
-
- itSub('New collection is not external', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
- const data = await collection.getData();
- expect(data?.raw.readOnly).to.be.false;
- });
-});
-
-describe('(!negative test!) integration test: ext. createCollection():', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- itSub('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async ({helper}) => {
- const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'A'.repeat(65), description: 'descr', tokenPrefix: 'COL'});
- await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
- });
- itSub('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async ({helper}) => {
- const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'A'.repeat(257), tokenPrefix: 'COL'});
- await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
- });
- itSub('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async ({helper}) => {
- const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(17)});
- await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
- });
-
- itSub('(!negative test!) fails when bad limits are set', async ({helper}) => {
- const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', limits: {tokenLimit: 0}});
- await expect(mintCollectionTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
- });
-
- itSub('(!negative test!) create collection with incorrect property limit (64 elements)', async ({helper}) => {
- const props: IProperty[] = [];
-
- for(let i = 0; i < 65; i++) {
- props.push({key: `key${i}`, value: `value${i}`});
- }
- const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', properties: props});
- await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
- });
-
- itSub('(!negative test!) create collection with incorrect property limit (40 kb)', async ({helper}) => {
- const props: IProperty[] = [];
-
- for(let i = 0; i < 32; i++) {
- props.push({key: `key${i}`.repeat(80), value: `value${i}`.repeat(80)});
- }
-
- const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', properties: props});
- await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error');
- });
-});
js-packages/tests/src/createItem.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/createItem.test.ts
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets} from './util/index.js';
-import type {IProperty, ICrossAccountId} from '@unique/playgrounds/src/types.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-
-async function mintTokenHelper(helper: UniqueHelper, collection: any, signer: IKeyringPair, owner: ICrossAccountId, type: 'nft' | 'fungible' | 'refungible'='nft', properties?: IProperty[]) {
- let token;
- const itemCountBefore = await helper.collection.getLastTokenId(collection.collectionId);
- const itemBalanceBefore = (await helper.callRpc('api.rpc.unique.balance', [collection.collectionId, owner, 0])).toBigInt();
- if(type === 'nft') {
- token = await collection.mintToken(signer, owner, properties);
- } else if(type === 'fungible') {
- await collection.mint(signer, 10n, owner);
- } else {
- token = await collection.mintToken(signer, 100n, owner, properties);
- }
-
- const itemCountAfter = await helper.collection.getLastTokenId(collection.collectionId);
- const itemBalanceAfter = (await helper.callRpc('api.rpc.unique.balance', [collection.collectionId, owner, 0])).toBigInt();
-
- if(type === 'fungible') {
- expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);
- } else {
- expect(itemCountAfter).to.be.equal(itemCountBefore + 1);
- }
-
- return token;
-}
-
-
-describe('integration test: ext. ():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Create new item in NFT collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await mintTokenHelper(helper, collection, alice, {Substrate: alice.address});
- });
- itSub('Create new item in Fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}, 'fungible');
- });
- itSub('Check events on create new item in Fungible collection', async ({helper}) => {
- const {collectionId} = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
- const to = {Substrate: alice.address};
- {
- const createData = {fungible: {value: 100}};
- const events = await helper.executeExtrinsic(alice, 'api.tx.unique.createItem', [collectionId, to, createData as any]);
- const result = helper.util.extractTokensFromCreationResult(events);
- expect(result.tokens[0].amount).to.be.equal(100n);
- expect(result.tokens[0].collectionId).to.be.equal(collectionId);
- expect(result.tokens[0].owner).to.be.deep.equal(to);
- }
- {
- const createData = {fungible: {value: 50}};
- const events = await helper.executeExtrinsic(alice, 'api.tx.unique.createItem', [collectionId, to, createData as any]);
- const result = helper.util.extractTokensFromCreationResult(events);
- expect(result.tokens[0].amount).to.be.equal(50n);
- expect(result.tokens[0].collectionId).to.be.equal(collectionId);
- expect(result.tokens[0].owner).to.be.deep.equal(to);
- }
- });
- itSub.ifWithPallets('Create new item in ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}, 'refungible');
- });
- itSub('Create new item in NFT collection with collection admin permissions', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.addAdmin(alice, {Substrate: bob.address});
- await mintTokenHelper(helper, collection, bob, {Substrate: alice.address});
- });
- itSub('Create new item in Fungible collection with collection admin permissions', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- await collection.addAdmin(alice, {Substrate: bob.address});
- await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}, 'fungible');
- });
- itSub.ifWithPallets('Create new item in ReFungible collection with collection admin permissions', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- await collection.addAdmin(alice, {Substrate: bob.address});
- await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}, 'refungible');
- });
-
- itSub('Set property Admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL',
- properties: [{key: 'k', value: 'v'}],
- tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: false, mutable: true, collectionAdmin: true}}],
- });
- await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]);
- });
-
- itSub('Set property AdminConst', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL',
- properties: [{key: 'k', value: 'v'}],
- tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}}],
- });
- await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]);
- });
-
- itSub('Set property itemOwnerOrAdmin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL',
- properties: [{key: 'k', value: 'v'}],
- tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}],
- });
- await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]);
- });
-
- itSub('Check total pieces of Fungible token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- const amount = 10n;
- await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'fungible');
- {
- const totalPieces = await collection.getTotalPieces();
- expect(totalPieces).to.be.equal(amount);
- }
- await collection.transfer(bob, {Substrate: alice.address}, 1n);
- {
- const totalPieces = await collection.getTotalPieces();
- expect(totalPieces).to.be.equal(amount);
- }
- });
-
- itSub('Check total pieces of NFT token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const amount = 1n;
- const token = await mintTokenHelper(helper, collection, alice, {Substrate: bob.address});
- {
- const totalPieces = await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, token.tokenId]);
- expect(totalPieces?.unwrap().toBigInt()).to.be.equal(amount);
- }
- await token.transfer(bob, {Substrate: alice.address});
- {
- const totalPieces = await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, token.tokenId]);
- expect(totalPieces?.unwrap().toBigInt()).to.be.equal(amount);
- }
- });
-
- itSub.ifWithPallets('Check total pieces of ReFungible token', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const amount = 100n;
- const token = await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'refungible');
- {
- const totalPieces = await token.getTotalPieces();
- expect(totalPieces).to.be.equal(amount);
- }
- await token.transfer(bob, {Substrate: alice.address}, 60n);
- {
- const totalPieces = await token.getTotalPieces();
- expect(totalPieces).to.be.equal(amount);
- }
- });
-});
-
-describe('Negative integration test: ext. createItem():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Regular user cannot create new item in NFT collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const mintTx = () => collection.mintToken(bob, {Substrate: bob.address});
- await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
- });
- itSub('Regular user cannot create new item in Fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- const mintTx = () => collection.mint(bob, 10n, {Substrate: bob.address});
- await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
- });
- itSub.ifWithPallets('Regular user cannot create new item in ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const mintTx = () => collection.mintToken(bob, 100n, {Substrate: bob.address});
- await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
- });
-
- itSub('No editing rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL',
- tokenPropertyPermissions: [{key: 'k', permission: {mutable: false, collectionAdmin: false, tokenOwner: false}}],
- });
- const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]);
- await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('User doesnt have editing rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL',
- tokenPropertyPermissions: [{key: 'k', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}],
- });
- const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]);
- await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Adding property without access rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]);
- await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Adding more than 64 prps', async ({helper}) => {
- const props: IProperty[] = [];
-
- for(let i = 0; i < 65; i++) {
- props.push({key: `key${i}`, value: `value${i}`});
- }
-
-
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, props);
- await expect(mintTx()).to.be.rejectedWith('Verification Error');
- });
-
- itSub('Trying to add bigger property than allowed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'k1', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
- {key: 'k2', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
- ],
- });
- const mintTx = () => collection.mintToken(alice, {Substrate: bob.address}, [
- {key: 'k1', value: 'vvvvvv'.repeat(5000)},
- {key: 'k2', value: 'vvv'.repeat(5000)},
- ]);
- await expect(mintTx()).to.be.rejectedWith(/common\.NoSpaceForProperty/);
- });
-
- itSub('Check total pieces for invalid Fungible token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
- const invalidTokenId = 1_000_000;
- expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true;
- expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n);
- });
-
- itSub('Check total pieces for invalid NFT token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const invalidTokenId = 1_000_000;
- expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true;
- expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n);
- });
-
- itSub.ifWithPallets('Check total pieces for invalid Refungible token', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
- const invalidTokenId = 1_000_000;
- expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true;
- expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n);
- });
-});
js-packages/tests/src/createMultipleItems.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/createMultipleItems.test.ts
+++ /dev/null
@@ -1,374 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, Pallets, itSub} from './util/index.js';
-
-describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- itSub('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: '1'}]},
- {properties: [{key: 'data', value: '2'}]},
- {properties: [{key: 'data', value: '3'}]},
- ];
- const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- for(const [i, token] of tokens.entries()) {
- const tokenData = await token.getData();
- expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
- expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
- }
- });
-
- itSub('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const args = [
- {value: 1n},
- {value: 2n},
- {value: 3n},
- ];
- await helper.ft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, args, {Substrate: alice.address});
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(6n);
- });
-
- itSub.ifWithPallets('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const args = [
- {pieces: 1n},
- {pieces: 2n},
- {pieces: 3n},
- ];
- const tokens = await helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
-
- for(const [i, token] of tokens.entries()) {
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(BigInt(i + 1));
- }
- });
-
- itSub('Can mint amount of items equals to collection limits', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- limits: {
- tokenLimit: 2,
- },
- });
- const args = [{}, {}];
- await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- });
-
- itSub('Create 0x31, 0x32, 0x33 items in active NFT with property Admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: false, mutable: true, collectionAdmin: true}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: '1'}]},
- {properties: [{key: 'data', value: '2'}]},
- {properties: [{key: 'data', value: '3'}]},
- ];
- const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- for(const [i, token] of tokens.entries()) {
- const tokenData = await token.getData();
- expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
- expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
- }
- });
-
- itSub('Create 0x31, 0x32, 0x33 items in active NFT with property AdminConst', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: '1'}]},
- {properties: [{key: 'data', value: '2'}]},
- {properties: [{key: 'data', value: '3'}]},
- ];
- const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- for(const [i, token] of tokens.entries()) {
- const tokenData = await token.getData();
- expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
- expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
- }
- });
-
- itSub('Create 0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: '1'}]},
- {properties: [{key: 'data', value: '2'}]},
- {properties: [{key: 'data', value: '3'}]},
- ];
- const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- for(const [i, token] of tokens.entries()) {
- const tokenData = await token.getData();
- expect(tokenData?.normalizedOwner).to.be.deep.equal({Substrate: helper.address.normalizeSubstrate(alice.address)});
- expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value);
- }
- });
-});
-
-describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Regular user cannot create items in active NFT collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const args = [
- {},
- {},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
- });
-
- itSub('Regular user cannot create items in active Fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const args = [
- {value: 1n},
- {value: 2n},
- {value: 3n},
- ];
- const mintTx = () => helper.ft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, args, {Substrate: alice.address});
- await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
- });
-
- itSub.ifWithPallets('Regular user cannot create items in active ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const args = [
- {pieces: 1n},
- {pieces: 1n},
- {pieces: 1n},
- ];
- const mintTx = () => helper.rft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/);
- });
-
- itSub('Create token in not existing collection', async ({helper}) => {
- const collectionId = 1_000_000;
- const args = [
- {},
- {},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(bob, collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Create NFTs that has reached the maximum data limit', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: 'A'.repeat(32769)}]},
- {properties: [{key: 'data', value: 'B'.repeat(32769)}]},
- {properties: [{key: 'data', value: 'C'.repeat(32769)}]},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith('Verification Error');
- });
-
- itSub.ifWithPallets('Create Refungible tokens that has reached the maximum data limit', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
- ],
- });
- const args = [
- {pieces: 10n, properties: [{key: 'data', value: 'A'.repeat(32769)}]},
- {pieces: 10n, properties: [{key: 'data', value: 'B'.repeat(32769)}]},
- {pieces: 10n, properties: [{key: 'data', value: 'C'.repeat(32769)}]},
- ];
- const mintTx = () => helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith('Verification Error');
- });
-
- itSub.ifWithPallets('Create tokens with different types', [Pallets.ReFungible], async ({helper}) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
-
- const types = ['NFT', 'Fungible', 'ReFungible'];
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.createMultipleItems',
- [collectionId, {Substrate: alice.address}, types],
- )).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/);
- });
-
- itSub('Create tokens with different data limits <> maximum data limit', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: 'A'}]},
- {properties: [{key: 'data', value: 'B'.repeat(32769)}]},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith('Verification Error');
- });
-
- itSub('Fails when minting tokens exceeds collectionLimits amount', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
- ],
- limits: {
- tokenLimit: 1,
- },
- });
- const args = [
- {},
- {},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
- });
-
- itSub('User doesnt have editing rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'data', permission: {tokenOwner: false, mutable: true, collectionAdmin: false}},
- ],
- });
- const args = [
- {properties: [{key: 'data', value: 'A'}]},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Adding property without access rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- properties: [
- {
- key: 'data',
- value: 'v',
- },
- ],
- });
- const args = [
- {properties: [{key: 'data', value: 'A'}]},
- ];
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Adding more than 64 prps', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const prps = [];
-
- for(let i = 0; i < 65; i++) {
- prps.push({key: `key${i}`, value: `value${i}`});
- }
-
- const args = [
- {properties: prps},
- {properties: prps},
- {properties: prps},
- ];
-
- const mintTx = () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args);
- await expect(mintTx()).to.be.rejectedWith('Verification Error');
- });
-});
js-packages/tests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/createMultipleItemsEx.test.ts
+++ /dev/null
@@ -1,442 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, Pallets, itSub} from './util/index.js';
-import type {IProperty} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test: createMultipleItemsEx', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('can initialize multiple NFT with different owners', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
- const args = [
- {
- owner: {Substrate: alice.address},
- },
- {
- owner: {Substrate: bob.address},
- },
- {
- owner: {Substrate: charlie.address},
- },
- ];
-
- const tokens = await collection.mintMultipleTokens(alice, args);
- for(const [i, token] of tokens.entries()) {
- expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
- }
- });
-
- itSub('createMultipleItemsEx with property Admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: false,
- },
- },
- ],
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'v1'}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'v2'}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'v3'}],
- },
- ];
-
- const tokens = await collection.mintMultipleTokens(alice, args);
- for(const [i, token] of tokens.entries()) {
- expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
- expect(await token.getData()).to.not.be.empty;
- }
- });
-
- itSub('createMultipleItemsEx with property AdminConst', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: false,
- collectionAdmin: true,
- tokenOwner: false,
- },
- },
- ],
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'v1'}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'v2'}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'v3'}],
- },
- ];
-
- const tokens = await collection.mintMultipleTokens(alice, args);
- for(const [i, token] of tokens.entries()) {
- expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
- expect(await token.getData()).to.not.be.empty;
- }
- });
-
- itSub('createMultipleItemsEx with property itemOwnerOrAdmin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: false,
- collectionAdmin: true,
- tokenOwner: true,
- },
- },
- ],
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'v1'}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'v2'}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'v3'}],
- },
- ];
-
- const tokens = await collection.mintMultipleTokens(alice, args);
- for(const [i, token] of tokens.entries()) {
- expect(await token.getOwner()).to.be.deep.equal(args[i].owner);
- expect(await token.getData()).to.not.be.empty;
- }
- });
-
- itSub('can initialize fungible with multiple owners', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- }, 0);
-
- await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
- Fungible: new Map([
- [JSON.stringify({Substrate: alice.address}), 50],
- [JSON.stringify({Substrate: bob.address}), 100],
- ]),
- }], true);
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(50n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(100n);
- });
-
- itSub.ifWithPallets('can initialize an RFT with multiple owners', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'k', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}},
- ],
- });
-
- await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx', [collection.collectionId, {
- RefungibleMultipleOwners: {
- users: new Map([
- [JSON.stringify({Substrate: alice.address}), 1],
- [JSON.stringify({Substrate: bob.address}), 2],
- ]),
- properties: [
- {key: 'k', value: 'v'},
- ],
- },
- }], true);
- const tokenId = await collection.getLastTokenId();
- expect(tokenId).to.be.equal(1);
- expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);
- expect(await collection.getTokenBalance(1, {Substrate: bob.address})).to.be.equal(2n);
- });
-
- itSub.ifWithPallets('can initialize multiple RFTs with the same owner', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {key: 'k', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}},
- ],
- });
-
- await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx', [collection.collectionId, {
- RefungibleMultipleItems: [
- {
- user: {Substrate: alice.address}, pieces: 1,
- properties: [
- {key: 'k', value: 'v1'},
- ],
- },
- {
- user: {Substrate: alice.address}, pieces: 3,
- properties: [
- {key: 'k', value: 'v2'},
- ],
- },
- ],
- }], true);
-
- expect(await collection.getLastTokenId()).to.be.equal(2);
- expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);
- expect(await collection.getTokenBalance(2, {Substrate: alice.address})).to.be.equal(3n);
-
- const tokenData1 = await helper.rft.getToken(collection.collectionId, 1);
- expect(tokenData1).to.not.be.null;
- expect(tokenData1?.properties[0]).to.be.deep.equal({key: 'k', value: 'v1'});
-
- const tokenData2 = await helper.rft.getToken(collection.collectionId, 2);
- expect(tokenData2).to.not.be.null;
- expect(tokenData2?.properties[0]).to.be.deep.equal({key: 'k', value: 'v2'});
- });
-});
-
-describe('Negative test: createMultipleItemsEx', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('No editing rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: true,
- collectionAdmin: false,
- tokenOwner: false,
- },
- },
- ],
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'v1'}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'v2'}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'v3'}],
- },
- ];
-
- await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('User doesnt have editing rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: false,
- collectionAdmin: false,
- tokenOwner: false,
- },
- },
- ],
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'v1'}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'v2'}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'v3'}],
- },
- ];
-
- await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Adding property without access rights', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'v1'}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'v2'}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'v3'}],
- },
- ];
-
- await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Adding more than 64 properties', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: true,
- },
- },
- ],
- });
-
- const properties: IProperty[] = [];
-
- for(let i = 0; i < 65; i++) {
- properties.push({key: `k${i}`, value: `v${i}`});
- }
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: properties,
- },
- {
- owner: {Substrate: bob.address},
- properties: properties,
- },
- {
- owner: {Substrate: charlie.address},
- properties: properties,
- },
- ];
-
- await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith('Verification Error');
- });
-
- itSub('Trying to add bigger property than allowed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'name',
- description: 'descr',
- tokenPrefix: 'COL',
- tokenPropertyPermissions: [
- {
- key: 'k',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: true,
- },
- },
- ],
- });
-
- const args = [
- {
- owner: {Substrate: alice.address},
- properties: [{key: 'k', value: 'A'.repeat(32769)}],
- },
- {
- owner: {Substrate: bob.address},
- properties: [{key: 'k', value: 'A'.repeat(32769)}],
- },
- {
- owner: {Substrate: charlie.address},
- properties: [{key: 'k', value: 'A'.repeat(32769)}],
- },
- ];
-
- await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith('Verification Error');
- });
-});
js-packages/tests/src/creditFeesToTreasury.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/creditFeesToTreasury.seqtest.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {ApiPromise} from '@polkadot/api';
-import {usingPlaygrounds, expect, itSub} from './util/index.js';
-import type {u32} from '@polkadot/types-codec';
-
-const TREASURY = '5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z';
-const saneMinimumFee = 0.05;
-const saneMaximumFee = 0.5;
-const createCollectionDeposit = 100;
-
-// Skip the inflation block pauses if the block is close to inflation block
-// until the inflation happens
-/*eslint no-async-promise-executor: "off"*/
-function skipInflationBlock(api: ApiPromise): Promise<void> {
- const promise = new Promise<void>(async (resolve) => {
- const inflationBlockInterval = api.consts.inflation.inflationBlockInterval as u32;
- const blockInterval = inflationBlockInterval.toNumber();
- const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => {
- const currentBlock = head.number.toNumber();
- if(currentBlock % blockInterval < blockInterval - 10) {
- unsubscribe();
- resolve();
- } else {
- console.log(`Skipping inflation block, current block: ${currentBlock}`);
- }
- });
- });
-
- return promise;
-}
-
-describe('integration test: Fees must be credited to Treasury:', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Total issuance does not change', async ({helper}) => {
- const api = helper.getApi();
- await skipInflationBlock(api);
- await helper.wait.newBlocks(1);
-
- const totalBefore = (await helper.callRpc('api.query.balances.totalIssuance', [])).toBigInt();
-
- await helper.balance.transferToSubstrate(alice, bob.address, 1n);
-
- const totalAfter = (await helper.callRpc('api.query.balances.totalIssuance', [])).toBigInt();
-
- expect(totalAfter).to.be.equal(totalBefore);
- });
-
- itSub('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async ({helper}) => {
- await skipInflationBlock(helper.getApi());
- await helper.wait.newBlocks(1);
-
- const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-
- const amount = 1n;
- await helper.balance.transferToSubstrate(alice, bob.address, amount);
-
- const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY);
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
-
- const fee = aliceBalanceBefore - aliceBalanceAfter - amount;
- const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;
-
- expect(treasuryIncrease).to.be.equal(fee);
- });
-
- itSub('Treasury balance increased by failed tx fee', async ({helper}) => {
- const api = helper.getApi();
- await helper.wait.newBlocks(1);
-
- const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- await expect(helper.signTransaction(bob, api.tx.balances.forceSetBalance(alice.address, 0))).to.be.rejected;
-
- const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY);
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- const fee = bobBalanceBefore - bobBalanceAfter;
- const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;
-
- expect(treasuryIncrease).to.be.equal(fee);
- });
-
- itSub('NFT Transactions also send fees to Treasury', async ({helper}) => {
- await skipInflationBlock(helper.getApi());
- await helper.wait.newBlocks(1);
-
- const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-
- await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY);
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
- const fee = aliceBalanceBefore - aliceBalanceAfter;
- const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;
-
- expect(treasuryIncrease).to.be.equal(fee);
- });
-
- itSub('Fees are sane', async ({helper}) => {
- const unique = helper.balance.getOneTokenNominal();
- await skipInflationBlock(helper.getApi());
- await helper.wait.newBlocks(1);
-
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-
- await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
- const fee = aliceBalanceBefore - aliceBalanceAfter;
-
- expect(fee / unique < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true;
- expect(fee / unique < BigInt(Math.ceil(saneMinimumFee + createCollectionDeposit))).to.be.true;
- });
-
- itSub('NFT Transfer fee is close to 0.1 Unique', async ({helper}) => {
- await skipInflationBlock(helper.getApi());
- await helper.wait.newBlocks(1);
-
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
- const token = await collection.mintToken(alice, {Substrate: alice.address});
-
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
- await token.transfer(alice, {Substrate: bob.address});
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
-
- const fee = Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal());
- const expectedTransferFee = 0.1;
- // fee drifts because of NextFeeMultiplier
- const tolerance = 0.001;
-
- expect(Math.abs(fee - expectedTransferFee)).to.be.lessThan(tolerance);
- });
-});
js-packages/tests/src/destroyCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/destroyCollection.test.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, expect, usingPlaygrounds, Pallets} from './util/index.js';
-
-describe('integration test: ext. destroyCollection():', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- itSub('NFT collection can be destroyed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- await collection.burn(alice);
- expect(await collection.getData()).to.be.null;
- });
- itSub('Fungible collection can be destroyed', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- }, 0);
- await collection.burn(alice);
- expect(await collection.getData()).to.be.null;
- });
- itSub.ifWithPallets('ReFungible collection can be destroyed', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- await collection.burn(alice);
- expect(await collection.getData()).to.be.null;
- });
-});
-
-describe('(!negative test!) integration test: ext. destroyCollection():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('(!negative test!) Destroy a collection that never existed', async ({helper}) => {
- const collectionId = 1_000_000;
- await expect(helper.collection.burn(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
- itSub('(!negative test!) Destroy a collection that has already been destroyed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- await collection.burn(alice);
- await expect(collection.burn(alice)).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
- itSub('(!negative test!) Destroy a collection using non-owner account', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- await expect(collection.burn(bob)).to.be.rejectedWith(/common\.NoPermission/);
- });
- itSub('(!negative test!) Destroy a collection using collection admin account', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- await collection.addAdmin(alice, {Substrate: bob.address});
- await expect(collection.burn(bob)).to.be.rejectedWith(/common\.NoPermission/);
- });
- itSub('fails when OwnerCanDestroy == false', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- limits: {
- ownerCanDestroy: false,
- },
- });
- await expect(collection.burn(alice)).to.be.rejectedWith(/common\.NoPermission/);
- });
- itSub('fails when a collection still has a token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- });
- await collection.mintToken(alice, {Substrate: alice.address});
- await expect(collection.burn(alice)).to.be.rejectedWith(/common\.CantDestroyNotEmptyCollection/);
- });
-});
js-packages/tests/src/enableDisableTransfer.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/enableDisableTransfer.test.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-
-describe('Enable/Disable Transfers', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('User can transfer token with enabled transfer flag', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- limits: {
- transfersEnabled: true,
- },
- });
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- await token.transfer(alice, {Substrate: bob.address});
- expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
- });
-
- itSub('User can\'n transfer token with disabled transfer flag', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- limits: {
- transfersEnabled: false,
- },
- });
- const token = await collection.mintToken(alice, {Substrate: alice.address});
- await expect(token.transfer(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.TransferNotAllowed/);
- });
-});
-
-describe('Negative Enable/Disable Transfers', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('Non-owner cannot change transfer flag', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test',
- description: 'test',
- tokenPrefix: 'test',
- limits: {
- transfersEnabled: true,
- },
- });
-
- await expect(collection.setLimits(bob, {transfersEnabled: false})).to.be.rejectedWith(/common\.NoPermission/);
- });
-});
js-packages/tests/src/eth/abi/collectionHelpers.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/collectionHelpers.json
+++ /dev/null
@@ -1,267 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "collectionId",
- "type": "address"
- }
- ],
- "name": "CollectionChanged",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "collectionId",
- "type": "address"
- }
- ],
- "name": "CollectionCreated",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "collectionId",
- "type": "address"
- }
- ],
- "name": "CollectionDestroyed",
- "type": "event"
- },
- {
- "inputs": [
- { "internalType": "uint32", "name": "collectionId", "type": "uint32" }
- ],
- "name": "collectionAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionCreationFee",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "collectionAddress",
- "type": "address"
- }
- ],
- "name": "collectionId",
- "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "string", "name": "name", "type": "string" },
- { "internalType": "string", "name": "description", "type": "string" },
- {
- "internalType": "string",
- "name": "token_prefix",
- "type": "string"
- },
- {
- "internalType": "enum CollectionMode",
- "name": "mode",
- "type": "uint8"
- },
- { "internalType": "uint8", "name": "decimals", "type": "uint8" },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- {
- "components": [
- {
- "internalType": "enum TokenPermissionField",
- "name": "code",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct PropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct TokenPropertyPermission[]",
- "name": "token_property_permissions",
- "type": "tuple[]"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress[]",
- "name": "admin_list",
- "type": "tuple[]"
- },
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "nesting_settings",
- "type": "tuple"
- },
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct CollectionLimitValue[]",
- "name": "limits",
- "type": "tuple[]"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "pending_sponsor",
- "type": "tuple"
- },
- {
- "internalType": "CollectionFlags",
- "name": "flags",
- "type": "uint8"
- }
- ],
- "internalType": "struct CreateCollectionData",
- "name": "data",
- "type": "tuple"
- }
- ],
- "name": "createCollection",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "payable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string", "name": "name", "type": "string" },
- { "internalType": "uint8", "name": "decimals", "type": "uint8" },
- { "internalType": "string", "name": "description", "type": "string" },
- { "internalType": "string", "name": "tokenPrefix", "type": "string" }
- ],
- "name": "createFTCollection",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "payable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string", "name": "name", "type": "string" },
- { "internalType": "string", "name": "description", "type": "string" },
- { "internalType": "string", "name": "tokenPrefix", "type": "string" }
- ],
- "name": "createNFTCollection",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "payable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string", "name": "name", "type": "string" },
- { "internalType": "string", "name": "description", "type": "string" },
- { "internalType": "string", "name": "tokenPrefix", "type": "string" }
- ],
- "name": "createRFTCollection",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "payable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "collectionAddress",
- "type": "address"
- }
- ],
- "name": "destroyCollection",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "collectionAddress",
- "type": "address"
- }
- ],
- "name": "isCollectionExist",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "collection", "type": "address" },
- { "internalType": "string", "name": "baseUri", "type": "string" }
- ],
- "name": "makeCollectionERC721MetadataCompatible",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/contractHelpers.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/contractHelpers.json
+++ /dev/null
@@ -1,326 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "ContractSponsorRemoved",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "address",
- "name": "sponsor",
- "type": "address"
- }
- ],
- "name": "ContractSponsorSet",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "address",
- "name": "sponsor",
- "type": "address"
- }
- ],
- "name": "ContractSponsorshipConfirmed",
- "type": "event"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "allowed",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "allowlistEnabled",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "confirmSponsorship",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "contractOwner",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "hasPendingSponsor",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "hasSponsor",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "removeSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "selfSponsoredEnable",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- { "internalType": "address", "name": "sponsor", "type": "address" }
- ],
- "name": "setSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- { "internalType": "uint256", "name": "feeLimit", "type": "uint256" }
- ],
- "name": "setSponsoringFeeLimit",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- {
- "internalType": "enum SponsoringModeT",
- "name": "mode",
- "type": "uint8"
- }
- ],
- "name": "setSponsoringMode",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }
- ],
- "name": "setSponsoringRateLimit",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "sponsor",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct OptionCrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "sponsoringEnabled",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "sponsoringFeeLimit",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- }
- ],
- "name": "sponsoringRateLimit",
- "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- { "internalType": "address", "name": "user", "type": "address" },
- { "internalType": "bool", "name": "isAllowed", "type": "bool" }
- ],
- "name": "toggleAllowed",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "internalType": "address",
- "name": "contractAddress",
- "type": "address"
- },
- { "internalType": "bool", "name": "enabled", "type": "bool" }
- ],
- "name": "toggleAllowlist",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/fungible.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/fungible.json
+++ /dev/null
@@ -1,722 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "spender",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Approval",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "from",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "to",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Transfer",
- "type": "event"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "newAdmin",
- "type": "tuple"
- }
- ],
- "name": "addCollectionAdminCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "addToCollectionAllowListCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "address", "name": "spender", "type": "address" }
- ],
- "name": "allowance",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "spender",
- "type": "tuple"
- }
- ],
- "name": "allowanceCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "allowlistedCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "spender", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "approve",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "spender",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "approveCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" }
- ],
- "name": "balanceOf",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- }
- ],
- "name": "balanceOfCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "burnFromCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "newOwner",
- "type": "tuple"
- }
- ],
- "name": "changeCollectionOwnerCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionAdmins",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionHelperAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionLimits",
- "outputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct OptionUint256",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct CollectionLimit[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNesting",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionOwner",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "collectionProperties",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
- "name": "collectionProperty",
- "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionSponsor",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "confirmCollectionSponsorship",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "contractAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "decimals",
- "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "deleteCollectionProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "description",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "hasCollectionPendingSponsor",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "isOwnerOrAdminCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "mint",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "internalType": "struct AmountForAddress[]",
- "name": "amounts",
- "type": "tuple[]"
- }
- ],
- "name": "mintBulk",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "mintCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "name",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "admin",
- "type": "tuple"
- }
- ],
- "name": "removeCollectionAdminCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "removeCollectionSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "removeFromCollectionAllowListCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
- ],
- "name": "setCollectionAccess",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct OptionUint256",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct CollectionLimit",
- "name": "limit",
- "type": "tuple"
- }
- ],
- "name": "setCollectionLimit",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
- "name": "setCollectionMintMode",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "collectionNestingAndPermissions",
- "type": "tuple"
- }
- ],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "setCollectionProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "sponsor",
- "type": "tuple"
- }
- ],
- "name": "setCollectionSponsorCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "symbol",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "totalSupply",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transfer",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferFrom",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferFromCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "uniqueCollectionType",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/fungibleDeprecated.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/fungibleDeprecated.json
+++ /dev/null
@@ -1,151 +0,0 @@
-[
- {
- "inputs": [
- { "internalType": "address", "name": "newAdmin", "type": "address" }
- ],
- "name": "addCollectionAdmin",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "addToCollectionAllowList",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "burnFrom",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "newOwner", "type": "address" }
- ],
- "name": "changeCollectionOwner",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
- "name": "deleteCollectionProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "isOwnerOrAdmin",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "admin", "type": "address" }
- ],
- "name": "removeCollectionAdmin",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "removeFromCollectionAllowList",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "name": "setCollectionProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "sponsor", "type": "address" }
- ],
- "name": "setCollectionSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNestingPermissions",
- "outputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionPermissionField",
- "name": "field",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct CollectionNestingPermission[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNestingRestrictedCollectionIds",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
- ],
- "internalType": "struct CollectionNesting",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bool", "name": "enable", "type": "bool" },
- {
- "internalType": "address[]",
- "name": "collections",
- "type": "address[]"
- }
- ],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/nativeFungible.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/nativeFungible.json
+++ /dev/null
@@ -1,201 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "spender",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Approval",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "from",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "to",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Transfer",
- "type": "event"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "address", "name": "spender", "type": "address" }
- ],
- "name": "allowance",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "spender", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "approve",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" }
- ],
- "name": "balanceOf",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- }
- ],
- "name": "balanceOfCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "decimals",
- "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "name",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "symbol",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "totalSupply",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transfer",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferFrom",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferFromCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/nonFungible.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/nonFungible.json
+++ /dev/null
@@ -1,988 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "approved",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "tokenId",
- "type": "uint256"
- }
- ],
- "name": "Approval",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "operator",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "bool",
- "name": "approved",
- "type": "bool"
- }
- ],
- "name": "ApprovalForAll",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "tokenId",
- "type": "uint256"
- }
- ],
- "name": "TokenChanged",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "from",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "to",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "tokenId",
- "type": "uint256"
- }
- ],
- "name": "Transfer",
- "type": "event"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "newAdmin",
- "type": "tuple"
- }
- ],
- "name": "addCollectionAdminCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "addToCollectionAllowListCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "allowlistedCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "approved", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "approve",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "approved",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "approveCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" }
- ],
- "name": "balanceOf",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- }
- ],
- "name": "balanceOfCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "burn",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "burnFromCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "newOwner",
- "type": "tuple"
- }
- ],
- "name": "changeCollectionOwnerCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionAdmins",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionHelperAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionLimits",
- "outputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct OptionUint256",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct CollectionLimit[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNesting",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionOwner",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "collectionProperties",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
- "name": "collectionProperty",
- "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionSponsor",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "confirmCollectionSponsorship",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "contractAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "deleteCollectionProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "deleteProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "description",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "getApproved",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "hasCollectionPendingSponsor",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "address", "name": "operator", "type": "address" }
- ],
- "name": "isApprovedForAll",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "isOwnerOrAdminCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
- "name": "mint",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct MintTokenData[]",
- "name": "data",
- "type": "tuple[]"
- }
- ],
- "name": "mintBulkCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "mintCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "string", "name": "tokenUri", "type": "string" }
- ],
- "name": "mintWithTokenURI",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "name",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "nextTokenId",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "ownerOf",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "ownerOfCross",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "properties",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string", "name": "key", "type": "string" }
- ],
- "name": "property",
- "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "admin",
- "type": "tuple"
- }
- ],
- "name": "removeCollectionAdminCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "removeCollectionSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "removeFromCollectionAllowListCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "safeTransferFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "bytes", "name": "data", "type": "bytes" }
- ],
- "name": "safeTransferFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "operator", "type": "address" },
- { "internalType": "bool", "name": "approved", "type": "bool" }
- ],
- "name": "setApprovalForAll",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
- ],
- "name": "setCollectionAccess",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct OptionUint256",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct CollectionLimit",
- "name": "limit",
- "type": "tuple"
- }
- ],
- "name": "setCollectionLimit",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
- "name": "setCollectionMintMode",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "collectionNestingAndPermissions",
- "type": "tuple"
- }
- ],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "setCollectionProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "sponsor",
- "type": "tuple"
- }
- ],
- "name": "setCollectionSponsorCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "setProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- {
- "components": [
- {
- "internalType": "enum TokenPermissionField",
- "name": "code",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct PropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct TokenPropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "name": "setTokenPropertyPermissions",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "symbol",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "index", "type": "uint256" }
- ],
- "name": "tokenByIndex",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "uint256", "name": "index", "type": "uint256" }
- ],
- "name": "tokenOfOwnerByIndex",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "tokenPropertyPermissions",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- {
- "components": [
- {
- "internalType": "enum TokenPermissionField",
- "name": "code",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct PropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct TokenPropertyPermission[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "tokenURI",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "totalSupply",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transfer",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transferCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transferFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transferFromCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "uniqueCollectionType",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/nonFungibleDeprecated.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/nonFungibleDeprecated.json
+++ /dev/null
@@ -1,172 +0,0 @@
-[
- {
- "inputs": [
- { "internalType": "address", "name": "newAdmin", "type": "address" }
- ],
- "name": "addCollectionAdmin",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "addToCollectionAllowList",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "burnFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
- "name": "deleteCollectionProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "isOwnerOrAdmin",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "admin", "type": "address" }
- ],
- "name": "removeCollectionAdmin",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "removeFromCollectionAllowList",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "name": "setCollectionProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "sponsor", "type": "address" }
- ],
- "name": "setCollectionSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "name": "setProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "newOwner", "type": "address" }
- ],
- "name": "changeCollectionOwner",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string", "name": "key", "type": "string" }
- ],
- "name": "deleteProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNestingPermissions",
- "outputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionPermissionField",
- "name": "field",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct CollectionNestingPermission[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNestingRestrictedCollectionIds",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
- ],
- "internalType": "struct CollectionNesting",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bool", "name": "enable", "type": "bool" },
- {
- "internalType": "address[]",
- "name": "collections",
- "type": "address[]"
- }
- ],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/reFungible.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/reFungible.json
+++ /dev/null
@@ -1,995 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "approved",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "tokenId",
- "type": "uint256"
- }
- ],
- "name": "Approval",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "operator",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "bool",
- "name": "approved",
- "type": "bool"
- }
- ],
- "name": "ApprovalForAll",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "tokenId",
- "type": "uint256"
- }
- ],
- "name": "TokenChanged",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "from",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "to",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "uint256",
- "name": "tokenId",
- "type": "uint256"
- }
- ],
- "name": "Transfer",
- "type": "event"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "newAdmin",
- "type": "tuple"
- }
- ],
- "name": "addCollectionAdminCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "addToCollectionAllowListCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "allowlistedCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "approved", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "approve",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" }
- ],
- "name": "balanceOf",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- }
- ],
- "name": "balanceOfCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "burn",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "burnFromCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "newOwner",
- "type": "tuple"
- }
- ],
- "name": "changeCollectionOwnerCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionAdmins",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionHelperAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionLimits",
- "outputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct OptionUint256",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct CollectionLimit[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNesting",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionOwner",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "collectionProperties",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
- "name": "collectionProperty",
- "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionSponsor",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "confirmCollectionSponsorship",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "contractAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "deleteCollectionProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "deleteProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "description",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "getApproved",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "hasCollectionPendingSponsor",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "address", "name": "operator", "type": "address" }
- ],
- "name": "isApprovedForAll",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "isOwnerOrAdminCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
- "name": "mint",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- {
- "components": [
- {
- "components": [
- {
- "internalType": "address",
- "name": "eth",
- "type": "address"
- },
- {
- "internalType": "uint256",
- "name": "sub",
- "type": "uint256"
- }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- },
- { "internalType": "uint128", "name": "pieces", "type": "uint128" }
- ],
- "internalType": "struct OwnerPieces[]",
- "name": "owners",
- "type": "tuple[]"
- },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct MintTokenData[]",
- "name": "tokenProperties",
- "type": "tuple[]"
- }
- ],
- "name": "mintBulkCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "mintCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "string", "name": "tokenUri", "type": "string" }
- ],
- "name": "mintWithTokenURI",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "name",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "nextTokenId",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "ownerOf",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "ownerOfCross",
- "outputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string[]", "name": "keys", "type": "string[]" }
- ],
- "name": "properties",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string", "name": "key", "type": "string" }
- ],
- "name": "property",
- "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "admin",
- "type": "tuple"
- }
- ],
- "name": "removeCollectionAdminCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "removeCollectionSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "user",
- "type": "tuple"
- }
- ],
- "name": "removeFromCollectionAllowListCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "safeTransferFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "bytes", "name": "data", "type": "bytes" }
- ],
- "name": "safeTransferFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "operator", "type": "address" },
- { "internalType": "bool", "name": "approved", "type": "bool" }
- ],
- "name": "setApprovalForAll",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
- ],
- "name": "setCollectionAccess",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionLimitField",
- "name": "field",
- "type": "uint8"
- },
- {
- "components": [
- { "internalType": "bool", "name": "status", "type": "bool" },
- { "internalType": "uint256", "name": "value", "type": "uint256" }
- ],
- "internalType": "struct OptionUint256",
- "name": "value",
- "type": "tuple"
- }
- ],
- "internalType": "struct CollectionLimit",
- "name": "limit",
- "type": "tuple"
- }
- ],
- "name": "setCollectionLimit",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
- "name": "setCollectionMintMode",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- {
- "internalType": "bool",
- "name": "collection_admin",
- "type": "bool"
- },
- {
- "internalType": "address[]",
- "name": "restricted",
- "type": "address[]"
- }
- ],
- "internalType": "struct CollectionNestingAndPermission",
- "name": "collectionNestingAndPermissions",
- "type": "tuple"
- }
- ],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "setCollectionProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "sponsor",
- "type": "tuple"
- }
- ],
- "name": "setCollectionSponsorCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "internalType": "struct Property[]",
- "name": "properties",
- "type": "tuple[]"
- }
- ],
- "name": "setProperties",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- {
- "components": [
- {
- "internalType": "enum TokenPermissionField",
- "name": "code",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct PropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct TokenPropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "name": "setTokenPropertyPermissions",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "symbol",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "index", "type": "uint256" }
- ],
- "name": "tokenByIndex",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "token", "type": "uint256" }
- ],
- "name": "tokenContractAddress",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "uint256", "name": "index", "type": "uint256" }
- ],
- "name": "tokenOfOwnerByIndex",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "tokenPropertyPermissions",
- "outputs": [
- {
- "components": [
- { "internalType": "string", "name": "key", "type": "string" },
- {
- "components": [
- {
- "internalType": "enum TokenPermissionField",
- "name": "code",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct PropertyPermission[]",
- "name": "permissions",
- "type": "tuple[]"
- }
- ],
- "internalType": "struct TokenPropertyPermission[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "tokenURI",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "totalSupply",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transfer",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transferCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transferFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "transferFromCross",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "uniqueCollectionType",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/reFungibleDeprecated.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/reFungibleDeprecated.json
+++ /dev/null
@@ -1,200 +0,0 @@
-[
- {
- "inputs": [
- { "internalType": "address", "name": "newAdmin", "type": "address" }
- ],
- "name": "addCollectionAdmin",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "addToCollectionAllowList",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
- ],
- "name": "burnFrom",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
- "name": "deleteCollectionProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "isOwnerOrAdmin",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "admin", "type": "address" }
- ],
- "name": "removeCollectionAdmin",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "user", "type": "address" }
- ],
- "name": "removeFromCollectionAllowList",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "name": "setCollectionProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "sponsor", "type": "address" }
- ],
- "name": "setCollectionSponsor",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string", "name": "key", "type": "string" },
- { "internalType": "bytes", "name": "value", "type": "bytes" }
- ],
- "name": "setProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "newOwner", "type": "address" }
- ],
- "name": "changeCollectionOwner",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
- { "internalType": "string", "name": "key", "type": "string" }
- ],
- "name": "deleteProperty",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
- ],
- "name": "mintBulk",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- {
- "components": [
- { "internalType": "uint256", "name": "field_0", "type": "uint256" },
- { "internalType": "string", "name": "field_1", "type": "string" }
- ],
- "internalType": "struct Tuple0[]",
- "name": "tokens",
- "type": "tuple[]"
- }
- ],
- "name": "mintBulkWithTokenURI",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNestingPermissions",
- "outputs": [
- {
- "components": [
- {
- "internalType": "enum CollectionPermissionField",
- "name": "field",
- "type": "uint8"
- },
- { "internalType": "bool", "name": "value", "type": "bool" }
- ],
- "internalType": "struct CollectionNestingPermission[]",
- "name": "",
- "type": "tuple[]"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "collectionNestingRestrictedCollectionIds",
- "outputs": [
- {
- "components": [
- { "internalType": "bool", "name": "token_owner", "type": "bool" },
- { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
- ],
- "internalType": "struct CollectionNesting",
- "name": "",
- "type": "tuple"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bool", "name": "enable", "type": "bool" },
- {
- "internalType": "address[]",
- "name": "collections",
- "type": "address[]"
- }
- ],
- "name": "setCollectionNesting",
- "outputs": [],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/reFungibleToken.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/reFungibleToken.json
+++ /dev/null
@@ -1,286 +0,0 @@
-[
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "owner",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "spender",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Approval",
- "type": "event"
- },
- {
- "anonymous": false,
- "inputs": [
- {
- "indexed": true,
- "internalType": "address",
- "name": "from",
- "type": "address"
- },
- {
- "indexed": true,
- "internalType": "address",
- "name": "to",
- "type": "address"
- },
- {
- "indexed": false,
- "internalType": "uint256",
- "name": "value",
- "type": "uint256"
- }
- ],
- "name": "Transfer",
- "type": "event"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" },
- { "internalType": "address", "name": "spender", "type": "address" }
- ],
- "name": "allowance",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "spender",
- "type": "tuple"
- }
- ],
- "name": "allowanceCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "spender", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "approve",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "spender",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "approveCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "owner", "type": "address" }
- ],
- "name": "balanceOf",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "owner",
- "type": "tuple"
- }
- ],
- "name": "balanceOfCross",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "burnFromCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "decimals",
- "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "name",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "parentToken",
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "parentTokenId",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "repartition",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
- ],
- "name": "supportsInterface",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "symbol",
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "totalSupply",
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transfer",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "address", "name": "to", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferFrom",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "from",
- "type": "tuple"
- },
- {
- "components": [
- { "internalType": "address", "name": "eth", "type": "address" },
- { "internalType": "uint256", "name": "sub", "type": "uint256" }
- ],
- "internalType": "struct CrossAddress",
- "name": "to",
- "type": "tuple"
- },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "transferFromCross",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/abi/reFungibleTokenDeprecated.jsondiffbeforeafterboth--- a/js-packages/tests/src/eth/abi/reFungibleTokenDeprecated.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "inputs": [
- { "internalType": "address", "name": "from", "type": "address" },
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
- ],
- "name": "burnFrom",
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
- "stateMutability": "nonpayable",
- "type": "function"
- }
-]
js-packages/tests/src/eth/allowlist.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/allowlist.test.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets} from '../util/index.js';
-import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util/index.js';
-import {CreateCollectionData} from './util/playgrounds/types.js';
-
-describe('EVM contract allowlist', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Contract allowlist can be toggled', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const flipper = await helper.eth.deployFlipper(owner);
- const helpers = helper.ethNativeContract.contractHelpers(owner);
-
- // Any user is allowed by default
- expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;
-
- // Enable
- await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
- expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.true;
-
- // Disable
- await helpers.methods.toggleAllowlist(flipper.options.address, false).send({from: owner});
- expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;
- });
-
- itEth('Non-allowlisted user can\'t call contract with allowlist enabled', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const flipper = await helper.eth.deployFlipper(owner);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
-
- // User can flip with allowlist disabled
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- // Tx will be reverted if user is not in allowlist
- await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
- await expect(flipper.methods.flip().send({from: caller})).to.rejected;
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- // Adding caller to allowlist will make contract callable again
- await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.false;
- });
-});
-
-describe('EVM collection allowlist', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- // Soft-deprecated
- itEth('Collection allowlist can be added and removed by [eth] address', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const user = helper.eth.createAccount();
- const crossUser = helper.ethCrossAccount.fromAddress(user);
-
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
- await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
- expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;
-
- await collectionEvm.methods.removeFromCollectionAllowList(user).send({from: owner});
- expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
- });
-
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, requiredPallets: []},
- ].map(testCase =>
- itEth.ifWithPallets(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {
- const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
- const [userSub] = await helper.arrange.createAccounts([10n], donor);
- const userEth = await helper.eth.createAccountWithBalance(donor);
- const mintParams = testCase.mode === 'ft' ? [userEth, 100] : [userEth];
-
- const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
- const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);
- const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);
- const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
-
- // Can addToCollectionAllowListCross:
- expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
- await collectionEvm.methods.addToCollectionAllowListCross(userCrossSub).send({from: owner});
- await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});
- await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});
-
- // Accounts are in allowed list:
- expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;
- expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;
- expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;
- expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;
-
- await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #1
- await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #2
- await collectionEvm.methods.setCollectionAccess(SponsoringMode.Allowlisted).send({from: owner});
-
- // allowlisted account can transfer and transferCross from eth:
- await collectionEvm.methods.transfer(owner, 1).send({from: userEth});
- await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});
-
- if(testCase.mode === 'ft') {
- expect(await helper.ft.getBalance(collectionId, {Ethereum: owner})).to.eq(1n);
- expect(await helper.ft.getBalance(collectionId, {Substrate: userSub.address})).to.eq(2n);
- } else {
- expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});
- expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});
- }
-
- // allowlisted cross substrate accounts can transfer from Substrate:
- testCase.mode === 'ft'
- ? await helper.ft.transfer(userSub, collectionId, {Ethereum: userEth}, 2n)
- : await helper.collection.transferToken(userSub, collectionId, 2, {Ethereum: userEth});
-
- // can removeFromCollectionAllowListCross:
- await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});
- await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossEth).send({from: owner});
- expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
- expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;
- expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.false;
- expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;
-
- // cannot transfer anymore
- await collectionEvm.methods.mint(...mintParams).send({from: owner});
- await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);
- }));
-
- [
- // cross-methods
- {mode: 'nft' as const, cross: true, requiredPallets: []},
- {mode: 'rft' as const, cross: true, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, cross: true, requiredPallets: []},
- // soft-deprecated
- {mode: 'nft' as const, cross: false, requiredPallets: []},
- {mode: 'rft' as const, cross: false, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, cross: false, requiredPallets: []},
- ].map(testCase =>
- itEth.ifWithPallets(`Non-owner cannot add or remove from collection allowlist ${testCase.cross ? 'cross ' : ''}${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {
- // Select methods:
- const addToAllowList = testCase.cross ? 'addToCollectionAllowListCross' : 'addToCollectionAllowList';
- const removeFromAllowList = testCase.cross ? 'removeFromCollectionAllowListCross' : 'removeFromCollectionAllowList';
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const notOwner = await helper.eth.createAccountWithBalance(donor);
- const userSub = donor;
- const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);
- const userEth = helper.eth.createAccount();
- const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);
-
- const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);
-
- expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
- expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;
-
- // 1. notOwner cannot add to allow list:
- // 1.1 plain ethereum or cross address:
- await expect(collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- // 1.2 cross-substrate address:
- if(testCase.cross)
- await expect(collectionEvm.methods[addToAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');
-
- // 2. owner can add to allow list:
- // 2.1 plain ethereum or cross address:
- await collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).send({from: owner});
- // 2.2 cross-substrate address:
- if(testCase.cross) {
- await collectionEvm.methods[addToAllowList](userCrossSub).send({from: owner});
- expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;
- }
- expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;
-
- // 3. notOwner cannot remove from allow list:
- // 3.1 plain ethereum or cross address:
- await expect(collectionEvm.methods[removeFromAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- // 3.2 cross-substrate address:
- if(testCase.cross)
- await expect(collectionEvm.methods[removeFromAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- }));
-});
js-packages/tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/CollectionHelpers.sol
+++ /dev/null
@@ -1,233 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface CollectionHelpersEvents {
- event CollectionCreated(address indexed owner, address indexed collectionId);
- event CollectionDestroyed(address indexed collectionId);
- event CollectionChanged(address indexed collectionId);
-}
-
-/// @title Contract, which allows users to operate with collections
-/// @dev the ERC-165 identifier for this interface is 0x94e5af0d
-interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
- /// Create a collection
- /// @return address Address of the newly created collection
- /// @dev EVM selector for this function is: 0x72b5bea7,
- /// or in textual repr: createCollection((string,string,string,uint8,uint8,(string,bytes)[],(string,(uint8,bool)[])[],(address,uint256)[],(bool,bool,address[]),(uint8,uint256)[],(address,uint256),uint8))
- function createCollection(CreateCollectionData memory data) external payable returns (address);
-
- /// Create an NFT collection
- /// @param name Name of the collection
- /// @param description Informative description of the collection
- /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
- /// @return address Address of the newly created collection
- /// @dev EVM selector for this function is: 0x844af658,
- /// or in textual repr: createNFTCollection(string,string,string)
- function createNFTCollection(
- string memory name,
- string memory description,
- string memory tokenPrefix
- ) external payable returns (address);
-
- // /// Create an NFT collection
- // /// @param name Name of the collection
- // /// @param description Informative description of the collection
- // /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
- // /// @return address Address of the newly created collection
- // /// @dev EVM selector for this function is: 0xe34a6844,
- // /// or in textual repr: createNonfungibleCollection(string,string,string)
- // function createNonfungibleCollection(string memory name, string memory description, string memory tokenPrefix) external payable returns (address);
-
- /// @dev EVM selector for this function is: 0xab173450,
- /// or in textual repr: createRFTCollection(string,string,string)
- function createRFTCollection(
- string memory name,
- string memory description,
- string memory tokenPrefix
- ) external payable returns (address);
-
- /// @dev EVM selector for this function is: 0x7335b79f,
- /// or in textual repr: createFTCollection(string,uint8,string,string)
- function createFTCollection(
- string memory name,
- uint8 decimals,
- string memory description,
- string memory tokenPrefix
- ) external payable returns (address);
-
- /// @dev EVM selector for this function is: 0x85624258,
- /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string)
- function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external;
-
- /// @dev EVM selector for this function is: 0x564e321f,
- /// or in textual repr: destroyCollection(address)
- function destroyCollection(address collectionAddress) external;
-
- /// Check if a collection exists
- /// @param collectionAddress Address of the collection in question
- /// @return bool Does the collection exist?
- /// @dev EVM selector for this function is: 0xc3de1494,
- /// or in textual repr: isCollectionExist(address)
- function isCollectionExist(address collectionAddress) external view returns (bool);
-
- /// @dev EVM selector for this function is: 0xd23a7ab1,
- /// or in textual repr: collectionCreationFee()
- function collectionCreationFee() external view returns (uint256);
-
- /// Returns address of a collection.
- /// @param collectionId - CollectionId of the collection
- /// @return eth mirror address of the collection
- /// @dev EVM selector for this function is: 0x2e716683,
- /// or in textual repr: collectionAddress(uint32)
- function collectionAddress(uint32 collectionId) external view returns (address);
-
- /// Returns collectionId of a collection.
- /// @param collectionAddress - Eth address of the collection
- /// @return collectionId of the collection
- /// @dev EVM selector for this function is: 0xb5cb7498,
- /// or in textual repr: collectionId(address)
- function collectionId(address collectionAddress) external view returns (uint32);
-}
-
-/// Collection properties
-struct CreateCollectionData {
- /// Collection name
- string name;
- /// Collection description
- string description;
- /// Token prefix
- string token_prefix;
- /// Token type (NFT, FT or RFT)
- CollectionMode mode;
- /// Fungible token precision
- uint8 decimals;
- /// Custom Properties
- Property[] properties;
- /// Permissions for token properties
- TokenPropertyPermission[] token_property_permissions;
- /// Collection admins
- CrossAddress[] admin_list;
- /// Nesting settings
- CollectionNestingAndPermission nesting_settings;
- /// Collection limits
- CollectionLimitValue[] limits;
- /// Collection sponsor
- CrossAddress pending_sponsor;
- /// Extra collection flags
- CollectionFlags flags;
-}
-
-type CollectionFlags is uint8;
-
-library CollectionFlagsLib {
- /// Tokens in foreign collections can be transferred, but not burnt
- CollectionFlags constant foreignField = CollectionFlags.wrap(128);
- /// Supports ERC721Metadata
- CollectionFlags constant erc721metadataField = CollectionFlags.wrap(64);
- /// External collections can't be managed using `unique` api
- CollectionFlags constant externalField = CollectionFlags.wrap(1);
-
- /// Reserved flags
- function reservedField(uint8 value) public pure returns (CollectionFlags) {
- require(value < 1 << 5, "out of bound value");
- return CollectionFlags.wrap(value << 1);
- }
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimitValue {
- CollectionLimitField field;
- uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
- /// How many tokens can a user have on one account.
- AccountTokenOwnership,
- /// How many bytes of data are available for sponsorship.
- SponsoredDataSize,
- /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
- SponsoredDataRateLimit,
- /// How many tokens can be mined into this collection.
- TokenLimit,
- /// Timeouts for transfer sponsoring.
- SponsorTransferTimeout,
- /// Timeout for sponsoring an approval in passed blocks.
- SponsorApproveTimeout,
- /// Whether the collection owner of the collection can send tokens (which belong to other users).
- OwnerCanTransfer,
- /// Can the collection owner burn other people's tokens.
- OwnerCanDestroy,
- /// Is it possible to send tokens from this collection between users.
- TransferEnabled
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
- /// Owner of token can nest tokens under it.
- bool token_owner;
- /// Admin of token collection can nest tokens under token.
- bool collection_admin;
- /// If set - only tokens from specified collections can be nested.
- address[] restricted;
-}
-
-/// Ethereum representation of Token Property Permissions.
-struct TokenPropertyPermission {
- /// Token property key.
- string key;
- /// Token property permissions.
- PropertyPermission[] permissions;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
-struct PropertyPermission {
- /// TokenPermission field.
- TokenPermissionField code;
- /// TokenPermission value.
- bool value;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
-enum TokenPermissionField {
- /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
- Mutable,
- /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
- TokenOwner,
- /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
- CollectionAdmin
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
- string key;
- bytes value;
-}
-
-/// Type of tokens in collection
-enum CollectionMode {
- /// Nonfungible
- Nonfungible,
- /// Fungible
- Fungible,
- /// Refungible
- Refungible
-}
js-packages/tests/src/eth/api/ContractHelpers.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/ContractHelpers.sol
+++ /dev/null
@@ -1,196 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface ContractHelpersEvents {
- event ContractSponsorSet(address indexed contractAddress, address sponsor);
- event ContractSponsorshipConfirmed(address indexed contractAddress, address sponsor);
- event ContractSponsorRemoved(address indexed contractAddress);
-}
-
-/// @title Magic contract, which allows users to reconfigure other contracts
-/// @dev the ERC-165 identifier for this interface is 0x30afad04
-interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
- /// Get user, which deployed specified contract
- /// @dev May return zero address in case if contract is deployed
- /// using uniquenetwork evm-migration pallet, or using other terms not
- /// intended by pallet-evm
- /// @dev Returns zero address if contract does not exists
- /// @param contractAddress Contract to get owner of
- /// @return address Owner of contract
- /// @dev EVM selector for this function is: 0x5152b14c,
- /// or in textual repr: contractOwner(address)
- function contractOwner(address contractAddress) external view returns (address);
-
- /// Set sponsor.
- /// @param contractAddress Contract for which a sponsor is being established.
- /// @param sponsor User address who set as pending sponsor.
- /// @dev EVM selector for this function is: 0xf01fba93,
- /// or in textual repr: setSponsor(address,address)
- function setSponsor(address contractAddress, address sponsor) external;
-
- /// Set contract as self sponsored.
- ///
- /// @param contractAddress Contract for which a self sponsoring is being enabled.
- /// @dev EVM selector for this function is: 0x89f7d9ae,
- /// or in textual repr: selfSponsoredEnable(address)
- function selfSponsoredEnable(address contractAddress) external;
-
- /// Remove sponsor.
- ///
- /// @param contractAddress Contract for which a sponsorship is being removed.
- /// @dev EVM selector for this function is: 0xef784250,
- /// or in textual repr: removeSponsor(address)
- function removeSponsor(address contractAddress) external;
-
- /// Confirm sponsorship.
- ///
- /// @dev Caller must be same that set via [`setSponsor`].
- ///
- /// @param contractAddress Сontract for which need to confirm sponsorship.
- /// @dev EVM selector for this function is: 0xabc00001,
- /// or in textual repr: confirmSponsorship(address)
- function confirmSponsorship(address contractAddress) external;
-
- /// Get current sponsor.
- ///
- /// @param contractAddress The contract for which a sponsor is requested.
- /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
- /// @dev EVM selector for this function is: 0x766c4f37,
- /// or in textual repr: sponsor(address)
- function sponsor(address contractAddress) external view returns (OptionCrossAddress memory);
-
- /// Check tat contract has confirmed sponsor.
- ///
- /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
- /// @return **true** if contract has confirmed sponsor.
- /// @dev EVM selector for this function is: 0x97418603,
- /// or in textual repr: hasSponsor(address)
- function hasSponsor(address contractAddress) external view returns (bool);
-
- /// Check tat contract has pending sponsor.
- ///
- /// @param contractAddress The contract for which the presence of a pending sponsor is checked.
- /// @return **true** if contract has pending sponsor.
- /// @dev EVM selector for this function is: 0x39b9b242,
- /// or in textual repr: hasPendingSponsor(address)
- function hasPendingSponsor(address contractAddress) external view returns (bool);
-
- /// @dev EVM selector for this function is: 0x6027dc61,
- /// or in textual repr: sponsoringEnabled(address)
- function sponsoringEnabled(address contractAddress) external view returns (bool);
-
- /// @dev EVM selector for this function is: 0xfde8a560,
- /// or in textual repr: setSponsoringMode(address,uint8)
- function setSponsoringMode(address contractAddress, SponsoringModeT mode) external;
-
- /// Get current contract sponsoring rate limit
- /// @param contractAddress Contract to get sponsoring rate limit of
- /// @return uint32 Amount of blocks between two sponsored transactions
- /// @dev EVM selector for this function is: 0xf29694d8,
- /// or in textual repr: sponsoringRateLimit(address)
- function sponsoringRateLimit(address contractAddress) external view returns (uint32);
-
- /// Set contract sponsoring rate limit
- /// @dev Sponsoring rate limit - is a minimum amount of blocks that should
- /// pass between two sponsored transactions
- /// @param contractAddress Contract to change sponsoring rate limit of
- /// @param rateLimit Target rate limit
- /// @dev Only contract owner can change this setting
- /// @dev EVM selector for this function is: 0x77b6c908,
- /// or in textual repr: setSponsoringRateLimit(address,uint32)
- function setSponsoringRateLimit(address contractAddress, uint32 rateLimit) external;
-
- /// Set contract sponsoring fee limit
- /// @dev Sponsoring fee limit - is maximum fee that could be spent by
- /// single transaction
- /// @param contractAddress Contract to change sponsoring fee limit of
- /// @param feeLimit Fee limit
- /// @dev Only contract owner can change this setting
- /// @dev EVM selector for this function is: 0x03aed665,
- /// or in textual repr: setSponsoringFeeLimit(address,uint256)
- function setSponsoringFeeLimit(address contractAddress, uint256 feeLimit) external;
-
- /// Get current contract sponsoring fee limit
- /// @param contractAddress Contract to get sponsoring fee limit of
- /// @return uint256 Maximum amount of fee that could be spent by single
- /// transaction
- /// @dev EVM selector for this function is: 0x75b73606,
- /// or in textual repr: sponsoringFeeLimit(address)
- function sponsoringFeeLimit(address contractAddress) external view returns (uint256);
-
- /// Is specified user present in contract allow list
- /// @dev Contract owner always implicitly included
- /// @param contractAddress Contract to check allowlist of
- /// @param user User to check
- /// @return bool Is specified users exists in contract allowlist
- /// @dev EVM selector for this function is: 0x5c658165,
- /// or in textual repr: allowed(address,address)
- function allowed(address contractAddress, address user) external view returns (bool);
-
- /// Toggle user presence in contract allowlist
- /// @param contractAddress Contract to change allowlist of
- /// @param user Which user presence should be toggled
- /// @param isAllowed `true` if user should be allowed to be sponsored
- /// or call this contract, `false` otherwise
- /// @dev Only contract owner can change this setting
- /// @dev EVM selector for this function is: 0x4706cc1c,
- /// or in textual repr: toggleAllowed(address,address,bool)
- function toggleAllowed(
- address contractAddress,
- address user,
- bool isAllowed
- ) external;
-
- /// Is this contract has allowlist access enabled
- /// @dev Allowlist always can have users, and it is used for two purposes:
- /// in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
- /// in case of allowlist access enabled, only users from allowlist may call this contract
- /// @param contractAddress Contract to get allowlist access of
- /// @return bool Is specified contract has allowlist access enabled
- /// @dev EVM selector for this function is: 0xc772ef6c,
- /// or in textual repr: allowlistEnabled(address)
- function allowlistEnabled(address contractAddress) external view returns (bool);
-
- /// Toggle contract allowlist access
- /// @param contractAddress Contract to change allowlist access of
- /// @param enabled Should allowlist access to be enabled?
- /// @dev EVM selector for this function is: 0x36de20f5,
- /// or in textual repr: toggleAllowlist(address,bool)
- function toggleAllowlist(address contractAddress, bool enabled) external;
-}
-
-/// Available contract sponsoring modes
-enum SponsoringModeT {
- /// Sponsoring is disabled
- Disabled,
- /// Only users from allowlist will be sponsored
- Allowlisted,
- /// All users will be sponsored
- Generous
-}
-
-/// Optional value
-struct OptionCrossAddress {
- /// Shows the status of accessibility of value
- bool status;
- /// Actual value if `status` is true
- CrossAddress value;
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
js-packages/tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/UniqueFungible.sol
+++ /dev/null
@@ -1,510 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
-interface Collection is Dummy, ERC165 {
- // /// Set collection property.
- // ///
- // /// @param key Property key.
- // /// @param value Propery value.
- // /// @dev EVM selector for this function is: 0x2f073f66,
- // /// or in textual repr: setCollectionProperty(string,bytes)
- // function setCollectionProperty(string memory key, bytes memory value) external;
-
- /// Set collection properties.
- ///
- /// @param properties Vector of properties key/value pair.
- /// @dev EVM selector for this function is: 0x50b26b2a,
- /// or in textual repr: setCollectionProperties((string,bytes)[])
- function setCollectionProperties(Property[] memory properties) external;
-
- // /// Delete collection property.
- // ///
- // /// @param key Property key.
- // /// @dev EVM selector for this function is: 0x7b7debce,
- // /// or in textual repr: deleteCollectionProperty(string)
- // function deleteCollectionProperty(string memory key) external;
-
- /// Delete collection properties.
- ///
- /// @param keys Properties keys.
- /// @dev EVM selector for this function is: 0xee206ee3,
- /// or in textual repr: deleteCollectionProperties(string[])
- function deleteCollectionProperties(string[] memory keys) external;
-
- /// Get collection property.
- ///
- /// @dev Throws error if key not found.
- ///
- /// @param key Property key.
- /// @return bytes The property corresponding to the key.
- /// @dev EVM selector for this function is: 0xcf24fd6d,
- /// or in textual repr: collectionProperty(string)
- function collectionProperty(string memory key) external view returns (bytes memory);
-
- /// Get collection properties.
- ///
- /// @param keys Properties keys. Empty keys for all propertyes.
- /// @return Vector of properties key/value pairs.
- /// @dev EVM selector for this function is: 0x285fb8e6,
- /// or in textual repr: collectionProperties(string[])
- function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
- // /// Set the sponsor of the collection.
- // ///
- // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
- // ///
- // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
- // /// @dev EVM selector for this function is: 0x7623402e,
- // /// or in textual repr: setCollectionSponsor(address)
- // function setCollectionSponsor(address sponsor) external;
-
- /// Set the sponsor of the collection.
- ///
- /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
- ///
- /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
- /// @dev EVM selector for this function is: 0x84a1d5a8,
- /// or in textual repr: setCollectionSponsorCross((address,uint256))
- function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
- /// Whether there is a pending sponsor.
- /// @dev EVM selector for this function is: 0x058ac185,
- /// or in textual repr: hasCollectionPendingSponsor()
- function hasCollectionPendingSponsor() external view returns (bool);
-
- /// Collection sponsorship confirmation.
- ///
- /// @dev After setting the sponsor for the collection, it must be confirmed with this function.
- /// @dev EVM selector for this function is: 0x3c50e97a,
- /// or in textual repr: confirmCollectionSponsorship()
- function confirmCollectionSponsorship() external;
-
- /// Remove collection sponsor.
- /// @dev EVM selector for this function is: 0x6e0326a3,
- /// or in textual repr: removeCollectionSponsor()
- function removeCollectionSponsor() external;
-
- /// Get current sponsor.
- ///
- /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
- /// @dev EVM selector for this function is: 0x6ec0a9f1,
- /// or in textual repr: collectionSponsor()
- function collectionSponsor() external view returns (CrossAddress memory);
-
- /// Get current collection limits.
- ///
- /// @return Array of collection limits
- /// @dev EVM selector for this function is: 0xf63bc572,
- /// or in textual repr: collectionLimits()
- function collectionLimits() external view returns (CollectionLimit[] memory);
-
- /// Set limits for the collection.
- /// @dev Throws error if limit not found.
- /// @param limit Some limit.
- /// @dev EVM selector for this function is: 0x2316ee74,
- /// or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
- function setCollectionLimit(CollectionLimit memory limit) external;
-
- /// Get contract address.
- /// @dev EVM selector for this function is: 0xf6b4dfb4,
- /// or in textual repr: contractAddress()
- function contractAddress() external view returns (address);
-
- /// Add collection admin.
- /// @param newAdmin Cross account administrator address.
- /// @dev EVM selector for this function is: 0x859aa7d6,
- /// or in textual repr: addCollectionAdminCross((address,uint256))
- function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
- /// Remove collection admin.
- /// @param admin Cross account administrator address.
- /// @dev EVM selector for this function is: 0x6c0cd173,
- /// or in textual repr: removeCollectionAdminCross((address,uint256))
- function removeCollectionAdminCross(CrossAddress memory admin) external;
-
- // /// Add collection admin.
- // /// @param newAdmin Address of the added administrator.
- // /// @dev EVM selector for this function is: 0x92e462c7,
- // /// or in textual repr: addCollectionAdmin(address)
- // function addCollectionAdmin(address newAdmin) external;
-
- // /// Remove collection admin.
- // ///
- // /// @param admin Address of the removed administrator.
- // /// @dev EVM selector for this function is: 0xfafd7b42,
- // /// or in textual repr: removeCollectionAdmin(address)
- // function removeCollectionAdmin(address admin) external;
-
- /// @dev EVM selector for this function is: 0x0b9f3890,
- /// or in textual repr: setCollectionNesting((bool,bool,address[]))
- function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
-
- // /// Toggle accessibility of collection nesting.
- // ///
- // /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
- // /// @dev EVM selector for this function is: 0x112d4586,
- // /// or in textual repr: setCollectionNesting(bool)
- // function setCollectionNesting(bool enable) external;
-
- // /// Toggle accessibility of collection nesting.
- // ///
- // /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
- // /// @param collections Addresses of collections that will be available for nesting.
- // /// @dev EVM selector for this function is: 0x64872396,
- // /// or in textual repr: setCollectionNesting(bool,address[])
- // function setCollectionNesting(bool enable, address[] memory collections) external;
-
- /// @dev EVM selector for this function is: 0x92c660a8,
- /// or in textual repr: collectionNesting()
- function collectionNesting() external view returns (CollectionNestingAndPermission memory);
-
- // /// Returns nesting for a collection
- // /// @dev EVM selector for this function is: 0x22d25bfe,
- // /// or in textual repr: collectionNestingRestrictedCollectionIds()
- // function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
- // /// Returns permissions for a collection
- // /// @dev EVM selector for this function is: 0x5b2eaf4b,
- // /// or in textual repr: collectionNestingPermissions()
- // function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
- /// Set the collection access method.
- /// @param mode Access mode
- /// @dev EVM selector for this function is: 0x41835d4c,
- /// or in textual repr: setCollectionAccess(uint8)
- function setCollectionAccess(AccessMode mode) external;
-
- /// Checks that user allowed to operate with collection.
- ///
- /// @param user User address to check.
- /// @dev EVM selector for this function is: 0x91b6df49,
- /// or in textual repr: allowlistedCross((address,uint256))
- function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
- // /// Add the user to the allowed list.
- // ///
- // /// @param user Address of a trusted user.
- // /// @dev EVM selector for this function is: 0x67844fe6,
- // /// or in textual repr: addToCollectionAllowList(address)
- // function addToCollectionAllowList(address user) external;
-
- /// Add user to allowed list.
- ///
- /// @param user User cross account address.
- /// @dev EVM selector for this function is: 0xa0184a3a,
- /// or in textual repr: addToCollectionAllowListCross((address,uint256))
- function addToCollectionAllowListCross(CrossAddress memory user) external;
-
- // /// Remove the user from the allowed list.
- // ///
- // /// @param user Address of a removed user.
- // /// @dev EVM selector for this function is: 0x85c51acb,
- // /// or in textual repr: removeFromCollectionAllowList(address)
- // function removeFromCollectionAllowList(address user) external;
-
- /// Remove user from allowed list.
- ///
- /// @param user User cross account address.
- /// @dev EVM selector for this function is: 0x09ba452a,
- /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))
- function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
- /// Switch permission for minting.
- ///
- /// @param mode Enable if "true".
- /// @dev EVM selector for this function is: 0x00018e84,
- /// or in textual repr: setCollectionMintMode(bool)
- function setCollectionMintMode(bool mode) external;
-
- // /// Check that account is the owner or admin of the collection
- // ///
- // /// @param user account to verify
- // /// @return "true" if account is the owner or admin
- // /// @dev EVM selector for this function is: 0x9811b0c7,
- // /// or in textual repr: isOwnerOrAdmin(address)
- // function isOwnerOrAdmin(address user) external view returns (bool);
-
- /// Check that account is the owner or admin of the collection
- ///
- /// @param user User cross account to verify
- /// @return "true" if account is the owner or admin
- /// @dev EVM selector for this function is: 0x3e75a905,
- /// or in textual repr: isOwnerOrAdminCross((address,uint256))
- function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
- /// Returns collection type
- ///
- /// @return `Fungible` or `NFT` or `ReFungible`
- /// @dev EVM selector for this function is: 0xd34b55b8,
- /// or in textual repr: uniqueCollectionType()
- function uniqueCollectionType() external view returns (string memory);
-
- /// Get collection owner.
- ///
- /// @return Tuble with sponsor address and his substrate mirror.
- /// If address is canonical then substrate mirror is zero and vice versa.
- /// @dev EVM selector for this function is: 0xdf727d3b,
- /// or in textual repr: collectionOwner()
- function collectionOwner() external view returns (CrossAddress memory);
-
- // /// Changes collection owner to another account
- // ///
- // /// @dev Owner can be changed only by current owner
- // /// @param newOwner new owner account
- // /// @dev EVM selector for this function is: 0x4f53e226,
- // /// or in textual repr: changeCollectionOwner(address)
- // function changeCollectionOwner(address newOwner) external;
-
- /// Get collection administrators
- ///
- /// @return Vector of tuples with admins address and his substrate mirror.
- /// If address is canonical then substrate mirror is zero and vice versa.
- /// @dev EVM selector for this function is: 0x5813216b,
- /// or in textual repr: collectionAdmins()
- function collectionAdmins() external view returns (CrossAddress[] memory);
-
- /// Changes collection owner to another account
- ///
- /// @dev Owner can be changed only by current owner
- /// @param newOwner new owner cross account
- /// @dev EVM selector for this function is: 0x6496c497,
- /// or in textual repr: changeCollectionOwnerCross((address,uint256))
- function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
- /// Access grant for owner and admins. Used as default.
- Normal,
- /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
- AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
- CollectionPermissionField field;
- bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
- /// Owner of token can nest tokens under it.
- TokenOwner,
- /// Admin of token collection can nest tokens under token.
- CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
- bool token_owner;
- uint256[] ids;
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
- /// Owner of token can nest tokens under it.
- bool token_owner;
- /// Admin of token collection can nest tokens under token.
- bool collection_admin;
- /// If set - only tokens from specified collections can be nested.
- address[] restricted;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
- CollectionLimitField field;
- OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
- /// Shows the status of accessibility of value
- bool status;
- /// Actual value if `status` is true
- uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
- /// How many tokens can a user have on one account.
- AccountTokenOwnership,
- /// How many bytes of data are available for sponsorship.
- SponsoredDataSize,
- /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
- SponsoredDataRateLimit,
- /// How many tokens can be mined into this collection.
- TokenLimit,
- /// Timeouts for transfer sponsoring.
- SponsorTransferTimeout,
- /// Timeout for sponsoring an approval in passed blocks.
- SponsorApproveTimeout,
- /// Whether the collection owner of the collection can send tokens (which belong to other users).
- OwnerCanTransfer,
- /// Can the collection owner burn other people's tokens.
- OwnerCanDestroy,
- /// Is it possible to send tokens from this collection between users.
- TransferEnabled
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
- string key;
- bytes value;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x69d14d3e
-interface ERC20UniqueExtensions is Dummy, ERC165 {
- /// @dev Function to check the amount of tokens that an owner allowed to a spender.
- /// @param owner crossAddress The address which owns the funds.
- /// @param spender crossAddress The address which will spend the funds.
- /// @return A uint256 specifying the amount of tokens still available for the spender.
- /// @dev EVM selector for this function is: 0xe0af4bd7,
- /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
- function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
-
- /// @notice A description for the collection.
- /// @dev EVM selector for this function is: 0x7284e416,
- /// or in textual repr: description()
- function description() external view returns (string memory);
-
- /// @dev EVM selector for this function is: 0x269e6158,
- /// or in textual repr: mintCross((address,uint256),uint256)
- function mintCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0x0ecd0ab0,
- /// or in textual repr: approveCross((address,uint256),uint256)
- function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
-
- // /// Burn tokens from account
- // /// @dev Function that burns an `amount` of the tokens of a given account,
- // /// deducting from the sender's allowance for said account.
- // /// @param from The account whose tokens will be burnt.
- // /// @param amount The amount that will be burnt.
- // /// @dev EVM selector for this function is: 0x79cc6790,
- // /// or in textual repr: burnFrom(address,uint256)
- // function burnFrom(address from, uint256 amount) external returns (bool);
-
- /// Burn tokens from account
- /// @dev Function that burns an `amount` of the tokens of a given account,
- /// deducting from the sender's allowance for said account.
- /// @param from The account whose tokens will be burnt.
- /// @param amount The amount that will be burnt.
- /// @dev EVM selector for this function is: 0xbb2f5a58,
- /// or in textual repr: burnFromCross((address,uint256),uint256)
- function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
-
- /// Mint tokens for multiple accounts.
- /// @param amounts array of pairs of account address and amount
- /// @dev EVM selector for this function is: 0x1acf2d55,
- /// or in textual repr: mintBulk((address,uint256)[])
- function mintBulk(AmountForAddress[] memory amounts) external returns (bool);
-
- /// @dev EVM selector for this function is: 0x2ada85ff,
- /// or in textual repr: transferCross((address,uint256),uint256)
- function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0xd5cf430b,
- /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
- function transferFromCross(
- CrossAddress memory from,
- CrossAddress memory to,
- uint256 amount
- ) external returns (bool);
-
- /// @notice Returns collection helper contract address
- /// @dev EVM selector for this function is: 0x1896cce6,
- /// or in textual repr: collectionHelperAddress()
- function collectionHelperAddress() external view returns (address);
-
- /// @notice Balance of account
- /// @param owner An cross address for whom to query the balance
- /// @return The number of fingibles owned by `owner`, possibly zero
- /// @dev EVM selector for this function is: 0xec069398,
- /// or in textual repr: balanceOfCross((address,uint256))
- function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-}
-
-struct AmountForAddress {
- address to;
- uint256 amount;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x40c10f19
-interface ERC20Mintable is Dummy, ERC165 {
- /// Mint tokens for `to` account.
- /// @param to account that will receive minted tokens
- /// @param amount amount of tokens to mint
- /// @dev EVM selector for this function is: 0x40c10f19,
- /// or in textual repr: mint(address,uint256)
- function mint(address to, uint256 amount) external returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC20Events {
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
- /// @dev EVM selector for this function is: 0x06fdde03,
- /// or in textual repr: name()
- function name() external view returns (string memory);
-
- /// @dev EVM selector for this function is: 0x95d89b41,
- /// or in textual repr: symbol()
- function symbol() external view returns (string memory);
-
- /// @dev EVM selector for this function is: 0x18160ddd,
- /// or in textual repr: totalSupply()
- function totalSupply() external view returns (uint256);
-
- /// @dev EVM selector for this function is: 0x313ce567,
- /// or in textual repr: decimals()
- function decimals() external view returns (uint8);
-
- /// @dev EVM selector for this function is: 0x70a08231,
- /// or in textual repr: balanceOf(address)
- function balanceOf(address owner) external view returns (uint256);
-
- /// @dev EVM selector for this function is: 0xa9059cbb,
- /// or in textual repr: transfer(address,uint256)
- function transfer(address to, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0x23b872dd,
- /// or in textual repr: transferFrom(address,address,uint256)
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) external returns (bool);
-
- /// @dev EVM selector for this function is: 0x095ea7b3,
- /// or in textual repr: approve(address,uint256)
- function approve(address spender, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0xdd62ed3e,
- /// or in textual repr: allowance(address,address)
- function allowance(address owner, address spender) external view returns (uint256);
-}
-
-interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
js-packages/tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/UniqueNFT.sol
+++ /dev/null
@@ -1,855 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC721TokenEvent {
- event TokenChanged(uint256 indexed tokenId);
-}
-
-/// @title A contract that allows to set and delete token properties and change token property permissions.
-/// @dev the ERC-165 identifier for this interface is 0xde0695c2
-interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
- // /// @notice Set permissions for token property.
- // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
- // /// @param key Property key.
- // /// @param isMutable Permission to mutate property.
- // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
- // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
- // /// @dev EVM selector for this function is: 0x222d97fa,
- // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
- // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
-
- /// @notice Set permissions for token property.
- /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
- /// @param permissions Permissions for keys.
- /// @dev EVM selector for this function is: 0xbd92983a,
- /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
- function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
-
- /// @notice Get permissions for token properties.
- /// @dev EVM selector for this function is: 0xf23d7790,
- /// or in textual repr: tokenPropertyPermissions()
- function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
-
- // /// @notice Set token property value.
- // /// @dev Throws error if `msg.sender` has no permission to edit the property.
- // /// @param tokenId ID of the token.
- // /// @param key Property key.
- // /// @param value Property value.
- // /// @dev EVM selector for this function is: 0x1752d67b,
- // /// or in textual repr: setProperty(uint256,string,bytes)
- // function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
-
- /// @notice Set token properties value.
- /// @dev Throws error if `msg.sender` has no permission to edit the property.
- /// @param tokenId ID of the token.
- /// @param properties settable properties
- /// @dev EVM selector for this function is: 0x14ed3a6e,
- /// or in textual repr: setProperties(uint256,(string,bytes)[])
- function setProperties(uint256 tokenId, Property[] memory properties) external;
-
- // /// @notice Delete token property value.
- // /// @dev Throws error if `msg.sender` has no permission to edit the property.
- // /// @param tokenId ID of the token.
- // /// @param key Property key.
- // /// @dev EVM selector for this function is: 0x066111d1,
- // /// or in textual repr: deleteProperty(uint256,string)
- // function deleteProperty(uint256 tokenId, string memory key) external;
-
- /// @notice Delete token properties value.
- /// @dev Throws error if `msg.sender` has no permission to edit the property.
- /// @param tokenId ID of the token.
- /// @param keys Properties key.
- /// @dev EVM selector for this function is: 0xc472d371,
- /// or in textual repr: deleteProperties(uint256,string[])
- function deleteProperties(uint256 tokenId, string[] memory keys) external;
-
- /// @notice Get token property value.
- /// @dev Throws error if key not found
- /// @param tokenId ID of the token.
- /// @param key Property key.
- /// @return Property value bytes
- /// @dev EVM selector for this function is: 0x7228c327,
- /// or in textual repr: property(uint256,string)
- function property(uint256 tokenId, string memory key) external view returns (bytes memory);
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
- string key;
- bytes value;
-}
-
-/// Ethereum representation of Token Property Permissions.
-struct TokenPropertyPermission {
- /// Token property key.
- string key;
- /// Token property permissions.
- PropertyPermission[] permissions;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
-struct PropertyPermission {
- /// TokenPermission field.
- TokenPermissionField code;
- /// TokenPermission value.
- bool value;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
-enum TokenPermissionField {
- /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
- Mutable,
- /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
- TokenOwner,
- /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
- CollectionAdmin
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
-interface Collection is Dummy, ERC165 {
- // /// Set collection property.
- // ///
- // /// @param key Property key.
- // /// @param value Propery value.
- // /// @dev EVM selector for this function is: 0x2f073f66,
- // /// or in textual repr: setCollectionProperty(string,bytes)
- // function setCollectionProperty(string memory key, bytes memory value) external;
-
- /// Set collection properties.
- ///
- /// @param properties Vector of properties key/value pair.
- /// @dev EVM selector for this function is: 0x50b26b2a,
- /// or in textual repr: setCollectionProperties((string,bytes)[])
- function setCollectionProperties(Property[] memory properties) external;
-
- // /// Delete collection property.
- // ///
- // /// @param key Property key.
- // /// @dev EVM selector for this function is: 0x7b7debce,
- // /// or in textual repr: deleteCollectionProperty(string)
- // function deleteCollectionProperty(string memory key) external;
-
- /// Delete collection properties.
- ///
- /// @param keys Properties keys.
- /// @dev EVM selector for this function is: 0xee206ee3,
- /// or in textual repr: deleteCollectionProperties(string[])
- function deleteCollectionProperties(string[] memory keys) external;
-
- /// Get collection property.
- ///
- /// @dev Throws error if key not found.
- ///
- /// @param key Property key.
- /// @return bytes The property corresponding to the key.
- /// @dev EVM selector for this function is: 0xcf24fd6d,
- /// or in textual repr: collectionProperty(string)
- function collectionProperty(string memory key) external view returns (bytes memory);
-
- /// Get collection properties.
- ///
- /// @param keys Properties keys. Empty keys for all propertyes.
- /// @return Vector of properties key/value pairs.
- /// @dev EVM selector for this function is: 0x285fb8e6,
- /// or in textual repr: collectionProperties(string[])
- function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
- // /// Set the sponsor of the collection.
- // ///
- // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
- // ///
- // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
- // /// @dev EVM selector for this function is: 0x7623402e,
- // /// or in textual repr: setCollectionSponsor(address)
- // function setCollectionSponsor(address sponsor) external;
-
- /// Set the sponsor of the collection.
- ///
- /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
- ///
- /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
- /// @dev EVM selector for this function is: 0x84a1d5a8,
- /// or in textual repr: setCollectionSponsorCross((address,uint256))
- function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
- /// Whether there is a pending sponsor.
- /// @dev EVM selector for this function is: 0x058ac185,
- /// or in textual repr: hasCollectionPendingSponsor()
- function hasCollectionPendingSponsor() external view returns (bool);
-
- /// Collection sponsorship confirmation.
- ///
- /// @dev After setting the sponsor for the collection, it must be confirmed with this function.
- /// @dev EVM selector for this function is: 0x3c50e97a,
- /// or in textual repr: confirmCollectionSponsorship()
- function confirmCollectionSponsorship() external;
-
- /// Remove collection sponsor.
- /// @dev EVM selector for this function is: 0x6e0326a3,
- /// or in textual repr: removeCollectionSponsor()
- function removeCollectionSponsor() external;
-
- /// Get current sponsor.
- ///
- /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
- /// @dev EVM selector for this function is: 0x6ec0a9f1,
- /// or in textual repr: collectionSponsor()
- function collectionSponsor() external view returns (CrossAddress memory);
-
- /// Get current collection limits.
- ///
- /// @return Array of collection limits
- /// @dev EVM selector for this function is: 0xf63bc572,
- /// or in textual repr: collectionLimits()
- function collectionLimits() external view returns (CollectionLimit[] memory);
-
- /// Set limits for the collection.
- /// @dev Throws error if limit not found.
- /// @param limit Some limit.
- /// @dev EVM selector for this function is: 0x2316ee74,
- /// or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
- function setCollectionLimit(CollectionLimit memory limit) external;
-
- /// Get contract address.
- /// @dev EVM selector for this function is: 0xf6b4dfb4,
- /// or in textual repr: contractAddress()
- function contractAddress() external view returns (address);
-
- /// Add collection admin.
- /// @param newAdmin Cross account administrator address.
- /// @dev EVM selector for this function is: 0x859aa7d6,
- /// or in textual repr: addCollectionAdminCross((address,uint256))
- function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
- /// Remove collection admin.
- /// @param admin Cross account administrator address.
- /// @dev EVM selector for this function is: 0x6c0cd173,
- /// or in textual repr: removeCollectionAdminCross((address,uint256))
- function removeCollectionAdminCross(CrossAddress memory admin) external;
-
- // /// Add collection admin.
- // /// @param newAdmin Address of the added administrator.
- // /// @dev EVM selector for this function is: 0x92e462c7,
- // /// or in textual repr: addCollectionAdmin(address)
- // function addCollectionAdmin(address newAdmin) external;
-
- // /// Remove collection admin.
- // ///
- // /// @param admin Address of the removed administrator.
- // /// @dev EVM selector for this function is: 0xfafd7b42,
- // /// or in textual repr: removeCollectionAdmin(address)
- // function removeCollectionAdmin(address admin) external;
-
- /// @dev EVM selector for this function is: 0x0b9f3890,
- /// or in textual repr: setCollectionNesting((bool,bool,address[]))
- function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
-
- // /// Toggle accessibility of collection nesting.
- // ///
- // /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
- // /// @dev EVM selector for this function is: 0x112d4586,
- // /// or in textual repr: setCollectionNesting(bool)
- // function setCollectionNesting(bool enable) external;
-
- // /// Toggle accessibility of collection nesting.
- // ///
- // /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
- // /// @param collections Addresses of collections that will be available for nesting.
- // /// @dev EVM selector for this function is: 0x64872396,
- // /// or in textual repr: setCollectionNesting(bool,address[])
- // function setCollectionNesting(bool enable, address[] memory collections) external;
-
- /// @dev EVM selector for this function is: 0x92c660a8,
- /// or in textual repr: collectionNesting()
- function collectionNesting() external view returns (CollectionNestingAndPermission memory);
-
- // /// Returns nesting for a collection
- // /// @dev EVM selector for this function is: 0x22d25bfe,
- // /// or in textual repr: collectionNestingRestrictedCollectionIds()
- // function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
- // /// Returns permissions for a collection
- // /// @dev EVM selector for this function is: 0x5b2eaf4b,
- // /// or in textual repr: collectionNestingPermissions()
- // function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
- /// Set the collection access method.
- /// @param mode Access mode
- /// @dev EVM selector for this function is: 0x41835d4c,
- /// or in textual repr: setCollectionAccess(uint8)
- function setCollectionAccess(AccessMode mode) external;
-
- /// Checks that user allowed to operate with collection.
- ///
- /// @param user User address to check.
- /// @dev EVM selector for this function is: 0x91b6df49,
- /// or in textual repr: allowlistedCross((address,uint256))
- function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
- // /// Add the user to the allowed list.
- // ///
- // /// @param user Address of a trusted user.
- // /// @dev EVM selector for this function is: 0x67844fe6,
- // /// or in textual repr: addToCollectionAllowList(address)
- // function addToCollectionAllowList(address user) external;
-
- /// Add user to allowed list.
- ///
- /// @param user User cross account address.
- /// @dev EVM selector for this function is: 0xa0184a3a,
- /// or in textual repr: addToCollectionAllowListCross((address,uint256))
- function addToCollectionAllowListCross(CrossAddress memory user) external;
-
- // /// Remove the user from the allowed list.
- // ///
- // /// @param user Address of a removed user.
- // /// @dev EVM selector for this function is: 0x85c51acb,
- // /// or in textual repr: removeFromCollectionAllowList(address)
- // function removeFromCollectionAllowList(address user) external;
-
- /// Remove user from allowed list.
- ///
- /// @param user User cross account address.
- /// @dev EVM selector for this function is: 0x09ba452a,
- /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))
- function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
- /// Switch permission for minting.
- ///
- /// @param mode Enable if "true".
- /// @dev EVM selector for this function is: 0x00018e84,
- /// or in textual repr: setCollectionMintMode(bool)
- function setCollectionMintMode(bool mode) external;
-
- // /// Check that account is the owner or admin of the collection
- // ///
- // /// @param user account to verify
- // /// @return "true" if account is the owner or admin
- // /// @dev EVM selector for this function is: 0x9811b0c7,
- // /// or in textual repr: isOwnerOrAdmin(address)
- // function isOwnerOrAdmin(address user) external view returns (bool);
-
- /// Check that account is the owner or admin of the collection
- ///
- /// @param user User cross account to verify
- /// @return "true" if account is the owner or admin
- /// @dev EVM selector for this function is: 0x3e75a905,
- /// or in textual repr: isOwnerOrAdminCross((address,uint256))
- function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
- /// Returns collection type
- ///
- /// @return `Fungible` or `NFT` or `ReFungible`
- /// @dev EVM selector for this function is: 0xd34b55b8,
- /// or in textual repr: uniqueCollectionType()
- function uniqueCollectionType() external view returns (string memory);
-
- /// Get collection owner.
- ///
- /// @return Tuble with sponsor address and his substrate mirror.
- /// If address is canonical then substrate mirror is zero and vice versa.
- /// @dev EVM selector for this function is: 0xdf727d3b,
- /// or in textual repr: collectionOwner()
- function collectionOwner() external view returns (CrossAddress memory);
-
- // /// Changes collection owner to another account
- // ///
- // /// @dev Owner can be changed only by current owner
- // /// @param newOwner new owner account
- // /// @dev EVM selector for this function is: 0x4f53e226,
- // /// or in textual repr: changeCollectionOwner(address)
- // function changeCollectionOwner(address newOwner) external;
-
- /// Get collection administrators
- ///
- /// @return Vector of tuples with admins address and his substrate mirror.
- /// If address is canonical then substrate mirror is zero and vice versa.
- /// @dev EVM selector for this function is: 0x5813216b,
- /// or in textual repr: collectionAdmins()
- function collectionAdmins() external view returns (CrossAddress[] memory);
-
- /// Changes collection owner to another account
- ///
- /// @dev Owner can be changed only by current owner
- /// @param newOwner new owner cross account
- /// @dev EVM selector for this function is: 0x6496c497,
- /// or in textual repr: changeCollectionOwnerCross((address,uint256))
- function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
- /// Access grant for owner and admins. Used as default.
- Normal,
- /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
- AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
- CollectionPermissionField field;
- bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
- /// Owner of token can nest tokens under it.
- TokenOwner,
- /// Admin of token collection can nest tokens under token.
- CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
- bool token_owner;
- uint256[] ids;
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
- /// Owner of token can nest tokens under it.
- bool token_owner;
- /// Admin of token collection can nest tokens under token.
- bool collection_admin;
- /// If set - only tokens from specified collections can be nested.
- address[] restricted;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
- CollectionLimitField field;
- OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
- /// Shows the status of accessibility of value
- bool status;
- /// Actual value if `status` is true
- uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
- /// How many tokens can a user have on one account.
- AccountTokenOwnership,
- /// How many bytes of data are available for sponsorship.
- SponsoredDataSize,
- /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
- SponsoredDataRateLimit,
- /// How many tokens can be mined into this collection.
- TokenLimit,
- /// Timeouts for transfer sponsoring.
- SponsorTransferTimeout,
- /// Timeout for sponsoring an approval in passed blocks.
- SponsorApproveTimeout,
- /// Whether the collection owner of the collection can send tokens (which belong to other users).
- OwnerCanTransfer,
- /// Can the collection owner burn other people's tokens.
- OwnerCanDestroy,
- /// Is it possible to send tokens from this collection between users.
- TransferEnabled
-}
-
-/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
-/// @dev See https://eips.ethereum.org/EIPS/eip-721
-/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
-interface ERC721Metadata is Dummy, ERC165 {
- // /// @notice A descriptive name for a collection of NFTs in this contract
- // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
- // /// @dev EVM selector for this function is: 0x06fdde03,
- // /// or in textual repr: name()
- // function name() external view returns (string memory);
-
- // /// @notice An abbreviated name for NFTs in this contract
- // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
- // /// @dev EVM selector for this function is: 0x95d89b41,
- // /// or in textual repr: symbol()
- // function symbol() external view returns (string memory);
-
- /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
- ///
- /// @dev If the token has a `url` property and it is not empty, it is returned.
- /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
- /// If the collection property `baseURI` is empty or absent, return "" (empty string)
- /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
- /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
- ///
- /// @return token's const_metadata
- /// @dev EVM selector for this function is: 0xc87b56dd,
- /// or in textual repr: tokenURI(uint256)
- function tokenURI(uint256 tokenId) external view returns (string memory);
-}
-
-/// @title ERC721 Token that can be irreversibly burned (destroyed).
-/// @dev the ERC-165 identifier for this interface is 0x42966c68
-interface ERC721Burnable is Dummy, ERC165 {
- /// @notice Burns a specific ERC721 token.
- /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param tokenId The NFT to approve
- /// @dev EVM selector for this function is: 0x42966c68,
- /// or in textual repr: burn(uint256)
- function burn(uint256 tokenId) external;
-}
-
-/// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
-interface ERC721UniqueMintable is Dummy, ERC165 {
- /// @notice Function to mint a token.
- /// @param to The new owner
- /// @return uint256 The id of the newly minted token
- /// @dev EVM selector for this function is: 0x6a627842,
- /// or in textual repr: mint(address)
- function mint(address to) external returns (uint256);
-
- // /// @notice Function to mint a token.
- // /// @dev `tokenId` should be obtained with `nextTokenId` method,
- // /// unlike standard, you can't specify it manually
- // /// @param to The new owner
- // /// @param tokenId ID of the minted NFT
- // /// @dev EVM selector for this function is: 0x40c10f19,
- // /// or in textual repr: mint(address,uint256)
- // function mint(address to, uint256 tokenId) external returns (bool);
-
- /// @notice Function to mint token with the given tokenUri.
- /// @param to The new owner
- /// @param tokenUri Token URI that would be stored in the NFT properties
- /// @return uint256 The id of the newly minted token
- /// @dev EVM selector for this function is: 0x45c17782,
- /// or in textual repr: mintWithTokenURI(address,string)
- function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
- // /// @notice Function to mint token with the given tokenUri.
- // /// @dev `tokenId` should be obtained with `nextTokenId` method,
- // /// unlike standard, you can't specify it manually
- // /// @param to The new owner
- // /// @param tokenId ID of the minted NFT
- // /// @param tokenUri Token URI that would be stored in the NFT properties
- // /// @dev EVM selector for this function is: 0x50bb4e7f,
- // /// or in textual repr: mintWithTokenURI(address,uint256,string)
- // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
-
-}
-
-/// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0x9b397d16
-interface ERC721UniqueExtensions is Dummy, ERC165 {
- /// @notice A descriptive name for a collection of NFTs in this contract
- /// @dev EVM selector for this function is: 0x06fdde03,
- /// or in textual repr: name()
- function name() external view returns (string memory);
-
- /// @notice An abbreviated name for NFTs in this contract
- /// @dev EVM selector for this function is: 0x95d89b41,
- /// or in textual repr: symbol()
- function symbol() external view returns (string memory);
-
- /// @notice A description for the collection.
- /// @dev EVM selector for this function is: 0x7284e416,
- /// or in textual repr: description()
- function description() external view returns (string memory);
-
- // /// Returns the owner (in cross format) of the token.
- // ///
- // /// @param tokenId Id for the token.
- // /// @dev EVM selector for this function is: 0x2b29dace,
- // /// or in textual repr: crossOwnerOf(uint256)
- // function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
-
- /// Returns the owner (in cross format) of the token.
- ///
- /// @param tokenId Id for the token.
- /// @dev EVM selector for this function is: 0xcaa3a4d0,
- /// or in textual repr: ownerOfCross(uint256)
- function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
-
- /// @notice Count all NFTs assigned to an owner
- /// @param owner An cross address for whom to query the balance
- /// @return The number of NFTs owned by `owner`, possibly zero
- /// @dev EVM selector for this function is: 0xec069398,
- /// or in textual repr: balanceOfCross((address,uint256))
- function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
- /// Returns the token properties.
- ///
- /// @param tokenId Id for the token.
- /// @param keys Properties keys. Empty keys for all propertyes.
- /// @return Vector of properties key/value pairs.
- /// @dev EVM selector for this function is: 0xe07ede7e,
- /// or in textual repr: properties(uint256,string[])
- function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
-
- /// @notice Set or reaffirm the approved address for an NFT
- /// @dev The zero address indicates there is no approved address.
- /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param approved The new substrate address approved NFT controller
- /// @param tokenId The NFT to approve
- /// @dev EVM selector for this function is: 0x0ecd0ab0,
- /// or in textual repr: approveCross((address,uint256),uint256)
- function approveCross(CrossAddress memory approved, uint256 tokenId) external;
-
- /// @notice Transfer ownership of an NFT
- /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
- /// is the zero address. Throws if `tokenId` is not a valid NFT.
- /// @param to The new owner
- /// @param tokenId The NFT to transfer
- /// @dev EVM selector for this function is: 0xa9059cbb,
- /// or in textual repr: transfer(address,uint256)
- function transfer(address to, uint256 tokenId) external;
-
- /// @notice Transfer ownership of an NFT
- /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
- /// is the zero address. Throws if `tokenId` is not a valid NFT.
- /// @param to The new owner
- /// @param tokenId The NFT to transfer
- /// @dev EVM selector for this function is: 0x2ada85ff,
- /// or in textual repr: transferCross((address,uint256),uint256)
- function transferCross(CrossAddress memory to, uint256 tokenId) external;
-
- /// @notice Transfer ownership of an NFT from cross account address to cross account address
- /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
- /// is the zero address. Throws if `tokenId` is not a valid NFT.
- /// @param from Cross acccount address of current owner
- /// @param to Cross acccount address of new owner
- /// @param tokenId The NFT to transfer
- /// @dev EVM selector for this function is: 0xd5cf430b,
- /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
- function transferFromCross(
- CrossAddress memory from,
- CrossAddress memory to,
- uint256 tokenId
- ) external;
-
- // /// @notice Burns a specific ERC721 token.
- // /// @dev Throws unless `msg.sender` is the current owner or an authorized
- // /// operator for this NFT. Throws if `from` is not the current owner. Throws
- // /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
- // /// @param from The current owner of the NFT
- // /// @param tokenId The NFT to transfer
- // /// @dev EVM selector for this function is: 0x79cc6790,
- // /// or in textual repr: burnFrom(address,uint256)
- // function burnFrom(address from, uint256 tokenId) external;
-
- /// @notice Burns a specific ERC721 token.
- /// @dev Throws unless `msg.sender` is the current owner or an authorized
- /// operator for this NFT. Throws if `from` is not the current owner. Throws
- /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
- /// @param from The current owner of the NFT
- /// @param tokenId The NFT to transfer
- /// @dev EVM selector for this function is: 0xbb2f5a58,
- /// or in textual repr: burnFromCross((address,uint256),uint256)
- function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
-
- /// @notice Returns next free NFT ID.
- /// @dev EVM selector for this function is: 0x75794a3c,
- /// or in textual repr: nextTokenId()
- function nextTokenId() external view returns (uint256);
-
- // /// @notice Function to mint multiple tokens.
- // /// @dev `tokenIds` should be an array of consecutive numbers and first number
- // /// should be obtained with `nextTokenId` method
- // /// @param to The new owner
- // /// @param tokenIds IDs of the minted NFTs
- // /// @dev EVM selector for this function is: 0x44a9945e,
- // /// or in textual repr: mintBulk(address,uint256[])
- // function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
-
- /// @notice Function to mint a token.
- /// @param data Array of pairs of token owner and token's properties for minted token
- /// @dev EVM selector for this function is: 0xab427b0c,
- /// or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[])
- function mintBulkCross(MintTokenData[] memory data) external returns (bool);
-
- // /// @notice Function to mint multiple tokens with the given tokenUris.
- // /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
- // /// numbers and first number should be obtained with `nextTokenId` method
- // /// @param to The new owner
- // /// @param tokens array of pairs of token ID and token URI for minted tokens
- // /// @dev EVM selector for this function is: 0x36543006,
- // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
- // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
-
- /// @notice Function to mint a token.
- /// @param to The new owner crossAccountId
- /// @param properties Properties of minted token
- /// @return uint256 The id of the newly minted token
- /// @dev EVM selector for this function is: 0xb904db03,
- /// or in textual repr: mintCross((address,uint256),(string,bytes)[])
- function mintCross(CrossAddress memory to, Property[] memory properties) external returns (uint256);
-
- /// @notice Returns collection helper contract address
- /// @dev EVM selector for this function is: 0x1896cce6,
- /// or in textual repr: collectionHelperAddress()
- function collectionHelperAddress() external view returns (address);
-}
-
-/// Data for creation token with uri.
-struct TokenUri {
- /// Id of new token.
- uint256 id;
- /// Uri of new token.
- string uri;
-}
-
-/// Token minting parameters
-struct MintTokenData {
- /// Minted token owner
- CrossAddress owner;
- /// Minted token properties
- Property[] properties;
-}
-
-/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
-/// @dev See https://eips.ethereum.org/EIPS/eip-721
-/// @dev the ERC-165 identifier for this interface is 0x780e9d63
-interface ERC721Enumerable is Dummy, ERC165 {
- /// @notice Enumerate valid NFTs
- /// @param index A counter less than `totalSupply()`
- /// @return The token identifier for the `index`th NFT,
- /// (sort order not specified)
- /// @dev EVM selector for this function is: 0x4f6ccce7,
- /// or in textual repr: tokenByIndex(uint256)
- function tokenByIndex(uint256 index) external view returns (uint256);
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0x2f745c59,
- /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
- function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
-
- /// @notice Count NFTs tracked by this contract
- /// @return A count of valid NFTs tracked by this contract, where each one of
- /// them has an assigned and queryable owner not equal to the zero address
- /// @dev EVM selector for this function is: 0x18160ddd,
- /// or in textual repr: totalSupply()
- function totalSupply() external view returns (uint256);
-}
-
-/// @dev inlined interface
-interface ERC721Events {
- event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
- event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
- event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-}
-
-/// @title ERC-721 Non-Fungible Token Standard
-/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
-interface ERC721 is Dummy, ERC165, ERC721Events {
- /// @notice Count all NFTs assigned to an owner
- /// @dev NFTs assigned to the zero address are considered invalid, and this
- /// function throws for queries about the zero address.
- /// @param owner An address for whom to query the balance
- /// @return The number of NFTs owned by `owner`, possibly zero
- /// @dev EVM selector for this function is: 0x70a08231,
- /// or in textual repr: balanceOf(address)
- function balanceOf(address owner) external view returns (uint256);
-
- /// @notice Find the owner of an NFT
- /// @dev NFTs assigned to zero address are considered invalid, and queries
- /// about them do throw.
- /// @param tokenId The identifier for an NFT
- /// @return The address of the owner of the NFT
- /// @dev EVM selector for this function is: 0x6352211e,
- /// or in textual repr: ownerOf(uint256)
- function ownerOf(uint256 tokenId) external view returns (address);
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0xb88d4fde,
- /// or in textual repr: safeTransferFrom(address,address,uint256,bytes)
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId,
- bytes memory data
- ) external;
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0x42842e0e,
- /// or in textual repr: safeTransferFrom(address,address,uint256)
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external;
-
- /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
- /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
- /// THEY MAY BE PERMANENTLY LOST
- /// @dev Throws unless `msg.sender` is the current owner or an authorized
- /// operator for this NFT. Throws if `from` is not the current owner. Throws
- /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
- /// @param from The current owner of the NFT
- /// @param to The new owner
- /// @param tokenId The NFT to transfer
- /// @dev EVM selector for this function is: 0x23b872dd,
- /// or in textual repr: transferFrom(address,address,uint256)
- function transferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external;
-
- /// @notice Set or reaffirm the approved address for an NFT
- /// @dev The zero address indicates there is no approved address.
- /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param approved The new approved NFT controller
- /// @param tokenId The NFT to approve
- /// @dev EVM selector for this function is: 0x095ea7b3,
- /// or in textual repr: approve(address,uint256)
- function approve(address approved, uint256 tokenId) external;
-
- /// @notice Sets or unsets the approval of a given operator.
- /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf.
- /// @param operator Operator
- /// @param approved Should operator status be granted or revoked?
- /// @dev EVM selector for this function is: 0xa22cb465,
- /// or in textual repr: setApprovalForAll(address,bool)
- function setApprovalForAll(address operator, bool approved) external;
-
- /// @notice Get the approved address for a single NFT
- /// @dev Throws if `tokenId` is not a valid NFT
- /// @param tokenId The NFT to find the approved address for
- /// @return The approved address for this NFT, or the zero address if there is none
- /// @dev EVM selector for this function is: 0x081812fc,
- /// or in textual repr: getApproved(uint256)
- function getApproved(uint256 tokenId) external view returns (address);
-
- /// @notice Tells whether the given `owner` approves the `operator`.
- /// @dev EVM selector for this function is: 0xe985e9c5,
- /// or in textual repr: isApprovedForAll(address,address)
- function isApprovedForAll(address owner, address operator) external view returns (bool);
-}
-
-interface UniqueNFT is
- Dummy,
- ERC165,
- ERC721,
- ERC721Enumerable,
- ERC721UniqueExtensions,
- ERC721UniqueMintable,
- ERC721Burnable,
- ERC721Metadata,
- Collection,
- TokenProperties
-{}
js-packages/tests/src/eth/api/UniqueNativeFungible.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/UniqueNativeFungible.sol
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x1313556c
-interface ERC20UniqueExtensions is Dummy, ERC165 {
- /// @dev EVM selector for this function is: 0xec069398,
- /// or in textual repr: balanceOfCross((address,uint256))
- function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
- /// @dev EVM selector for this function is: 0x2ada85ff,
- /// or in textual repr: transferCross((address,uint256),uint256)
- function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0xd5cf430b,
- /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
- function transferFromCross(
- CrossAddress memory from,
- CrossAddress memory to,
- uint256 amount
- ) external returns (bool);
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
-
-/// @dev inlined interface
-interface ERC20Events {
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
- /// @dev EVM selector for this function is: 0xdd62ed3e,
- /// or in textual repr: allowance(address,address)
- function allowance(address owner, address spender) external view returns (uint256);
-
- /// @dev EVM selector for this function is: 0x095ea7b3,
- /// or in textual repr: approve(address,uint256)
- function approve(address spender, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0x70a08231,
- /// or in textual repr: balanceOf(address)
- function balanceOf(address owner) external view returns (uint256);
-
- /// @dev EVM selector for this function is: 0x313ce567,
- /// or in textual repr: decimals()
- function decimals() external view returns (uint8);
-
- /// @dev EVM selector for this function is: 0x06fdde03,
- /// or in textual repr: name()
- function name() external view returns (string memory);
-
- /// @dev EVM selector for this function is: 0x95d89b41,
- /// or in textual repr: symbol()
- function symbol() external view returns (string memory);
-
- /// @dev EVM selector for this function is: 0x18160ddd,
- /// or in textual repr: totalSupply()
- function totalSupply() external view returns (uint256);
-
- /// @dev EVM selector for this function is: 0xa9059cbb,
- /// or in textual repr: transfer(address,uint256)
- function transfer(address to, uint256 amount) external returns (bool);
-
- /// @dev EVM selector for this function is: 0x23b872dd,
- /// or in textual repr: transferFrom(address,address,uint256)
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) external returns (bool);
-}
-
-interface UniqueNativeFungible is Dummy, ERC165, ERC20, ERC20UniqueExtensions {}
js-packages/tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/UniqueRefungible.sol
+++ /dev/null
@@ -1,859 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC721TokenEvent {
- event TokenChanged(uint256 indexed tokenId);
-}
-
-/// @title A contract that allows to set and delete token properties and change token property permissions.
-/// @dev the ERC-165 identifier for this interface is 0xde0695c2
-interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
- // /// @notice Set permissions for token property.
- // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
- // /// @param key Property key.
- // /// @param isMutable Permission to mutate property.
- // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
- // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
- // /// @dev EVM selector for this function is: 0x222d97fa,
- // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
- // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
-
- /// @notice Set permissions for token property.
- /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
- /// @param permissions Permissions for keys.
- /// @dev EVM selector for this function is: 0xbd92983a,
- /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
- function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
-
- /// @notice Get permissions for token properties.
- /// @dev EVM selector for this function is: 0xf23d7790,
- /// or in textual repr: tokenPropertyPermissions()
- function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
-
- // /// @notice Set token property value.
- // /// @dev Throws error if `msg.sender` has no permission to edit the property.
- // /// @param tokenId ID of the token.
- // /// @param key Property key.
- // /// @param value Property value.
- // /// @dev EVM selector for this function is: 0x1752d67b,
- // /// or in textual repr: setProperty(uint256,string,bytes)
- // function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
-
- /// @notice Set token properties value.
- /// @dev Throws error if `msg.sender` has no permission to edit the property.
- /// @param tokenId ID of the token.
- /// @param properties settable properties
- /// @dev EVM selector for this function is: 0x14ed3a6e,
- /// or in textual repr: setProperties(uint256,(string,bytes)[])
- function setProperties(uint256 tokenId, Property[] memory properties) external;
-
- // /// @notice Delete token property value.
- // /// @dev Throws error if `msg.sender` has no permission to edit the property.
- // /// @param tokenId ID of the token.
- // /// @param key Property key.
- // /// @dev EVM selector for this function is: 0x066111d1,
- // /// or in textual repr: deleteProperty(uint256,string)
- // function deleteProperty(uint256 tokenId, string memory key) external;
-
- /// @notice Delete token properties value.
- /// @dev Throws error if `msg.sender` has no permission to edit the property.
- /// @param tokenId ID of the token.
- /// @param keys Properties key.
- /// @dev EVM selector for this function is: 0xc472d371,
- /// or in textual repr: deleteProperties(uint256,string[])
- function deleteProperties(uint256 tokenId, string[] memory keys) external;
-
- /// @notice Get token property value.
- /// @dev Throws error if key not found
- /// @param tokenId ID of the token.
- /// @param key Property key.
- /// @return Property value bytes
- /// @dev EVM selector for this function is: 0x7228c327,
- /// or in textual repr: property(uint256,string)
- function property(uint256 tokenId, string memory key) external view returns (bytes memory);
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
- string key;
- bytes value;
-}
-
-/// Ethereum representation of Token Property Permissions.
-struct TokenPropertyPermission {
- /// Token property key.
- string key;
- /// Token property permissions.
- PropertyPermission[] permissions;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
-struct PropertyPermission {
- /// TokenPermission field.
- TokenPermissionField code;
- /// TokenPermission value.
- bool value;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
-enum TokenPermissionField {
- /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
- Mutable,
- /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
- TokenOwner,
- /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
- CollectionAdmin
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
-interface Collection is Dummy, ERC165 {
- // /// Set collection property.
- // ///
- // /// @param key Property key.
- // /// @param value Propery value.
- // /// @dev EVM selector for this function is: 0x2f073f66,
- // /// or in textual repr: setCollectionProperty(string,bytes)
- // function setCollectionProperty(string memory key, bytes memory value) external;
-
- /// Set collection properties.
- ///
- /// @param properties Vector of properties key/value pair.
- /// @dev EVM selector for this function is: 0x50b26b2a,
- /// or in textual repr: setCollectionProperties((string,bytes)[])
- function setCollectionProperties(Property[] memory properties) external;
-
- // /// Delete collection property.
- // ///
- // /// @param key Property key.
- // /// @dev EVM selector for this function is: 0x7b7debce,
- // /// or in textual repr: deleteCollectionProperty(string)
- // function deleteCollectionProperty(string memory key) external;
-
- /// Delete collection properties.
- ///
- /// @param keys Properties keys.
- /// @dev EVM selector for this function is: 0xee206ee3,
- /// or in textual repr: deleteCollectionProperties(string[])
- function deleteCollectionProperties(string[] memory keys) external;
-
- /// Get collection property.
- ///
- /// @dev Throws error if key not found.
- ///
- /// @param key Property key.
- /// @return bytes The property corresponding to the key.
- /// @dev EVM selector for this function is: 0xcf24fd6d,
- /// or in textual repr: collectionProperty(string)
- function collectionProperty(string memory key) external view returns (bytes memory);
-
- /// Get collection properties.
- ///
- /// @param keys Properties keys. Empty keys for all propertyes.
- /// @return Vector of properties key/value pairs.
- /// @dev EVM selector for this function is: 0x285fb8e6,
- /// or in textual repr: collectionProperties(string[])
- function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
- // /// Set the sponsor of the collection.
- // ///
- // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
- // ///
- // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
- // /// @dev EVM selector for this function is: 0x7623402e,
- // /// or in textual repr: setCollectionSponsor(address)
- // function setCollectionSponsor(address sponsor) external;
-
- /// Set the sponsor of the collection.
- ///
- /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
- ///
- /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
- /// @dev EVM selector for this function is: 0x84a1d5a8,
- /// or in textual repr: setCollectionSponsorCross((address,uint256))
- function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
- /// Whether there is a pending sponsor.
- /// @dev EVM selector for this function is: 0x058ac185,
- /// or in textual repr: hasCollectionPendingSponsor()
- function hasCollectionPendingSponsor() external view returns (bool);
-
- /// Collection sponsorship confirmation.
- ///
- /// @dev After setting the sponsor for the collection, it must be confirmed with this function.
- /// @dev EVM selector for this function is: 0x3c50e97a,
- /// or in textual repr: confirmCollectionSponsorship()
- function confirmCollectionSponsorship() external;
-
- /// Remove collection sponsor.
- /// @dev EVM selector for this function is: 0x6e0326a3,
- /// or in textual repr: removeCollectionSponsor()
- function removeCollectionSponsor() external;
-
- /// Get current sponsor.
- ///
- /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
- /// @dev EVM selector for this function is: 0x6ec0a9f1,
- /// or in textual repr: collectionSponsor()
- function collectionSponsor() external view returns (CrossAddress memory);
-
- /// Get current collection limits.
- ///
- /// @return Array of collection limits
- /// @dev EVM selector for this function is: 0xf63bc572,
- /// or in textual repr: collectionLimits()
- function collectionLimits() external view returns (CollectionLimit[] memory);
-
- /// Set limits for the collection.
- /// @dev Throws error if limit not found.
- /// @param limit Some limit.
- /// @dev EVM selector for this function is: 0x2316ee74,
- /// or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
- function setCollectionLimit(CollectionLimit memory limit) external;
-
- /// Get contract address.
- /// @dev EVM selector for this function is: 0xf6b4dfb4,
- /// or in textual repr: contractAddress()
- function contractAddress() external view returns (address);
-
- /// Add collection admin.
- /// @param newAdmin Cross account administrator address.
- /// @dev EVM selector for this function is: 0x859aa7d6,
- /// or in textual repr: addCollectionAdminCross((address,uint256))
- function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
- /// Remove collection admin.
- /// @param admin Cross account administrator address.
- /// @dev EVM selector for this function is: 0x6c0cd173,
- /// or in textual repr: removeCollectionAdminCross((address,uint256))
- function removeCollectionAdminCross(CrossAddress memory admin) external;
-
- // /// Add collection admin.
- // /// @param newAdmin Address of the added administrator.
- // /// @dev EVM selector for this function is: 0x92e462c7,
- // /// or in textual repr: addCollectionAdmin(address)
- // function addCollectionAdmin(address newAdmin) external;
-
- // /// Remove collection admin.
- // ///
- // /// @param admin Address of the removed administrator.
- // /// @dev EVM selector for this function is: 0xfafd7b42,
- // /// or in textual repr: removeCollectionAdmin(address)
- // function removeCollectionAdmin(address admin) external;
-
- /// @dev EVM selector for this function is: 0x0b9f3890,
- /// or in textual repr: setCollectionNesting((bool,bool,address[]))
- function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
-
- // /// Toggle accessibility of collection nesting.
- // ///
- // /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
- // /// @dev EVM selector for this function is: 0x112d4586,
- // /// or in textual repr: setCollectionNesting(bool)
- // function setCollectionNesting(bool enable) external;
-
- // /// Toggle accessibility of collection nesting.
- // ///
- // /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
- // /// @param collections Addresses of collections that will be available for nesting.
- // /// @dev EVM selector for this function is: 0x64872396,
- // /// or in textual repr: setCollectionNesting(bool,address[])
- // function setCollectionNesting(bool enable, address[] memory collections) external;
-
- /// @dev EVM selector for this function is: 0x92c660a8,
- /// or in textual repr: collectionNesting()
- function collectionNesting() external view returns (CollectionNestingAndPermission memory);
-
- // /// Returns nesting for a collection
- // /// @dev EVM selector for this function is: 0x22d25bfe,
- // /// or in textual repr: collectionNestingRestrictedCollectionIds()
- // function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
- // /// Returns permissions for a collection
- // /// @dev EVM selector for this function is: 0x5b2eaf4b,
- // /// or in textual repr: collectionNestingPermissions()
- // function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
- /// Set the collection access method.
- /// @param mode Access mode
- /// @dev EVM selector for this function is: 0x41835d4c,
- /// or in textual repr: setCollectionAccess(uint8)
- function setCollectionAccess(AccessMode mode) external;
-
- /// Checks that user allowed to operate with collection.
- ///
- /// @param user User address to check.
- /// @dev EVM selector for this function is: 0x91b6df49,
- /// or in textual repr: allowlistedCross((address,uint256))
- function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
- // /// Add the user to the allowed list.
- // ///
- // /// @param user Address of a trusted user.
- // /// @dev EVM selector for this function is: 0x67844fe6,
- // /// or in textual repr: addToCollectionAllowList(address)
- // function addToCollectionAllowList(address user) external;
-
- /// Add user to allowed list.
- ///
- /// @param user User cross account address.
- /// @dev EVM selector for this function is: 0xa0184a3a,
- /// or in textual repr: addToCollectionAllowListCross((address,uint256))
- function addToCollectionAllowListCross(CrossAddress memory user) external;
-
- // /// Remove the user from the allowed list.
- // ///
- // /// @param user Address of a removed user.
- // /// @dev EVM selector for this function is: 0x85c51acb,
- // /// or in textual repr: removeFromCollectionAllowList(address)
- // function removeFromCollectionAllowList(address user) external;
-
- /// Remove user from allowed list.
- ///
- /// @param user User cross account address.
- /// @dev EVM selector for this function is: 0x09ba452a,
- /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))
- function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
- /// Switch permission for minting.
- ///
- /// @param mode Enable if "true".
- /// @dev EVM selector for this function is: 0x00018e84,
- /// or in textual repr: setCollectionMintMode(bool)
- function setCollectionMintMode(bool mode) external;
-
- // /// Check that account is the owner or admin of the collection
- // ///
- // /// @param user account to verify
- // /// @return "true" if account is the owner or admin
- // /// @dev EVM selector for this function is: 0x9811b0c7,
- // /// or in textual repr: isOwnerOrAdmin(address)
- // function isOwnerOrAdmin(address user) external view returns (bool);
-
- /// Check that account is the owner or admin of the collection
- ///
- /// @param user User cross account to verify
- /// @return "true" if account is the owner or admin
- /// @dev EVM selector for this function is: 0x3e75a905,
- /// or in textual repr: isOwnerOrAdminCross((address,uint256))
- function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
- /// Returns collection type
- ///
- /// @return `Fungible` or `NFT` or `ReFungible`
- /// @dev EVM selector for this function is: 0xd34b55b8,
- /// or in textual repr: uniqueCollectionType()
- function uniqueCollectionType() external view returns (string memory);
-
- /// Get collection owner.
- ///
- /// @return Tuble with sponsor address and his substrate mirror.
- /// If address is canonical then substrate mirror is zero and vice versa.
- /// @dev EVM selector for this function is: 0xdf727d3b,
- /// or in textual repr: collectionOwner()
- function collectionOwner() external view returns (CrossAddress memory);
-
- // /// Changes collection owner to another account
- // ///
- // /// @dev Owner can be changed only by current owner
- // /// @param newOwner new owner account
- // /// @dev EVM selector for this function is: 0x4f53e226,
- // /// or in textual repr: changeCollectionOwner(address)
- // function changeCollectionOwner(address newOwner) external;
-
- /// Get collection administrators
- ///
- /// @return Vector of tuples with admins address and his substrate mirror.
- /// If address is canonical then substrate mirror is zero and vice versa.
- /// @dev EVM selector for this function is: 0x5813216b,
- /// or in textual repr: collectionAdmins()
- function collectionAdmins() external view returns (CrossAddress[] memory);
-
- /// Changes collection owner to another account
- ///
- /// @dev Owner can be changed only by current owner
- /// @param newOwner new owner cross account
- /// @dev EVM selector for this function is: 0x6496c497,
- /// or in textual repr: changeCollectionOwnerCross((address,uint256))
- function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
- /// Access grant for owner and admins. Used as default.
- Normal,
- /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
- AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
- CollectionPermissionField field;
- bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
- /// Owner of token can nest tokens under it.
- TokenOwner,
- /// Admin of token collection can nest tokens under token.
- CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
- bool token_owner;
- uint256[] ids;
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
- /// Owner of token can nest tokens under it.
- bool token_owner;
- /// Admin of token collection can nest tokens under token.
- bool collection_admin;
- /// If set - only tokens from specified collections can be nested.
- address[] restricted;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
- CollectionLimitField field;
- OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
- /// Shows the status of accessibility of value
- bool status;
- /// Actual value if `status` is true
- uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
- /// How many tokens can a user have on one account.
- AccountTokenOwnership,
- /// How many bytes of data are available for sponsorship.
- SponsoredDataSize,
- /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
- SponsoredDataRateLimit,
- /// How many tokens can be mined into this collection.
- TokenLimit,
- /// Timeouts for transfer sponsoring.
- SponsorTransferTimeout,
- /// Timeout for sponsoring an approval in passed blocks.
- SponsorApproveTimeout,
- /// Whether the collection owner of the collection can send tokens (which belong to other users).
- OwnerCanTransfer,
- /// Can the collection owner burn other people's tokens.
- OwnerCanDestroy,
- /// Is it possible to send tokens from this collection between users.
- TransferEnabled
-}
-
-/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
-/// @dev See https://eips.ethereum.org/EIPS/eip-721
-/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
-interface ERC721Metadata is Dummy, ERC165 {
- // /// @notice A descriptive name for a collection of NFTs in this contract
- // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
- // /// @dev EVM selector for this function is: 0x06fdde03,
- // /// or in textual repr: name()
- // function name() external view returns (string memory);
-
- // /// @notice An abbreviated name for NFTs in this contract
- // /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
- // /// @dev EVM selector for this function is: 0x95d89b41,
- // /// or in textual repr: symbol()
- // function symbol() external view returns (string memory);
-
- /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
- ///
- /// @dev If the token has a `url` property and it is not empty, it is returned.
- /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
- /// If the collection property `baseURI` is empty or absent, return "" (empty string)
- /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
- /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
- ///
- /// @return token's const_metadata
- /// @dev EVM selector for this function is: 0xc87b56dd,
- /// or in textual repr: tokenURI(uint256)
- function tokenURI(uint256 tokenId) external view returns (string memory);
-}
-
-/// @title ERC721 Token that can be irreversibly burned (destroyed).
-/// @dev the ERC-165 identifier for this interface is 0x42966c68
-interface ERC721Burnable is Dummy, ERC165 {
- /// @notice Burns a specific ERC721 token.
- /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
- /// operator of the current owner.
- /// @param tokenId The RFT to approve
- /// @dev EVM selector for this function is: 0x42966c68,
- /// or in textual repr: burn(uint256)
- function burn(uint256 tokenId) external;
-}
-
-/// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
-interface ERC721UniqueMintable is Dummy, ERC165 {
- /// @notice Function to mint a token.
- /// @param to The new owner
- /// @return uint256 The id of the newly minted token
- /// @dev EVM selector for this function is: 0x6a627842,
- /// or in textual repr: mint(address)
- function mint(address to) external returns (uint256);
-
- // /// @notice Function to mint a token.
- // /// @dev `tokenId` should be obtained with `nextTokenId` method,
- // /// unlike standard, you can't specify it manually
- // /// @param to The new owner
- // /// @param tokenId ID of the minted RFT
- // /// @dev EVM selector for this function is: 0x40c10f19,
- // /// or in textual repr: mint(address,uint256)
- // function mint(address to, uint256 tokenId) external returns (bool);
-
- /// @notice Function to mint token with the given tokenUri.
- /// @param to The new owner
- /// @param tokenUri Token URI that would be stored in the NFT properties
- /// @return uint256 The id of the newly minted token
- /// @dev EVM selector for this function is: 0x45c17782,
- /// or in textual repr: mintWithTokenURI(address,string)
- function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
- // /// @notice Function to mint token with the given tokenUri.
- // /// @dev `tokenId` should be obtained with `nextTokenId` method,
- // /// unlike standard, you can't specify it manually
- // /// @param to The new owner
- // /// @param tokenId ID of the minted RFT
- // /// @param tokenUri Token URI that would be stored in the RFT properties
- // /// @dev EVM selector for this function is: 0x50bb4e7f,
- // /// or in textual repr: mintWithTokenURI(address,uint256,string)
- // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
-
-}
-
-/// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0x4abaabdb
-interface ERC721UniqueExtensions is Dummy, ERC165 {
- /// @notice A descriptive name for a collection of NFTs in this contract
- /// @dev EVM selector for this function is: 0x06fdde03,
- /// or in textual repr: name()
- function name() external view returns (string memory);
-
- /// @notice An abbreviated name for NFTs in this contract
- /// @dev EVM selector for this function is: 0x95d89b41,
- /// or in textual repr: symbol()
- function symbol() external view returns (string memory);
-
- /// @notice A description for the collection.
- /// @dev EVM selector for this function is: 0x7284e416,
- /// or in textual repr: description()
- function description() external view returns (string memory);
-
- // /// Returns the owner (in cross format) of the token.
- // ///
- // /// @param tokenId Id for the token.
- // /// @dev EVM selector for this function is: 0x2b29dace,
- // /// or in textual repr: crossOwnerOf(uint256)
- // function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
-
- /// Returns the owner (in cross format) of the token.
- ///
- /// @param tokenId Id for the token.
- /// @dev EVM selector for this function is: 0xcaa3a4d0,
- /// or in textual repr: ownerOfCross(uint256)
- function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
-
- /// @notice Count all RFTs assigned to an owner
- /// @param owner An cross address for whom to query the balance
- /// @return The number of RFTs owned by `owner`, possibly zero
- /// @dev EVM selector for this function is: 0xec069398,
- /// or in textual repr: balanceOfCross((address,uint256))
- function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
- /// Returns the token properties.
- ///
- /// @param tokenId Id for the token.
- /// @param keys Properties keys. Empty keys for all propertyes.
- /// @return Vector of properties key/value pairs.
- /// @dev EVM selector for this function is: 0xe07ede7e,
- /// or in textual repr: properties(uint256,string[])
- function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
-
- /// @notice Transfer ownership of an RFT
- /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
- /// is the zero address. Throws if `tokenId` is not a valid RFT.
- /// Throws if RFT pieces have multiple owners.
- /// @param to The new owner
- /// @param tokenId The RFT to transfer
- /// @dev EVM selector for this function is: 0xa9059cbb,
- /// or in textual repr: transfer(address,uint256)
- function transfer(address to, uint256 tokenId) external;
-
- /// @notice Transfer ownership of an RFT
- /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
- /// is the zero address. Throws if `tokenId` is not a valid RFT.
- /// Throws if RFT pieces have multiple owners.
- /// @param to The new owner
- /// @param tokenId The RFT to transfer
- /// @dev EVM selector for this function is: 0x2ada85ff,
- /// or in textual repr: transferCross((address,uint256),uint256)
- function transferCross(CrossAddress memory to, uint256 tokenId) external;
-
- /// @notice Transfer ownership of an RFT
- /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
- /// is the zero address. Throws if `tokenId` is not a valid RFT.
- /// Throws if RFT pieces have multiple owners.
- /// @param to The new owner
- /// @param tokenId The RFT to transfer
- /// @dev EVM selector for this function is: 0xd5cf430b,
- /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
- function transferFromCross(
- CrossAddress memory from,
- CrossAddress memory to,
- uint256 tokenId
- ) external;
-
- // /// @notice Burns a specific ERC721 token.
- // /// @dev Throws unless `msg.sender` is the current owner or an authorized
- // /// operator for this RFT. Throws if `from` is not the current owner. Throws
- // /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
- // /// Throws if RFT pieces have multiple owners.
- // /// @param from The current owner of the RFT
- // /// @param tokenId The RFT to transfer
- // /// @dev EVM selector for this function is: 0x79cc6790,
- // /// or in textual repr: burnFrom(address,uint256)
- // function burnFrom(address from, uint256 tokenId) external;
-
- /// @notice Burns a specific ERC721 token.
- /// @dev Throws unless `msg.sender` is the current owner or an authorized
- /// operator for this RFT. Throws if `from` is not the current owner. Throws
- /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
- /// Throws if RFT pieces have multiple owners.
- /// @param from The current owner of the RFT
- /// @param tokenId The RFT to transfer
- /// @dev EVM selector for this function is: 0xbb2f5a58,
- /// or in textual repr: burnFromCross((address,uint256),uint256)
- function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
-
- /// @notice Returns next free RFT ID.
- /// @dev EVM selector for this function is: 0x75794a3c,
- /// or in textual repr: nextTokenId()
- function nextTokenId() external view returns (uint256);
-
- // /// @notice Function to mint multiple tokens.
- // /// @dev `tokenIds` should be an array of consecutive numbers and first number
- // /// should be obtained with `nextTokenId` method
- // /// @param to The new owner
- // /// @param tokenIds IDs of the minted RFTs
- // /// @dev EVM selector for this function is: 0x44a9945e,
- // /// or in textual repr: mintBulk(address,uint256[])
- // function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
-
- /// @notice Function to mint a token.
- /// @param tokenProperties Properties of minted token
- /// @dev EVM selector for this function is: 0xdf7a5db7,
- /// or in textual repr: mintBulkCross((((address,uint256),uint128)[],(string,bytes)[])[])
- function mintBulkCross(MintTokenData[] memory tokenProperties) external returns (bool);
-
- // /// @notice Function to mint multiple tokens with the given tokenUris.
- // /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
- // /// numbers and first number should be obtained with `nextTokenId` method
- // /// @param to The new owner
- // /// @param tokens array of pairs of token ID and token URI for minted tokens
- // /// @dev EVM selector for this function is: 0x36543006,
- // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
- // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
-
- /// @notice Function to mint a token.
- /// @param to The new owner crossAccountId
- /// @param properties Properties of minted token
- /// @return uint256 The id of the newly minted token
- /// @dev EVM selector for this function is: 0xb904db03,
- /// or in textual repr: mintCross((address,uint256),(string,bytes)[])
- function mintCross(CrossAddress memory to, Property[] memory properties) external returns (uint256);
-
- /// Returns EVM address for refungible token
- ///
- /// @param token ID of the token
- /// @dev EVM selector for this function is: 0xab76fac6,
- /// or in textual repr: tokenContractAddress(uint256)
- function tokenContractAddress(uint256 token) external view returns (address);
-
- /// @notice Returns collection helper contract address
- /// @dev EVM selector for this function is: 0x1896cce6,
- /// or in textual repr: collectionHelperAddress()
- function collectionHelperAddress() external view returns (address);
-}
-
-/// Data for creation token with uri.
-struct TokenUri {
- /// Id of new token.
- uint256 id;
- /// Uri of new token.
- string uri;
-}
-
-/// Token minting parameters
-struct MintTokenData {
- /// Minted token owner and number of pieces
- OwnerPieces[] owners;
- /// Minted token properties
- Property[] properties;
-}
-
-/// Token minting parameters
-struct OwnerPieces {
- /// Minted token owner
- CrossAddress owner;
- /// Number of token pieces
- uint128 pieces;
-}
-
-/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
-/// @dev See https://eips.ethereum.org/EIPS/eip-721
-/// @dev the ERC-165 identifier for this interface is 0x780e9d63
-interface ERC721Enumerable is Dummy, ERC165 {
- /// @notice Enumerate valid RFTs
- /// @param index A counter less than `totalSupply()`
- /// @return The token identifier for the `index`th NFT,
- /// (sort order not specified)
- /// @dev EVM selector for this function is: 0x4f6ccce7,
- /// or in textual repr: tokenByIndex(uint256)
- function tokenByIndex(uint256 index) external view returns (uint256);
-
- /// Not implemented
- /// @dev EVM selector for this function is: 0x2f745c59,
- /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
- function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
-
- /// @notice Count RFTs tracked by this contract
- /// @return A count of valid RFTs tracked by this contract, where each one of
- /// them has an assigned and queryable owner not equal to the zero address
- /// @dev EVM selector for this function is: 0x18160ddd,
- /// or in textual repr: totalSupply()
- function totalSupply() external view returns (uint256);
-}
-
-/// @dev inlined interface
-interface ERC721Events {
- event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
- event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
- event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-}
-
-/// @title ERC-721 Non-Fungible Token Standard
-/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
-interface ERC721 is Dummy, ERC165, ERC721Events {
- /// @notice Count all RFTs assigned to an owner
- /// @dev RFTs assigned to the zero address are considered invalid, and this
- /// function throws for queries about the zero address.
- /// @param owner An address for whom to query the balance
- /// @return The number of RFTs owned by `owner`, possibly zero
- /// @dev EVM selector for this function is: 0x70a08231,
- /// or in textual repr: balanceOf(address)
- function balanceOf(address owner) external view returns (uint256);
-
- /// @notice Find the owner of an RFT
- /// @dev RFTs assigned to zero address are considered invalid, and queries
- /// about them do throw.
- /// Returns special 0xffffffffffffffffffffffffffffffffffffffff address for
- /// the tokens that are partially owned.
- /// @param tokenId The identifier for an RFT
- /// @return The address of the owner of the RFT
- /// @dev EVM selector for this function is: 0x6352211e,
- /// or in textual repr: ownerOf(uint256)
- function ownerOf(uint256 tokenId) external view returns (address);
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0xb88d4fde,
- /// or in textual repr: safeTransferFrom(address,address,uint256,bytes)
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId,
- bytes memory data
- ) external;
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0x42842e0e,
- /// or in textual repr: safeTransferFrom(address,address,uint256)
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external;
-
- /// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE
- /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
- /// THEY MAY BE PERMANENTLY LOST
- /// @dev Throws unless `msg.sender` is the current owner or an authorized
- /// operator for this RFT. Throws if `from` is not the current owner. Throws
- /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
- /// Throws if RFT pieces have multiple owners.
- /// @param from The current owner of the NFT
- /// @param to The new owner
- /// @param tokenId The NFT to transfer
- /// @dev EVM selector for this function is: 0x23b872dd,
- /// or in textual repr: transferFrom(address,address,uint256)
- function transferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external;
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0x095ea7b3,
- /// or in textual repr: approve(address,uint256)
- function approve(address approved, uint256 tokenId) external;
-
- /// @notice Sets or unsets the approval of a given operator.
- /// The `operator` is allowed to transfer all token pieces of the `caller` on their behalf.
- /// @param operator Operator
- /// @param approved Should operator status be granted or revoked?
- /// @dev EVM selector for this function is: 0xa22cb465,
- /// or in textual repr: setApprovalForAll(address,bool)
- function setApprovalForAll(address operator, bool approved) external;
-
- /// @dev Not implemented
- /// @dev EVM selector for this function is: 0x081812fc,
- /// or in textual repr: getApproved(uint256)
- function getApproved(uint256 tokenId) external view returns (address);
-
- /// @notice Tells whether the given `owner` approves the `operator`.
- /// @dev EVM selector for this function is: 0xe985e9c5,
- /// or in textual repr: isApprovedForAll(address,address)
- function isApprovedForAll(address owner, address operator) external view returns (bool);
-}
-
-interface UniqueRefungible is
- Dummy,
- ERC165,
- ERC721,
- ERC721Enumerable,
- ERC721UniqueExtensions,
- ERC721UniqueMintable,
- ERC721Burnable,
- ERC721Metadata,
- Collection,
- TokenProperties
-{}
js-packages/tests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/api/UniqueRefungibleToken.sol
+++ /dev/null
@@ -1,181 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
- function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x5755c3f2
-interface ERC1633 is Dummy, ERC165 {
- /// @dev EVM selector for this function is: 0x80a54001,
- /// or in textual repr: parentToken()
- function parentToken() external view returns (address);
-
- /// @dev EVM selector for this function is: 0xd7f083f3,
- /// or in textual repr: parentTokenId()
- function parentTokenId() external view returns (uint256);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0xedd3a564
-interface ERC20UniqueExtensions is Dummy, ERC165 {
- /// @dev Function to check the amount of tokens that an owner allowed to a spender.
- /// @param owner crossAddress The address which owns the funds.
- /// @param spender crossAddress The address which will spend the funds.
- /// @return A uint256 specifying the amount of tokens still available for the spender.
- /// @dev EVM selector for this function is: 0xe0af4bd7,
- /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
- function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
-
- // /// @dev Function that burns an amount of the token of a given account,
- // /// deducting from the sender's allowance for said account.
- // /// @param from The account whose tokens will be burnt.
- // /// @param amount The amount that will be burnt.
- // /// @dev EVM selector for this function is: 0x79cc6790,
- // /// or in textual repr: burnFrom(address,uint256)
- // function burnFrom(address from, uint256 amount) external returns (bool);
-
- /// @dev Function that burns an amount of the token of a given account,
- /// deducting from the sender's allowance for said account.
- /// @param from The account whose tokens will be burnt.
- /// @param amount The amount that will be burnt.
- /// @dev EVM selector for this function is: 0xbb2f5a58,
- /// or in textual repr: burnFromCross((address,uint256),uint256)
- function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
-
- /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
- /// Beware that changing an allowance with this method brings the risk that someone may use both the old
- /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
- /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
- /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
- /// @param spender The crossaccount which will spend the funds.
- /// @param amount The amount of tokens to be spent.
- /// @dev EVM selector for this function is: 0x0ecd0ab0,
- /// or in textual repr: approveCross((address,uint256),uint256)
- function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
-
- /// @notice Balance of account
- /// @param owner An cross address for whom to query the balance
- /// @return The number of fingibles owned by `owner`, possibly zero
- /// @dev EVM selector for this function is: 0xec069398,
- /// or in textual repr: balanceOfCross((address,uint256))
- function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
- /// @dev Function that changes total amount of the tokens.
- /// Throws if `msg.sender` doesn't owns all of the tokens.
- /// @param amount New total amount of the tokens.
- /// @dev EVM selector for this function is: 0xd2418ca7,
- /// or in textual repr: repartition(uint256)
- function repartition(uint256 amount) external returns (bool);
-
- /// @dev Transfer token for a specified address
- /// @param to The crossaccount to transfer to.
- /// @param amount The amount to be transferred.
- /// @dev EVM selector for this function is: 0x2ada85ff,
- /// or in textual repr: transferCross((address,uint256),uint256)
- function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
- /// @dev Transfer tokens from one address to another
- /// @param from The address which you want to send tokens from
- /// @param to The address which you want to transfer to
- /// @param amount the amount of tokens to be transferred
- /// @dev EVM selector for this function is: 0xd5cf430b,
- /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
- function transferFromCross(
- CrossAddress memory from,
- CrossAddress memory to,
- uint256 amount
- ) external returns (bool);
-}
-
-/// Cross account struct
-struct CrossAddress {
- address eth;
- uint256 sub;
-}
-
-/// @dev inlined interface
-interface ERC20Events {
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @title Standard ERC20 token
-///
-/// @dev Implementation of the basic standard token.
-/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
- /// @return the name of the token.
- /// @dev EVM selector for this function is: 0x06fdde03,
- /// or in textual repr: name()
- function name() external view returns (string memory);
-
- /// @return the symbol of the token.
- /// @dev EVM selector for this function is: 0x95d89b41,
- /// or in textual repr: symbol()
- function symbol() external view returns (string memory);
-
- /// @dev Total number of tokens in existence
- /// @dev EVM selector for this function is: 0x18160ddd,
- /// or in textual repr: totalSupply()
- function totalSupply() external view returns (uint256);
-
- /// @dev Not supported
- /// @dev EVM selector for this function is: 0x313ce567,
- /// or in textual repr: decimals()
- function decimals() external view returns (uint8);
-
- /// @dev Gets the balance of the specified address.
- /// @param owner The address to query the balance of.
- /// @return An uint256 representing the amount owned by the passed address.
- /// @dev EVM selector for this function is: 0x70a08231,
- /// or in textual repr: balanceOf(address)
- function balanceOf(address owner) external view returns (uint256);
-
- /// @dev Transfer token for a specified address
- /// @param to The address to transfer to.
- /// @param amount The amount to be transferred.
- /// @dev EVM selector for this function is: 0xa9059cbb,
- /// or in textual repr: transfer(address,uint256)
- function transfer(address to, uint256 amount) external returns (bool);
-
- /// @dev Transfer tokens from one address to another
- /// @param from address The address which you want to send tokens from
- /// @param to address The address which you want to transfer to
- /// @param amount uint256 the amount of tokens to be transferred
- /// @dev EVM selector for this function is: 0x23b872dd,
- /// or in textual repr: transferFrom(address,address,uint256)
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) external returns (bool);
-
- /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
- /// Beware that changing an allowance with this method brings the risk that someone may use both the old
- /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
- /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
- /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
- /// @param spender The address which will spend the funds.
- /// @param amount The amount of tokens to be spent.
- /// @dev EVM selector for this function is: 0x095ea7b3,
- /// or in textual repr: approve(address,uint256)
- function approve(address spender, uint256 amount) external returns (bool);
-
- /// @dev Function to check the amount of tokens that an owner allowed to a spender.
- /// @param owner address The address which owns the funds.
- /// @param spender address The address which will spend the funds.
- /// @return A uint256 specifying the amount of tokens still available for the spender.
- /// @dev EVM selector for this function is: 0xdd62ed3e,
- /// or in textual repr: allowance(address,address)
- function allowance(address owner, address spender) external view returns (uint256);
-}
-
-interface UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions, ERC1633 {}
js-packages/tests/src/eth/base.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/base.test.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-
-
-describe('Contract calls', () => {
- let donor: IKeyringPair;
-
- before(async function () {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Call of simple contract fee is less than 0.2 UNQ', async ({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const flipper = await helper.eth.deployFlipper(deployer);
-
- const cost = await helper.eth.calculateFee({Ethereum: deployer}, () => flipper.methods.flip().send({from: deployer}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
- });
-
- itEth('Balance transfer fee is less than 0.2 UNQ', async ({helper}) => {
- const userA = await helper.eth.createAccountWithBalance(donor);
- const userB = helper.eth.createAccount();
- const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({
- from: userA,
- to: userB,
- value: '1000000',
- gas: helper.eth.DEFAULT_GAS,
- }));
- const balanceB = await helper.balance.getEthereum(userB);
- expect(cost - balanceB < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
- });
-
- itEth('NFT transfer is close to 0.15 UNQ', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const [alice] = await helper.arrange.createAccounts([10n], donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, tokenId).send(caller));
-
- const fee = Number(cost) / Number(helper.balance.getOneTokenNominal());
- const expectedFee = 0.15;
- const tolerance = 0.001;
-
- expect(Math.abs(fee - expectedFee)).to.be.lessThan(tolerance);
- });
-});
-
-describe('ERC165 tests', () => {
- // https://eips.ethereum.org/EIPS/eip-165
-
- let erc721MetadataCompatibleNftCollectionId: number;
- let simpleNftCollectionId: number;
- let minter: string;
-
- const BASE_URI = 'base/';
-
- async function checkInterface(helper: EthUniqueHelper, interfaceId: string, simpleResult: boolean, compatibleResult: boolean) {
- const simple = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(simpleNftCollectionId), 'nft', minter);
- const compatible = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(erc721MetadataCompatibleNftCollectionId), 'nft', minter);
-
- expect(await simple.methods.supportsInterface(interfaceId).call()).to.equal(simpleResult, `empty (not ERC721Metadata compatible) NFT collection returns not ${simpleResult}`);
- expect(await compatible.methods.supportsInterface(interfaceId).call()).to.equal(compatibleResult, `ERC721Metadata compatible NFT collection returns not ${compatibleResult}`);
- }
-
- before(async () => {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- const [alice] = await helper.arrange.createAccounts([10n], donor);
- ({collectionId: simpleNftCollectionId} = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}));
- minter = await helper.eth.createAccountWithBalance(donor);
- ({collectionId: erc721MetadataCompatibleNftCollectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(minter, 'n', 'd', 'p', BASE_URI));
- });
- });
-
- itEth('nonexistent interfaceID - 0xffffffff - always false', async ({helper}) => {
- await checkInterface(helper, '0xffffffff', false, false);
- });
-
- itEth('ERC721 - 0x780e9d63 - support', async ({helper}) => {
- await checkInterface(helper, '0x780e9d63', true, true);
- });
-
- itEth('ERC721Metadata - 0x5b5e139f - support', async ({helper}) => {
- await checkInterface(helper, '0x5b5e139f', false, true);
- });
-
- itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => {
- await checkInterface(helper, '0x780e9d63', true, true);
- });
-
- itEth.skip('ERC721UniqueExtensions support', async ({helper}) => {
- await checkInterface(helper, '0xb74c26b7', true, true);
- });
-
- itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {
- await checkInterface(helper, '0x42966c68', true, true);
- });
-
- itEth('ERC165 - 0x01ffc9a7 - support', async ({helper}) => {
- await checkInterface(helper, '0x01ffc9a7', true, true);
- });
-});
js-packages/tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/collectionAdmin.test.ts
+++ /dev/null
@@ -1,469 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect} from 'chai';
-import {Pallets} from '../util/index.js';
-import type {IEthCrossAccountId} from '@unique/playgrounds/src/types.js';
-import {usingEthPlaygrounds, itEth} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import {CreateCollectionData} from './util/playgrounds/types.js';
-
-async function recordEthFee(helper: EthUniqueHelper, userAddress: string, call: () => Promise<any>) {
- const before = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));
- await call();
- await helper.wait.newBlocks(1);
- const after = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));
-
- expect(after < before).to.be.true;
-
- return before - after;
-}
-
-describe('Add collection admins', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`can add account admin by owner for ${testCase.mode}`, testCase.requiredPallets, async ({helper, privateKey}) => {
- // arrange
- const owner = await helper.eth.createAccountWithBalance(donor);
- const adminSub = await privateKey('//admin2');
- const adminEth = helper.eth.createAccount().toLowerCase();
-
- const adminDeprecated = helper.eth.createAccount().toLowerCase();
- const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
-
- const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, true);
-
- // Check isOwnerOrAdminCross returns false:
- expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.false;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.false;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.false;
-
- // Soft-deprecated: can addCollectionAdmin
- await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();
- // Can addCollectionAdminCross for substrate and ethereum address
- await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
- await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
-
- // 1. Expect api.rpc.unique.adminlist returns admins:
- const adminListRpc = await helper.collection.getAdmins(collectionId);
- expect(adminListRpc).to.has.length(3);
- expect(adminListRpc).to.be.deep.contain.members([{Substrate: adminSub.address}, {Ethereum: adminEth}, {Ethereum: adminDeprecated}]);
-
- // 2. Expect methods.collectionAdmins == api.rpc.unique.adminlist
- let adminListEth = await collectionEvm.methods.collectionAdmins().call();
- adminListEth = adminListEth.map((element: IEthCrossAccountId) => helper.address.convertCrossAccountFromEthCrossAccount(element));
- expect(adminListRpc).to.be.like(adminListEth);
-
- // 3. check isOwnerOrAdminCross returns true:
- expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.true;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.true;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.true;
- });
- });
-
- itEth('cross account admin can mint', async ({helper}) => {
- // arrange: create collection and accounts
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', 'uri');
- const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
- const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
- const [adminSub] = await helper.arrange.createAccounts([100n], donor);
- const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- // cannot mint while not admin
- await expect(collectionEvm.methods.mint(owner).send({from: adminEth})).to.be.rejected;
- await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
-
- // admin (sub and eth) can mint token:
- await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
- await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
- await collectionEvm.methods.mint(owner).send({from: adminEth});
- await helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}});
-
- expect(await helper.collection.getLastTokenId(collectionId)).to.eq(2);
- });
-
- itEth('cannot add invalid cross account admin', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const [admin] = await helper.arrange.createAccounts([100n, 100n], donor);
-
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- const adminCross = {
- eth: helper.address.substrateToEth(admin.address),
- sub: admin.addressRaw,
- };
- await expect(collectionEvm.methods.addCollectionAdminCross(adminCross).send()).to.be.rejected;
- });
-
- itEth('can verify owner with methods.isOwnerOrAdmin[Cross]', async ({helper, privateKey}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const adminDeprecated = helper.eth.createAccount();
- const admin1Cross = helper.ethCrossAccount.fromKeyringPair(await privateKey('admin'));
- const admin2Cross = helper.ethCrossAccount.fromAddress(helper.address.substrateToEth((await privateKey('admin3')).address));
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- // Soft-deprecated:
- expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.false;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.false;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.false;
-
- await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();
- await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send();
- await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send();
-
- // Soft-deprecated: isOwnerOrAdmin returns true
- expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.true;
- // Expect isOwnerOrAdminCross return true
- expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.true;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.true;
- });
-
- // Soft-deprecated
- itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const admin = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
- await collectionEvm.methods.addCollectionAdmin(admin).send();
-
- const user = helper.eth.createAccount();
- await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin}))
- .to.be.rejectedWith('NoPermission');
-
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(1);
- expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
- .to.be.eq(admin.toLocaleLowerCase());
- });
-
- // Soft-deprecated
- itEth('(!negative tests!) Add admin by USER is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const notAdmin = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- const user = helper.eth.createAccount();
- await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin}))
- .to.be.rejectedWith('NoPermission');
-
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(0);
- });
-
- itEth('(!negative tests!) Add [cross] admin by ADMIN is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const [admin, notAdmin] = await helper.arrange.createAccounts([10n, 10n], donor);
- const adminCross = helper.ethCrossAccount.fromKeyringPair(admin);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- await collectionEvm.methods.addCollectionAdminCross(adminCross).send();
-
- const notAdminCross = helper.ethCrossAccount.fromKeyringPair(notAdmin);
- await expect(collectionEvm.methods.addCollectionAdminCross(notAdminCross).call({from: adminCross.eth}))
- .to.be.rejectedWith('NoPermission');
-
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(1);
-
- const admin0Cross = helper.ethCrossAccount.fromKeyringPair(adminList[0]);
- expect(admin0Cross.eth.toLocaleLowerCase())
- .to.be.eq(adminCross.eth.toLocaleLowerCase());
- });
-
- itEth('(!negative tests!) Add [cross] admin by USER is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const notAdmin0 = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- const [notAdmin1] = await helper.arrange.createAccounts([10n], donor);
- const notAdmin1Cross = helper.ethCrossAccount.fromKeyringPair(notAdmin1);
- await expect(collectionEvm.methods.addCollectionAdminCross(notAdmin1Cross).call({from: notAdmin0}))
- .to.be.rejectedWith('NoPermission');
-
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(0);
- });
-});
-
-describe('Remove collection admins', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- // Soft-deprecated
- itEth('Remove admin by owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const newAdmin = helper.eth.createAccount();
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
- await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
-
- {
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(1);
- expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
- .to.be.eq(newAdmin.toLocaleLowerCase());
- }
-
- await collectionEvm.methods.removeCollectionAdmin(newAdmin).send();
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(0);
- });
-
- itEth('Remove [cross] admin by owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const [adminSub] = await helper.arrange.createAccounts([10n], donor);
- const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
- const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
- await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
-
- {
- const adminList = await helper.collection.getAdmins(collectionId);
- expect(adminList).to.deep.include({Substrate: adminSub.address});
- expect(adminList).to.deep.include({Ethereum: adminEth});
- }
-
- await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send();
- await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send();
- const adminList = await helper.collection.getAdmins(collectionId);
- expect(adminList.length).to.be.eq(0);
-
- // Non admin cannot mint:
- await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
- await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected;
- });
-
- // Soft-deprecated
- itEth('(!negative tests!) Remove admin by ADMIN is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- const admin0 = await helper.eth.createAccountWithBalance(donor);
- await collectionEvm.methods.addCollectionAdmin(admin0).send();
- const admin1 = await helper.eth.createAccountWithBalance(donor);
- await collectionEvm.methods.addCollectionAdmin(admin1).send();
-
- await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0}))
- .to.be.rejectedWith('NoPermission');
- {
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(2);
- expect(adminList.toString().toLocaleLowerCase())
- .to.be.deep.contains(admin0.toLocaleLowerCase())
- .to.be.deep.contains(admin1.toLocaleLowerCase());
- }
- });
-
- // Soft-deprecated
- itEth('(!negative tests!) Remove admin by USER is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- const admin = await helper.eth.createAccountWithBalance(donor);
- await collectionEvm.methods.addCollectionAdmin(admin).send();
- const notAdmin = helper.eth.createAccount();
-
- await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin}))
- .to.be.rejectedWith('NoPermission');
- {
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
- .to.be.eq(admin.toLocaleLowerCase());
- expect(adminList.length).to.be.eq(1);
- }
- });
-
- itEth('(!negative tests!) Remove [cross] admin by ADMIN is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const [admin1] = await helper.arrange.createAccounts([10n], donor);
- const admin1Cross = helper.ethCrossAccount.fromKeyringPair(admin1);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send();
-
- const [admin2] = await helper.arrange.createAccounts([10n], donor);
- const admin2Cross = helper.ethCrossAccount.fromKeyringPair(admin2);
- await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send();
-
- await expect(collectionEvm.methods.removeCollectionAdminCross(admin1Cross).call({from: admin2Cross.eth}))
- .to.be.rejectedWith('NoPermission');
-
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(2);
- expect(adminList.toString().toLocaleLowerCase())
- .to.be.deep.contains(admin1.address.toLocaleLowerCase())
- .to.be.deep.contains(admin2.address.toLocaleLowerCase());
- });
-
- itEth('(!negative tests!) Remove [cross] admin by USER is not allowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const [adminSub] = await helper.arrange.createAccounts([10n], donor);
- const adminSubCross = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- await collectionEvm.methods.addCollectionAdminCross(adminSubCross).send();
- const notAdminEth = await helper.eth.createAccountWithBalance(donor);
-
- await expect(collectionEvm.methods.removeCollectionAdminCross(adminSubCross).call({from: notAdminEth}))
- .to.be.rejectedWith('NoPermission');
-
- const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
- expect(adminList.length).to.be.eq(1);
- expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())
- .to.be.eq(adminSub.address.toLocaleLowerCase());
- });
-});
-
-// Soft-deprecated
-describe('Change owner tests', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Change owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const newOwner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- await collectionEvm.methods.changeCollectionOwner(newOwner).send();
-
- expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;
- expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.true;
- });
-
- itEth('change owner call fee', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const newOwner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
- const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.changeCollectionOwner(newOwner).send());
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- expect(cost > 0);
- });
-
- itEth('(!negative tests!) call setOwner by non owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const newOwner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- await expect(collectionEvm.methods.changeCollectionOwner(newOwner).send({from: newOwner})).to.be.rejected;
- expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.false;
- });
-});
-
-describe('Change substrate owner tests', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Change owner [cross]', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ownerEth = await helper.eth.createAccountWithBalance(donor);
- const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
- const [ownerSub] = await helper.arrange.createAccounts([10n], donor);
- const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
-
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.false;
-
- // Can set ethereum owner:
- await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossEth).send({from: owner});
- expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossEth).call()).to.be.true;
- expect(await helper.collection.getData(collectionId))
- .to.have.property('normalizedOwner').that.is.eq(helper.address.ethToSubstrate(ownerEth));
-
- // Can set Substrate owner:
- await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossSub).send({from: ownerEth});
- expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.true;
- expect(await helper.collection.getData(collectionId))
- .to.have.property('normalizedOwner').that.is.eq(helper.address.normalizeSubstrate(ownerSub.address));
- });
-
- itEth.skip('change owner call fee', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const [newOwner] = await helper.arrange.createAccounts([10n], donor);
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send());
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- expect(cost > 0);
- });
-
- itEth('(!negative tests!) call setOwner by non owner [cross]', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const otherReceiver = await helper.eth.createAccountWithBalance(donor);
- const [newOwner] = await helper.arrange.createAccounts([10n], donor);
- const newOwnerCross = helper.ethCrossAccount.fromKeyringPair(newOwner);
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- await expect(collectionEvm.methods.changeCollectionOwnerCross(newOwnerCross).send({from: otherReceiver})).to.be.rejected;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.false;
- });
-});
js-packages/tests/src/eth/collectionHelperAddress.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/collectionHelperAddress.test.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {COLLECTION_HELPER, Pallets} from '../util/index.js';
-
-describe('[eth]CollectionHelperAddress test: ERC20/ERC721 ', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('NFT', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress: nftCollectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
- const nftCollection = await helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);
-
- expect((await nftCollection.methods.collectionHelperAddress().call())
- .toString().toLowerCase()).to.be.equal(COLLECTION_HELPER);
- });
-
- itEth.ifWithPallets('RFT ', [Pallets.ReFungible], async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress: rftCollectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
-
- const rftCollection = await helper.ethNativeContract.collection(rftCollectionAddress, 'rft', owner);
- expect((await rftCollection.methods.collectionHelperAddress().call())
- .toString().toLowerCase()).to.be.equal(COLLECTION_HELPER);
- });
-
- itEth('FT', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', 18, 'absolutely anything', 'ROC');
- const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- expect((await collection.methods.collectionHelperAddress().call())
- .toString().toLowerCase()).to.be.equal(COLLECTION_HELPER);
- });
-
- itEth('[collectionHelpers] convert collectionId into address', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionId = 7;
- const collectionAddress = helper.ethAddress.fromCollectionId(collectionId);
- const helperContract = await helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await helperContract.methods.collectionAddress(collectionId).call()).to.be.equal(collectionAddress);
- expect(parseInt(await helperContract.methods.collectionId(collectionAddress).call())).to.be.equal(collectionId);
- });
-
-});
js-packages/tests/src/eth/collectionLimits.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/collectionLimits.test.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField, CreateCollectionData} from './util/playgrounds/types.js';
-
-
-describe('Can set collection limits', () => {
- let donor: IKeyringPair;
-
- before(async () => {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {case: 'nft' as const},
- {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {case: 'ft' as const},
- ].map(testCase =>
- itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'FLO', testCase.case, 18)).send();
- const limits = {
- accountTokenOwnershipLimit: 1000,
- sponsoredDataSize: 1024,
- sponsoredDataRateLimit: 30,
- tokenLimit: 1000000,
- sponsorTransferTimeout: 6,
- sponsorApproveTimeout: 6,
- ownerCanTransfer: 1,
- ownerCanDestroy: 0,
- transfersEnabled: 0,
- };
-
- const expectedLimits = {
- accountTokenOwnershipLimit: 1000,
- sponsoredDataSize: 1024,
- sponsoredDataRateLimit: {blocks: 30},
- tokenLimit: 1000000,
- sponsorTransferTimeout: 6,
- sponsorApproveTimeout: 6,
- ownerCanTransfer: true,
- ownerCanDestroy: false,
- transfersEnabled: false,
- };
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: limits.accountTokenOwnershipLimit}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataSize, value: {status: true, value: limits.sponsoredDataSize}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: limits.sponsoredDataRateLimit}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.TokenLimit, value: {status: true, value: limits.tokenLimit}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsorTransferTimeout, value: {status: true, value: limits.sponsorTransferTimeout}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsorApproveTimeout, value: {status: true, value: limits.sponsorApproveTimeout}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: limits.ownerCanTransfer}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanDestroy, value: {status: true, value: limits.ownerCanDestroy}}).send();
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.TransferEnabled, value: {status: true, value: limits.transfersEnabled}}).send();
-
- // Check limits from sub:
- const data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.limits).to.deep.eq(expectedLimits);
- expect(await helper.collection.getEffectiveLimits(collectionId)).to.deep.eq(expectedLimits);
- // Check limits from eth:
- const limitsEvm = await collectionEvm.methods.collectionLimits().call({from: owner});
- expect(limitsEvm).to.have.length(9);
- expect(limitsEvm[0]).to.deep.eq([CollectionLimitField.AccountTokenOwnership.toString(), [true, limits.accountTokenOwnershipLimit.toString()]]);
- expect(limitsEvm[1]).to.deep.eq([CollectionLimitField.SponsoredDataSize.toString(), [true, limits.sponsoredDataSize.toString()]]);
- expect(limitsEvm[2]).to.deep.eq([CollectionLimitField.SponsoredDataRateLimit.toString(), [true, limits.sponsoredDataRateLimit.toString()]]);
- expect(limitsEvm[3]).to.deep.eq([CollectionLimitField.TokenLimit.toString(), [true, limits.tokenLimit.toString()]]);
- expect(limitsEvm[4]).to.deep.eq([CollectionLimitField.SponsorTransferTimeout.toString(), [true, limits.sponsorTransferTimeout.toString()]]);
- expect(limitsEvm[5]).to.deep.eq([CollectionLimitField.SponsorApproveTimeout.toString(), [true, limits.sponsorApproveTimeout.toString()]]);
- expect(limitsEvm[6]).to.deep.eq([CollectionLimitField.OwnerCanTransfer.toString(), [true, limits.ownerCanTransfer.toString()]]);
- expect(limitsEvm[7]).to.deep.eq([CollectionLimitField.OwnerCanDestroy.toString(), [true, limits.ownerCanDestroy.toString()]]);
- expect(limitsEvm[8]).to.deep.eq([CollectionLimitField.TransferEnabled.toString(), [true, limits.transfersEnabled.toString()]]);
- }));
-});
-
-describe('Cannot set invalid collection limits', () => {
- let donor: IKeyringPair;
-
- before(async () => {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {case: 'nft' as const},
- {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {case: 'ft' as const},
- ].map(testCase =>
- itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
- const invalidLimits = {
- accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),
- transfersEnabled: 3,
- };
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'ISNI', testCase.case, 18)).send();
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
-
- // Cannot set non-existing limit
- await expect(collectionEvm.methods
- .setCollectionLimit({field: 9, value: {status: true, value: 1}})
- .call()).to.be.rejectedWith('Returned error: VM Exception while processing transaction: revert value not convertible into enum "CollectionLimitField"');
-
- // Cannot disable limits
- await expect(collectionEvm.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: false, value: 0}})
- .call()).to.be.rejectedWith('user can\'t disable limits');
-
- await expect(collectionEvm.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: invalidLimits.accountTokenOwnershipLimit}})
- .call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);
-
- await expect(collectionEvm.methods
- .setCollectionLimit({field: CollectionLimitField.TransferEnabled, value: {status: true, value: 3}})
- .call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);
-
- expect(() => collectionEvm.methods
- .setCollectionLimit({field: CollectionLimitField.SponsoredDataSize, value: {status: true, value: -1}}).send()).to.throw('value out-of-bounds');
- }));
-
- [
- {case: 'nft' as const, requiredPallets: []},
- {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {case: 'ft' as const, requiredPallets: []},
- ].map(testCase =>
- itEth.ifWithPallets(`Non-owner and non-admin cannot set collection limits for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const nonOwner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'FLO', testCase.case, 18)).send();
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
- await expect(collectionEvm.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call({from: nonOwner}))
- .to.be.rejectedWith('NoPermission');
-
- await expect(collectionEvm.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .send({from: nonOwner}))
- .to.be.rejected;
- }));
-});
js-packages/tests/src/eth/collectionProperties.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/collectionProperties.test.ts
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import {Pallets} from '../util/index.js';
-import type {IProperty, ITokenPropertyPermission} from '@unique/playgrounds/src/types.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-describe('EVM collection properties', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await _helper.arrange.createAccounts([50n], donor);
- });
- });
-
- // Soft-deprecated: setCollectionProperty
- [
- {method: 'setCollectionProperties', mode: 'nft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
- {method: 'setCollectionProperties', mode: 'rft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
- {method: 'setCollectionProperties', mode: 'ft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
- {method: 'setCollectionProperty', mode: 'nft' as const, methodParams: ['testKey', Buffer.from('testValue')], expectedProps: [{key: 'testKey', value: 'testValue'}]},
- ].map(testCase =>
- itEth.ifWithPallets(`Collection properties can be set: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []});
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'setCollectionProperty');
-
- // collectionProperties returns an empty array if no properties:
- expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like([]);
- expect(await collectionEvm.methods.collectionProperties(['NonExistingKey']).call()).to.be.like([]);
-
- await collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller});
-
- const raw = (await collection.getData())?.raw;
- expect(raw.properties).to.deep.equal(testCase.expectedProps);
-
- // collectionProperties returns properties:
- expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like(testCase.expectedProps.map(prop => helper.ethProperty.property(prop.key, prop.value)));
- }));
-
- itEth('Cannot set invalid properties', async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []});
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- await expect(contract.methods.setCollectionProperties([{key: '', value: Buffer.from('val1')}]).send({from: caller})).to.be.rejected;
- await expect(contract.methods.setCollectionProperties([{key: 'déjà vu', value: Buffer.from('hmm...')}]).send({from: caller})).to.be.rejected;
- await expect(contract.methods.setCollectionProperties([{key: 'a'.repeat(257), value: Buffer.from('val3')}]).send({from: caller})).to.be.rejected;
- // TODO add more expects
- const raw = (await collection.getData())?.raw;
- expect(raw.properties).to.deep.equal([]);
- });
-
-
- // Soft-deprecated: deleteCollectionProperty
- [
- {method: 'deleteCollectionProperties', mode: 'nft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},
- {method: 'deleteCollectionProperties', mode: 'rft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},
- {method: 'deleteCollectionProperties', mode: 'ft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},
- {method: 'deleteCollectionProperty', mode: 'nft' as const, methodParams: ['testKey1'], expectedProps: [{key: 'testKey2', value: 'testValue2'}, {key: 'testKey3', value: 'testValue3'}]},
- ].map(testCase =>
- itEth.ifWithPallets(`Collection properties can be deleted: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
- const properties = [
- {key: 'testKey1', value: 'testValue1'},
- {key: 'testKey2', value: 'testValue2'},
- {key: 'testKey3', value: 'testValue3'}];
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties});
-
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'deleteCollectionProperty');
-
- await contract.methods[testCase.method](...testCase.methodParams).send({from: caller});
-
- const raw = (await collection.getData())?.raw;
-
- expect(raw.properties.length).to.equal(testCase.expectedProps.length);
- expect(raw.properties).to.deep.equal(testCase.expectedProps);
- }));
-
- [
- {method: 'deleteCollectionProperties', methodParams: [['testKey2']]},
- {method: 'deleteCollectionProperty', methodParams: ['testKey2']},
- ].map(testCase =>
- itEth(`cannot ${testCase.method}() of non-owned collections`, async ({helper}) => {
- const properties = [
- {key: 'testKey1', value: 'testValue1'},
- {key: 'testKey2', value: 'testValue2'},
- ];
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'deleteCollectionProperty');
-
- await expect(collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller})).to.be.rejected;
- expect(await collection.getProperties()).to.deep.eq(properties);
- }));
-
- itEth('Can be read', async({helper}) => {
- const caller = helper.eth.createAccount();
- const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: [{key: 'testKey', value: 'testValue'}]});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- const value = await contract.methods.collectionProperty('testKey').call();
- expect(value).to.equal(helper.getWeb3().utils.toHex('testValue'));
- });
-});
-
-describe('Supports ERC721Metadata', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {case: 'nft' as const},
- {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`ERC721Metadata property can be set for ${testCase.case} collection`, testCase.requiredPallets || [], async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const bruh = await helper.eth.createAccountWithBalance(donor);
-
- const BASE_URI = 'base/';
- const SUFFIX = 'suffix1';
- const URI = 'uri1';
-
- const collectionHelpers = await helper.ethNativeContract.collectionHelpers(caller);
- const creatorMethod = testCase.case === 'rft' ? 'createRFTCollection' : 'createNFTCollection';
-
- const {collectionId, collectionAddress} = await helper.eth[creatorMethod](caller, 'n', 'd', 'p');
- const bruhCross = helper.ethCrossAccount.fromAddress(bruh);
-
- const contract = await helper.ethNativeContract.collectionById(collectionId, testCase.case, caller);
- await contract.methods.addCollectionAdminCross(bruhCross).send(); // to check that admin will work too
-
- const collection1 = helper.nft.getCollectionObject(collectionId);
- const data1 = await collection1.getData();
- expect(data1?.raw.flags.erc721metadata).to.be.false;
- expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false;
-
- await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, BASE_URI)
- .send({from: bruh});
-
- expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true;
-
- const collection2 = helper.nft.getCollectionObject(collectionId);
- const data2 = await collection2.getData();
- expect(data2?.raw.flags.erc721metadata).to.be.true;
-
- const propertyPermissions = data2?.raw.tokenPropertyPermissions;
- expect(propertyPermissions?.length).to.equal(2);
-
- expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => tpp.key === 'URI' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner)).to.be.not.null;
-
- expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => tpp.key === 'URISuffix' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner)).to.be.not.null;
-
- expect(data2?.raw.properties?.find((property: IProperty) => property.key === 'baseURI' && property.value === BASE_URI)).to.be.not.null;
-
- const token1Result = await contract.methods.mint(bruh).send();
- const tokenId1 = token1Result.events.Transfer.returnValues.tokenId;
-
- expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI);
-
- await contract.methods.setProperties(tokenId1, [{key: 'URISuffix', value: Buffer.from(SUFFIX)}]).send();
- expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
-
- await contract.methods.setProperties(tokenId1, [{key: 'URI', value: Buffer.from(URI)}]).send();
- expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI);
-
- await contract.methods.deleteProperties(tokenId1, ['URI']).send();
- expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
-
- const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send();
- const tokenId2 = token2Result.events.Transfer.returnValues.tokenId;
-
- expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI);
-
- await contract.methods.deleteProperties(tokenId2, ['URI']).send();
- expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI);
-
- await contract.methods.setProperties(tokenId2, [{key: 'URISuffix', value: Buffer.from(SUFFIX)}]).send();
- expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI + SUFFIX);
- }));
-});
js-packages/tests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/collectionSponsoring.test.ts
+++ /dev/null
@@ -1,955 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index.js';
-import {itEth, expect} from './util/index.js';
-import {CollectionLimitField, TokenPermissionField} from './util/playgrounds/types.js';
-
-describe('evm nft collection sponsoring', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let nominal: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- // TODO: move to substrate tests
- itEth('sponsors mint transactions', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}});
- await collection.setSponsor(alice, alice.address);
- await collection.confirmSponsorship(alice);
-
- const minter = helper.eth.createAccount();
- expect(await helper.balance.getEthereum(minter)).to.equal(0n);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', minter);
-
- await collection.addToAllowList(alice, {Ethereum: minter});
-
- const result = await contract.methods.mint(minter).send();
-
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: minter,
- tokenId: '1',
- },
- },
- ]);
- });
-
- // TODO: Temprorary off. Need refactor
- // itWeb3('Set substrate sponsor', async ({api, web3, privateKeyWrapper}) => {
- // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- // const collectionHelpers = evmCollectionHelpers(web3, owner);
- // let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send();
- // const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
- // const sponsor = privateKeyWrapper('//Alice');
- // const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
-
- // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
- // result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});
- // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-
- // const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);
- // await submitTransactionAsync(sponsor, confirmTx);
- // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-
- // const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
- // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);
- // });
-
- [
- 'setCollectionSponsorCross',
- 'setCollectionSponsor', // Soft-deprecated
- ].map(testCase =>
- itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
-
- let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
- const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner, testCase === 'setCollectionSponsor');
-
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
- result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
- let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-
- await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
-
- sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
- }));
-
- [
- 'setCollectionSponsorCross',
- 'setCollectionSponsor', // Soft-deprecated
- ].map(testCase =>
- itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
-
- const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');
-
- const collectionSub = helper.nft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor');
-
- // Set collection sponsor:
- await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});
- let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
- expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
- // Account cannot confirm sponsorship if it is not set as a sponsor
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- // Sponsor can confirm sponsorship:
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
- sponsorship = (await collectionSub.getData())!.raw.sponsorship;
- expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
-
- // Create user with no balance:
- const user = helper.ethCrossAccount.createAccount();
- const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
-
- // Set collection permissions:
- const oldPermissions = (await collectionSub.getData())!.raw.permissions;
- expect(oldPermissions.mintMode).to.be.false;
- expect(oldPermissions.access).to.be.equal('Normal');
-
- await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
- await collectionEvm.methods.addToCollectionAllowListCross(user).send({from: owner});
- await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: 30}}).send();
-
- const newPermissions = (await collectionSub.getData())!.raw.permissions;
- expect(newPermissions.mintMode).to.be.true;
- expect(newPermissions.access).to.be.equal('AllowList');
-
- // Set token permissions
- await collectionEvm.methods.setTokenPropertyPermissions([
- ['key', [
- [TokenPermissionField.TokenOwner, true],
- ],
- ],
- ]).send({from: owner});
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
-
- // User can mint token without balance:
- {
- const result = await collectionEvm.methods.mintCross(user, [{key: 'key', value: Buffer.from('Value')}]).send({from: user.eth});
- const event = helper.eth.normalizeEvents(result.events)
- .find(event => event.event === 'Transfer');
-
- expect(event).to.be.deep.equal({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user.eth,
- tokenId: '1',
- },
- });
-
- // await collectionEvm.methods.setProperties(1, [{key: 'key', value: Buffer.from('Value1')}]).send({from: user.eth});
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
-
- expect(await collectionEvm.methods.properties(nextTokenId, []).call())
- .to.be.like([
- [
- 'key',
- '0x' + Buffer.from('Value').toString('hex'),
- ],
- ]);
- expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
- }
- }));
-
- itEth('Can sponsor [set token properties] via access list', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, false);
-
- // Set collection sponsor:
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
-
- // Sponsor can confirm sponsorship:
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
-
- // Create user with no balance:
- const user = helper.ethCrossAccount.createAccount();
- const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
-
- // Set collection permissions:
- await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
- await collectionEvm.methods.addToCollectionAllowListCross(user).send({from: owner});
- await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
- await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: 30}}).send();
-
- // Set token permissions
- await collectionEvm.methods.setTokenPropertyPermissions([
- ['key', [
- [TokenPermissionField.TokenOwner, true],
- ],
- ],
- ]).send({from: owner});
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
-
- // User can mint token without balance:
- {
- const result = await collectionEvm.methods.mintCross(user, []).send({from: user.eth});
- const event = helper.eth.normalizeEvents(result.events)
- .find(event => event.event === 'Transfer');
-
- expect(event).to.be.deep.equal({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user.eth,
- tokenId: '1',
- },
- });
-
- await collectionEvm.methods.setProperties(1, [{key: 'key', value: Buffer.from('Value')}]).send({from: user.eth});
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
-
- expect(await collectionEvm.methods.properties(nextTokenId, []).call())
- .to.be.like([
- [
- 'key',
- '0x' + Buffer.from('Value').toString('hex'),
- ],
- ]);
- expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
- }
- });
-
- // TODO: Temprorary off. Need refactor
- // itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => {
- // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- // const collectionHelpers = evmCollectionHelpers(web3, owner);
- // const result = await collectionHelpers.methods.createERC721MetadataCompatibleNFTCollection('Sponsor collection', '1', '1', '').send();
- // const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
- // const sponsor = privateKeyWrapper('//Alice');
- // const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
-
- // await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});
-
- // const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);
- // await submitTransactionAsync(sponsor, confirmTx);
-
- // const user = createEthAccount(web3);
- // const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- // expect(nextTokenId).to.be.equal('1');
-
- // await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
- // await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
- // await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
- // const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
- // const sponsorBalanceBefore = (await getBalance(api, [sponsor.address]))[0];
-
- // {
- // const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- // expect(nextTokenId).to.be.equal('1');
- // const result = await collectionEvm.methods.mintWithTokenURI(
- // user,
- // nextTokenId,
- // 'Test URI',
- // ).send({from: user});
- // const events = normalizeEvents(result.events);
-
- // expect(events).to.be.deep.equal([
- // {
- // address: collectionIdAddress,
- // event: 'Transfer',
- // args: {
- // from: '0x0000000000000000000000000000000000000000',
- // to: user,
- // tokenId: nextTokenId,
- // },
- // },
- // ]);
-
- // const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
- // const sponsorBalanceAfter = (await getBalance(api, [sponsor.address]))[0];
-
- // expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
- // expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
- // expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
- // }
- // });
-
- [
- 'setCollectionSponsorCross',
- 'setCollectionSponsor', // Soft-deprecated
- ].map(testCase =>
- itEth(`[${testCase}] Check that transaction via EVM spend money from sponsor address`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');
-
- const collectionSub = helper.nft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor');
- // Set collection sponsor:
- await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
- let collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
- collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-
- const user = helper.eth.createAccount();
- const userCross = helper.ethCrossAccount.fromAddress(user);
- await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
- const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
-
- const event = helper.eth.normalizeEvents(mintingResult.events)
- .find(event => event.event === 'Transfer');
- const address = helper.ethAddress.fromCollectionId(collectionId);
-
- expect(event).to.be.deep.equal({
- address,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user,
- tokenId: '1',
- },
- });
- expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- }));
-
- itEth('Can reassign collection sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
- const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
- const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');
- const collectionSub = helper.nft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- // Set and confirm sponsor:
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
-
- // Can reassign sponsor:
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
- const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
- expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
- });
-});
-
-describe('evm RFT collection sponsoring', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let nominal: bigint;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- [
- 'mintCross',
- 'mintWithTokenURI',
- ].map(testCase =>
- itEth(`[${testCase}] sponsors mint transactions`, async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}, tokenPropertyPermissions: [
- {key: 'URI', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
- ]});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- await collection.setSponsor(alice, alice.address);
- await collection.confirmSponsorship(alice);
-
- const minter = helper.eth.createAccount();
- const minterCross = helper.ethCrossAccount.fromAddress(minter);
- expect(await helper.balance.getEthereum(minter)).to.equal(0n);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);
-
- await collection.addToAllowList(alice, {Ethereum: minter});
- await collection.addAdmin(alice, {Ethereum: owner});
- const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
- await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/')
- .send();
-
- let mintingResult;
- let tokenId;
- switch (testCase) {
- case 'mintCross':
- mintingResult = await contract.methods.mintCross(minterCross, []).send();
- break;
- case 'mintWithTokenURI':
- mintingResult = await contract.methods.mintWithTokenURI(minter, 'Test URI').send();
- tokenId = mintingResult.events.Transfer.returnValues.tokenId;
- expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
- break;
- }
-
- const events = helper.eth.normalizeEvents(mintingResult.events);
- expect(events).to.deep.include({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: minter,
- tokenId: '1',
- },
- });
- }));
-
- [
- 'setCollectionSponsorCross',
- 'setCollectionSponsor', // Soft-deprecated
- ].map(testCase =>
- itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
-
- let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
- const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, testCase === 'setCollectionSponsor');
-
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
- result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-
- await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
-
- const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
- }));
-
- [
- 'setCollectionSponsorCross',
- 'setCollectionSponsor', // Soft-deprecated
- ].map(testCase =>
- itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
-
- const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');
-
- const collectionSub = helper.rft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
-
- // Set collection sponsor:
- await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});
- let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
- expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
- // Account cannot confirm sponsorship if it is not set as a sponsor
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- // Sponsor can confirm sponsorship:
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
- sponsorship = (await collectionSub.getData())!.raw.sponsorship;
- expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
-
- // Create user with no balance:
- const user = helper.eth.createAccount();
- const userCross = helper.ethCrossAccount.fromAddress(user);
- const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
-
- // Set collection permissions:
- const oldPermissions = (await collectionSub.getData())!.raw.permissions;
- expect(oldPermissions.mintMode).to.be.false;
- expect(oldPermissions.access).to.be.equal('Normal');
-
- await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
- await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
- await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
- const newPermissions = (await collectionSub.getData())!.raw.permissions;
- expect(newPermissions.mintMode).to.be.true;
- expect(newPermissions.access).to.be.equal('AllowList');
-
- // Set token permissions
- await collectionEvm.methods.setTokenPropertyPermissions([
- ['URI', [
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true],
- ],
- ],
- ]).send({from: owner});
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- // User can mint token without balance:
- {
- const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.deep.include({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user,
- tokenId: '1',
- },
- });
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
- expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
- }
- }));
-
- [
- 'setCollectionSponsorCross',
- 'setCollectionSponsor', // Soft-deprecated
- ].map(testCase =>
- itEth(`[${testCase}] Check that collection admin EVM transaction spend money from sponsor eth address`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-
- const collectionSub = helper.rft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
- // Set collection sponsor:
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
- await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
- let collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
- collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
- const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- const sponsorSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.ethToSubstrate(sponsor));
- const actualSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub)));
- expect(actualSubAddress).to.be.equal(sponsorSubAddress);
-
- const user = helper.eth.createAccount();
- const userCross = helper.ethCrossAccount.fromAddress(user);
- await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
- const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
-
- const events = helper.eth.normalizeEvents(mintingResult.events);
- const address = helper.ethAddress.fromCollectionId(collectionId);
-
- expect(events).to.deep.include({
- address,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user,
- tokenId: '1',
- },
- });
- expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- }));
-
- itEth('Check that collection admin EVM transaction spend money from sponsor sub address', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = alice;
- const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-
- const collectionSub = helper.rft.getCollectionObject(collectionId);
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
- // Set collection sponsor:
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
- let collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(sponsor.address);
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- await collectionSub.confirmSponsorship(sponsor);
- collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(sponsor.address);
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
- const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- expect(BigInt(sponsorStruct.sub)).to.be.equal(BigInt('0x' + Buffer.from(sponsor.addressRaw).toString('hex')));
-
- const user = helper.eth.createAccount();
- const userCross = helper.ethCrossAccount.fromAddress(user);
- await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
-
- const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
-
- const events = helper.eth.normalizeEvents(mintingResult.events);
-
- expect(events).to.deep.include({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user,
- tokenId: '1',
- },
- });
- expect(await collectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- });
-
- itEth('Sponsoring collection from substrate address via access list', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const user = helper.eth.createAccount();
- const userCross = helper.ethCrossAccount.fromAddress(user);
- const sponsor = alice;
- const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
-
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});
-
- const collectionSub = helper.rft.getCollectionObject(collectionId);
- await collectionSub.confirmSponsorship(sponsor);
-
- const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
-
- await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
-
- await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
- await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
- // Set token permissions
- await collectionEvm.methods.setTokenPropertyPermissions([
- ['URI', [
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true],
- ],
- ],
- ]).send({from: owner});
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- {
- const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const mintingResult = await collectionEvm.methods.mintWithTokenURI(
- user,
- 'Test URI',
- ).send({from: user});
-
- const events = helper.eth.normalizeEvents(mintingResult.events);
-
-
- expect(events).to.deep.include({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user,
- tokenId: nextTokenId,
- },
- });
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
- expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
- }
- });
-
- itEth('Can reassign collection sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
- const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
- const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
- const collectionSub = helper.rft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- // Set and confirm sponsor:
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
-
- // Can reassign sponsor:
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
- const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
- expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
- });
-
- [
- 'transfer',
- 'transferCross',
- 'transferFrom',
- 'transferFromCross',
- ].map(testCase =>
- itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-
- const user = await helper.eth.createAccountWithBalance(donor);
- const userCross = helper.ethCrossAccount.fromAddress(user);
- await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
- const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- switch (testCase) {
- case 'transfer':
- await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});
- break;
- case 'transferCross':
- await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
- break;
- case 'transferFrom':
- await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});
- break;
- case 'transferFromCross':
- await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
- break;
- }
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- }));
-});
-
-describe('evm RFT token sponsoring', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- 'transfer',
- 'transferCross',
- 'transferFrom',
- 'transferFromCross',
- ].map(testCase =>
- itEth(`[${testCase}] Check that token piece transfer via EVM spend money from sponsor address`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-
- const user = await helper.eth.createAccountWithBalance(donor);
- const userCross = helper.ethCrossAccount.fromAddress(user);
- await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
- const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);
- await tokenContract.methods.repartition(2).send();
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- switch (testCase) {
- case 'transfer':
- await tokenContract.methods.transfer(receiver, 1).send();
- break;
- case 'transferCross':
- await tokenContract.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
- break;
- case 'transferFrom':
- await tokenContract.methods.transferFrom(user, receiver, 1).send();
- break;
- case 'transferFromCross':
- await tokenContract.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), 1).send();
- break;
- }
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- }));
-
- [
- 'approve',
- 'approveCross',
- ].map(testCase =>
- itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-
- const user = await helper.eth.createAccountWithBalance(donor);
- const userCross = helper.ethCrossAccount.fromAddress(user);
- await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
- const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);
- await tokenContract.methods.repartition(2).send();
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- switch (testCase) {
- case 'approve':
- await tokenContract.methods.approve(receiver, 1).send();
- break;
- case 'approveCross':
- await tokenContract.methods.approveCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
- break;
- }
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- }));
-});
-
js-packages/tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/contractSponsoring.test.ts
+++ /dev/null
@@ -1,579 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import {itEth, expect, SponsoringMode, usingEthPlaygrounds} from './util/index.js';
-import {usingPlaygrounds} from '../util/index.js';
-import type {CompiledContract} from './util/playgrounds/types.js';
-
-describe('Sponsoring EVM contracts', () => {
- let donor: IKeyringPair;
- let nominal: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- itEth('Self sponsoring can be set by the address that deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const flipper = await helper.eth.deployFlipper(owner);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
-
- // 1. owner can set selfSponsoring:
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send({from: owner});
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
-
- // 1.1 Can get sponsor using methods.sponsor:
- const actualSponsorOpt = await helpers.methods.sponsor(flipper.options.address).call();
- expect(actualSponsorOpt.status).to.be.true;
- const actualSponsor = actualSponsorOpt.value;
- expect(actualSponsor.eth).to.eq(flipper.options.address);
- expect(actualSponsor.sub).to.eq('0');
-
- // 2. Events should be:
- const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events);
- expect(ethEvents).to.be.deep.equal([
- {
- address: flipper.options.address,
- event: 'ContractSponsorSet',
- args: {
- contractAddress: flipper.options.address,
- sponsor: flipper.options.address,
- },
- },
- {
- address: flipper.options.address,
- event: 'ContractSponsorshipConfirmed',
- args: {
- contractAddress: flipper.options.address,
- sponsor: flipper.options.address,
- },
- },
- ]);
- });
-
- itEth('Self sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const notOwner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- });
-
- itEth('Sponsoring can be set by the address that has deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
- await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
- expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
- });
-
- itEth('Sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const notOwner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
- await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
- });
-
- itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- // 1. owner can set a sponsor:
- expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
- const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;
-
- // 2. Events should be:
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address: flipper.options.address,
- event: 'ContractSponsorSet',
- args: {
- contractAddress: flipper.options.address,
- sponsor: sponsor,
- },
- },
- ]);
- });
-
- itEth('Sponsor cannot be set by the address that did not deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const notOwner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
- await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
- });
-
- itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
-
- // 1. sponsor can confirm sponsorship:
- const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
-
- // 1.1 Can get sponsor using methods.sponsor:
- const actualSponsorOpt = await helpers.methods.sponsor(flipper.options.address).call();
- expect(actualSponsorOpt.status).to.be.true;
- const actualSponsor = actualSponsorOpt.value;
- expect(actualSponsor.eth).to.eq(sponsor);
- expect(actualSponsor.sub).to.eq('0');
-
- // 2. Events should be:
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address: flipper.options.address,
- event: 'ContractSponsorshipConfirmed',
- args: {
- contractAddress: flipper.options.address,
- sponsor: sponsor,
- },
- },
- ]);
- });
-
- itEth('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const notSponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
- await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- });
-
- itEth('Sponsorship can not be confirmed by the address that not set as sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const notSponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- });
-
- itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
- // 1. Can remove sponsor:
- const result = await helpers.methods.removeSponsor(flipper.options.address).send();
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
-
- // 2. Events should be:
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address: flipper.options.address,
- event: 'ContractSponsorRemoved',
- args: {
- contractAddress: flipper.options.address,
- },
- },
- ]);
-
- // TODO: why call method reverts?
- // const actualSponsor = await helpers.methods.sponsor(flipper.options.address).call();
- // expect(actualSponsor.eth).to.eq(sponsor);
- // expect(actualSponsor.sub).to.eq('0');
- });
-
- itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const notOwner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
-
- await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');
- await expect(helpers.methods.removeSponsor(flipper.options.address).send({from: notOwner})).to.be.rejected;
- expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
- });
-
- itEth('In generous mode, non-allowlisted user transaction will be sponsored', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
-
- await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
-
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const callerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
-
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- // Balance should be taken from sponsor instead of caller
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);
- });
-
- itEth('In generous mode, non-allowlisted user transaction will be self sponsored', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
-
- await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
-
- await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
-
- const contractBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address));
- const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
-
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- // Balance should be taken from sponsor instead of caller
- const contractBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address));
- const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
- expect(contractBalanceAfter < contractBalanceBefore).to.be.true;
- expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);
- });
-
- [
- {balance: 0n, label: '0'},
- {balance: 10n, label: '10'},
- ].map(testCase => {
- itEth(`Allow-listed address that has ${testCase.label} UNQ can call a contract. Sponsor balance should decrease`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const caller = helper.eth.createAccount();
- await helper.eth.transferBalanceFromSubstrate(donor, caller, testCase.balance);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
- await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
-
- await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
-
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
-
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceBefore > 0n).to.be.true;
-
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- // Balance should be taken from flipper instead of caller
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- // Caller's balance does not change:
- const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
- expect(callerBalanceAfter).to.eq(testCase.balance * nominal);
- });
- });
-
- itEth('Non-allow-listed address can call a contract. Sponsor balance should not decrease', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = helper.eth.createAccount();
- const contractHelpers = await helper.ethNativeContract.contractHelpers(owner);
-
- // Deploy flipper and send some tokens:
- const flipper = await helper.eth.deployFlipper(owner);
- await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
- expect(await flipper.methods.getValue().call()).to.be.false;
- // flipper address has some tokens:
- const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address);
- expect(originalFlipperBalance > 0n).to.be.true;
-
- // Set Allowlisted sponsoring mode. caller is not in allow list:
- await contractHelpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
- await contractHelpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
- await contractHelpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
-
- // 1. Caller has no UNQ and is not in allow list. So he cannot flip:
- await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/Returned error: insufficient funds for gas \* price \+ value/);
- expect(await flipper.methods.getValue().call()).to.be.false;
-
- // Flipper's balance does not change:
- const balanceAfter = await helper.balance.getEthereum(flipper.options.address);
- expect(balanceAfter).to.be.equal(originalFlipperBalance);
- });
-
- itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- const originalCallerBalance = await helper.balance.getEthereum(caller);
- await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
- await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
-
- await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});
-
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
-
- const originalFlipperBalance = await helper.balance.getEthereum(sponsor);
- expect(originalFlipperBalance > 0n).to.be.true;
-
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
- expect(await helper.balance.getEthereum(caller)).to.be.equal(originalCallerBalance);
-
- const newFlipperBalance = await helper.balance.getEthereum(sponsor);
- expect(newFlipperBalance).to.be.not.equal(originalFlipperBalance);
-
- await flipper.methods.flip().send({from: caller});
- // todo:playgrounds fails rarely (expected 99893341659775672580n to equal 99912598679356033129n) (again, 99893341659775672580n)
- expect(await helper.balance.getEthereum(sponsor)).to.be.equal(newFlipperBalance);
- expect(await helper.balance.getEthereum(caller)).to.be.not.equal(originalCallerBalance);
- });
-
- // TODO: Find a way to calculate default rate limit
- itEth('Default rate limit equal 7200', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.sponsoringRateLimit(flipper.options.address).call()).to.be.equal('7200');
- });
-
- itEth('Gas price boundaries', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
-
- await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
-
- let sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- let callerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
-
- let expectValue = await flipper.methods.getValue().call();
-
- const flip = async (gasPrice: bigint, shouldPass = true) => {
- await flipper.methods.flip().send({from: caller, gasPrice: gasPrice});
- expectValue = !expectValue;
- expect(await flipper.methods.getValue().call()).to.be.eq(expectValue);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.eq(shouldPass);
- expect(callerBalanceAfter === callerBalanceBefore).to.be.eq(shouldPass);
- sponsorBalanceBefore = sponsorBalanceAfter;
- callerBalanceBefore = callerBalanceAfter;
- };
-
- const gasPrice = BigInt((await helper.eth.getGasPrice())!);
- await flip(gasPrice);
- await flip(gasPrice * 2n);
- await flip(gasPrice * 21n / 10n);
- await flip(gasPrice * 22n / 10n, false);
- });
-});
-
-describe('Sponsoring Fee Limit', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let testContract: CompiledContract;
-
- async function compileTestContract(helper: EthUniqueHelper) {
- if(!testContract) {
- testContract = await helper.ethContract.compile(
- 'TestContract',
- `
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.0;
-
- contract TestContract {
- event Result(bool);
-
- function test(uint32 cycles) public {
- uint256 counter = 0;
- while(true) {
- counter ++;
- if (counter > cycles){
- break;
- }
- }
- emit Result(true);
- }
- }
- `,
- );
- }
- return testContract;
- }
-
- async function deployTestContract(helper: EthUniqueHelper, owner: string) {
- const compiled = await compileTestContract(helper);
- return await helper.ethContract.deployByAbi(owner, compiled.abi, compiled.object);
- }
-
- before(async () => {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- itEth('Default fee limit', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equal('115792089237316195423570985008687907853269984665640564039457584007913129639935');
- });
-
- itEth('Set fee limit', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- await helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send();
- expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equal('100');
- });
-
- itEth('Negative test - set fee limit by non-owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const stranger = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
- const flipper = await helper.eth.deployFlipper(owner);
-
- await expect(helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send({from: stranger})).to.be.rejected;
- });
-
- itEth('Negative test - check that eth transactions exceeding fee limit are not executed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const user = await helper.eth.createAccountWithBalance(donor);
- const helpers = helper.ethNativeContract.contractHelpers(owner);
-
- const testContract = await deployTestContract(helper, owner);
-
- await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});
-
- await helpers.methods.setSponsor(testContract.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});
-
- const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
-
- await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();
-
- const originalUserBalance = await helper.balance.getEthereum(user);
- await testContract.methods.test(100).send({from: user, gas: 2_000_000, maxFeePerGas: gasPrice.toString()});
- expect(await helper.balance.getEthereum(user)).to.be.equal(originalUserBalance);
-
- await testContract.methods.test(100).send({from: user, gas: 2_100_000, maxFeePerGas: gasPrice.toString()});
- expect(await helper.balance.getEthereum(user)).to.not.be.equal(originalUserBalance);
- });
-
- itEth('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(owner);
-
- const testContract = await deployTestContract(helper, owner);
-
- await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});
- await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});
-
- await helpers.methods.setSponsor(testContract.options.address, sponsor).send();
- await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});
-
- const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
-
- await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();
-
- const originalAliceBalance = await helper.balance.getSubstrate(alice.address);
-
- await helper.eth.sendEVM(
- alice,
- testContract.options.address,
- testContract.methods.test(100).encodeABI(),
- '0',
- 2_000_000,
- );
- // expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance);
- expect(await helper.balance.getSubstrate(alice.address)).to.be.equal(originalAliceBalance);
-
- await helper.eth.sendEVM(
- alice,
- testContract.options.address,
- testContract.methods.test(100).encodeABI(),
- '0',
- 2_100_000,
- );
- expect(await helper.balance.getSubstrate(alice.address)).to.not.be.equal(originalAliceBalance);
- });
-});
js-packages/tests/src/eth/createCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/createCollection.test.ts
+++ /dev/null
@@ -1,1449 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {evmToAddress} from '@polkadot/util-crypto';
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CREATE_COLLECTION_DATA_DEFAULTS, CollectionLimitField, CollectionMode, CreateCollectionData, TokenPermissionField, emptyAddress} from './util/playgrounds/types.js';
-import {CollectionFlag} from '@unique/playgrounds/src/types.js';
-import type {IEthCrossAccountId, TCollectionMode} from '@unique/playgrounds/src/types.js';
-
-const DECIMALS = 18;
-const CREATE_COLLECTION_DATA_DEFAULTS_ARRAY = [
- [], // properties
- [], // tokenPropertyPermissions
- [], // adminList
- [false, false, []], // nestingSettings
- [], // limits
- emptyAddress, // pendingSponsor
- [0], // flags
-];
-
-type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
-function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
- if(args.length === 0) {
- yield internalRest as any;
- return;
- }
- for(const value of args[0]) {
- yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
- }
-}
-
-describe('Create collection from EVM', () => {
- let donor: IKeyringPair;
- let nominal: bigint;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- describe('Fungible collection', () => {
- before(async function() {
- await usingEthPlaygrounds((helper) => {
- requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
- return Promise.resolve();
- });
- });
-
- itEth('Collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
- .to.be.false;
-
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Exister', 'absolutely anything', 'WIWT', 'ft', DECIMALS)).send();
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddress).call())
- .to.be.true;
-
- // check collectionOwner:
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- const collectionOwner = await collectionEvm.methods.collectionOwner().call();
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
- });
-
- itEth('destroyCollection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Exister', 'absolutely anything', 'WIWT', 'ft', DECIMALS)).send();
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
-
- const result = await collectionHelper.methods
- .destroyCollection(collectionAddress)
- .send({from: owner});
-
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address: collectionHelper.options.address,
- event: 'CollectionDestroyed',
- args: {
- collectionId: collectionAddress,
- },
- },
- ]);
-
- expect(await collectionHelper.methods
- .isCollectionExist(collectionAddress)
- .call()).to.be.false;
- expect(await helper.collection.getData(collectionId)).to.be.null;
- });
-
- itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- {
- const MAX_NAME_LENGTH = 64;
- const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
- const description = 'A';
- const tokenPrefix = 'A';
-
- await expect(collectionHelper.methods
- .createCollection([
- collectionName,
- description,
- tokenPrefix,
- CollectionMode.Fungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
- }
- {
- const MAX_DESCRIPTION_LENGTH = 256;
- const collectionName = 'A';
- const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
- const tokenPrefix = 'A';
- await expect(collectionHelper.methods
- .createCollection([
- collectionName,
- description,
- tokenPrefix,
- CollectionMode.Fungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
- }
- {
- const MAX_TOKEN_PREFIX_LENGTH = 16;
- const collectionName = 'A';
- const description = 'A';
- const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
- await expect(collectionHelper.methods
- .createCollection([
- collectionName,
- description,
- tokenPrefix,
- CollectionMode.Fungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
- }
- });
-
- itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- const expects = [0n, 1n, 30n].map(async value => {
- await expect(collectionHelper.methods
- .createCollection([
- 'Peasantry',
- 'absolutely anything',
- 'TWIW',
- CollectionMode.Fungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
- await Promise.all(expects);
- });
- });
-
- describe('Nonfungible collection', () => {
- before(async function() {
- await usingEthPlaygrounds((helper) => {
- requirePalletsOrSkip(this, helper, [Pallets.NFT]);
- return Promise.resolve();
- });
- });
-
- itEth('Create collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
-
- // todo:playgrounds this might fail when in async environment.
- const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
- const {collectionId, collectionAddress, events} = await helper.eth.createCollection(owner, new CreateCollectionData(name, description, prefix, 'nft')).send();
-
- expect(events).to.be.deep.equal([
- {
- address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',
- event: 'CollectionCreated',
- args: {
- owner: owner,
- collectionId: collectionAddress,
- },
- },
- ]);
-
- const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
-
- const collection = helper.nft.getCollectionObject(collectionId);
- const data = (await collection.getData())!;
-
- // Parallel test safety
- expect(collectionCountAfter - collectionCountBefore).to.be.gte(1);
- expect(collectionId).to.be.eq(collectionCountAfter);
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('NFT');
-
- const options = await collection.getOptions();
-
- expect(options.tokenPropertyPermissions).to.be.empty;
- });
-
- // this test will occasionally fail when in async environment.
- itEth('Check collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
- const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers.methods
- .isCollectionExist(expectedCollectionAddress)
- .call()).to.be.false;
-
- await collectionHelpers.methods
- .createCollection([
- 'A',
- 'A',
- 'A',
- CollectionMode.Nonfungible,
- 0,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .send({value: Number(2n * helper.balance.getOneTokenNominal())});
-
- expect(await collectionHelpers.methods
- .isCollectionExist(expectedCollectionAddress)
- .call()).to.be.true;
- });
- });
-
- describe('Create RFT collection from EVM', () => {
- before(async function() {
- await usingEthPlaygrounds((helper) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- return Promise.resolve();
- });
- });
-
- itEth('Create collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
-
- const {collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData(name, description, prefix, 'rft')).send();
- const data = (await helper.rft.getData(collectionId))!;
- const collection = helper.rft.getCollectionObject(collectionId);
-
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('ReFungible');
-
- const options = await collection.getOptions();
-
- expect(options.tokenPropertyPermissions).to.be.empty;
- });
-
- itEth('Create collection with properties & get description', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
- const baseUri = 'BaseURI';
-
- const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const collection = helper.rft.getCollectionObject(collectionId);
- const data = (await collection.getData())!;
-
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('ReFungible');
-
- expect(await contract.methods.description().call()).to.deep.equal(description);
-
- const options = await collection.getOptions();
- expect(options.tokenPropertyPermissions).to.be.deep.equal([
- {
- key: 'URI',
- permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
- },
- {
- key: 'URISuffix',
- permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
- },
- ]);
- });
-
- itEth('Set sponsorship', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Sponsor', 'absolutely anything', 'ENVY', 'rft')).send();
-
- const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await collection.methods.setCollectionSponsorCross(sponsorCross).send();
-
- let data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
- });
-
- itEth('Collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
- .to.be.false;
-
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('Exister', 'absolutely anything', 'WIWT', 'rft')).send();
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddress).call())
- .to.be.true;
-
- // check collectionOwner:
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- const collectionOwner = await collectionEvm.methods.collectionOwner().call();
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
- });
-
- itEth('destroyCollection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Limits', 'absolutely anything', 'OLF', 'rft')).send();
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
-
- await expect(collectionHelper.methods
- .destroyCollection(collectionAddress)
- .send({from: owner})).to.be.fulfilled;
-
- expect(await collectionHelper.methods
- .isCollectionExist(collectionAddress)
- .call()).to.be.false;
- expect(await helper.collection.getData(collectionId)).to.be.null;
- });
-
- itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- {
- const MAX_NAME_LENGTH = 64;
- const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
- const description = 'A';
- const tokenPrefix = 'A';
-
- await expect(collectionHelper.methods
- .createCollection([
- collectionName,
- description,
- tokenPrefix,
- CollectionMode.Refungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
- }
- {
- const MAX_DESCRIPTION_LENGTH = 256;
- const collectionName = 'A';
- const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
- const tokenPrefix = 'A';
- await expect(collectionHelper.methods
- .createCollection([
- collectionName,
- description,
- tokenPrefix,
- CollectionMode.Refungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
- }
- {
- const MAX_TOKEN_PREFIX_LENGTH = 16;
- const collectionName = 'A';
- const description = 'A';
- const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
- await expect(collectionHelper.methods
- .createCollection([
- collectionName,
- description,
- tokenPrefix,
- CollectionMode.Refungible,
- DECIMALS,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
- }
- });
-
- itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- await expect(collectionHelper.methods
- .createCollection([
- 'Peasantry',
- 'absolutely anything',
- 'TWIW',
- CollectionMode.Refungible,
- 0,
- ...CREATE_COLLECTION_DATA_DEFAULTS_ARRAY,
- ])
- .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
- });
-
- describe('Sponsoring', () => {
- itEth('Сan remove collection sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddr(sponsor);
-
- const {collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Sponsor collection',
- description: '1',
- tokenPrefix: '1',
- collectionMode: 'nft',
- pendingSponsor: sponsorCross,
- },
- ).send();
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
- let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
- expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-
- await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
-
- sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
- expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
- });
-
- itEth('Can sponsor from evm address via access list', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddr(sponsorEth);
-
- const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Sponsor collection',
- description: '1',
- tokenPrefix: '1',
- collectionMode: 'nft',
- pendingSponsor: sponsorCross,
- limits: [{field: CollectionLimitField.SponsoredDataRateLimit, value: 30n}],
- tokenPropertyPermissions: [{key: 'key', permissions: [{code: TokenPermissionField.TokenOwner, value: true}]}],
- },
- '',
- );
-
- const collectionSub = helper.nft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
- expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
- // Account cannot confirm sponsorship if it is not set as a sponsor
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- // Sponsor can confirm sponsorship:
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
- sponsorship = (await collectionSub.getData())!.raw.sponsorship;
- expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
-
- // Create user with no balance:
- const user = helper.ethCrossAccount.createAccount();
- const nextTokenId = await collectionEvm.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
-
- // Set collection permissions:
- const oldPermissions = (await collectionSub.getData())!.raw.permissions;
- expect(oldPermissions.mintMode).to.be.false;
- expect(oldPermissions.access).to.be.equal('Normal');
-
- await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
- await collectionEvm.methods.addToCollectionAllowListCross(user).send({from: owner});
- await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
- const newPermissions = (await collectionSub.getData())!.raw.permissions;
- expect(newPermissions.mintMode).to.be.true;
- expect(newPermissions.access).to.be.equal('AllowList');
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
-
- // User can mint token without balance:
- {
- const result = await collectionEvm.methods.mintCross(user, [{key: 'key', value: Buffer.from('Value')}]).send({from: user.eth});
- const event = helper.eth.normalizeEvents(result.events)
- .find(event => event.event === 'Transfer');
-
- expect(event).to.be.deep.equal({
- address: collectionAddress,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user.eth,
- tokenId: '1',
- },
- });
-
- // await collectionEvm.methods.setProperties(1, [{key: 'key', value: Buffer.from('Value1')}]).send({from: user.eth});
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user.eth));
-
- expect(await collectionEvm.methods.properties(nextTokenId, []).call())
- .to.be.like([
- [
- 'key',
- '0x' + Buffer.from('Value').toString('hex'),
- ],
- ]);
- expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
- }
- });
-
- itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddr(sponsor);
- const user = helper.eth.createAccount();
- const userCross = helper.ethCrossAccount.fromAddress(user);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Sponsor collection',
- description: '1',
- tokenPrefix: '1',
- collectionMode: 'nft',
- pendingSponsor: sponsorCross,
- adminList: [userCross],
- },
- '',
- );
-
- const collectionSub = helper.nft.getCollectionObject(collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- // Set collection sponsor:
- let collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
- await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
- collectionData = (await collectionSub.getData())!;
- expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
- const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
-
- const event = helper.eth.normalizeEvents(mintingResult.events)
- .find(event => event.event === 'Transfer');
- const address = helper.ethAddress.fromCollectionId(collectionId);
-
- expect(event).to.be.deep.equal({
- address,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: user,
- tokenId: '1',
- },
- });
- expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- });
-
- itEth('Can reassign collection sponsor', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsorEth = await helper.eth.createAccountWithBalance(donor);
- const sponsorCrossEth = helper.ethCrossAccount.fromAddr(sponsorEth);
- const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
- const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
-
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Sponsor collection',
- description: '1',
- tokenPrefix: '1',
- collectionMode: 'nft',
- pendingSponsor: sponsorCrossEth,
- },
- '',
- );
- const collectionSub = helper.nft.getCollectionObject(collectionId);
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- // Set and confirm sponsor:
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
-
- // Can reassign sponsor:
- await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
- const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
- expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
- });
-
- [
- 'transfer',
- 'transferCross',
- 'transferFrom',
- 'transferFromCross',
- ].map(testCase =>
- itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddr(sponsor);
- const user = await helper.eth.createAccountWithBalance(donor);
- const userCross = helper.ethCrossAccount.fromAddress(user);
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Sponsor collection',
- description: '1',
- tokenPrefix: '1',
- collectionMode: 'rft',
- pendingSponsor: sponsorCross,
- adminList: [userCross],
- },
- '',
- );
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-
- const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-
- switch (testCase) {
- case 'transfer':
- await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});
- break;
- case 'transferCross':
- await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
- break;
- case 'transferFrom':
- await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});
- break;
- case 'transferFromCross':
- await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
- break;
- }
-
- const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
- expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
- const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
- expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
- const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
- expect(userBalanceAfter).to.be.eq(userBalanceBefore);
- }));
- });
-
- describe('Collection admins', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`can add account admin by owner for ${testCase.mode}`, testCase.requiredPallets, async ({helper, privateKey}) => {
- // arrange
- const owner = await helper.eth.createAccountWithBalance(donor);
- const adminSub = await privateKey('//admin2');
- const adminEth = helper.eth.createAccount().toLowerCase();
-
- const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
-
- const {collectionAddress, collectionId} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Mint collection',
- description: 'a',
- tokenPrefix: 'b',
- collectionMode: testCase.mode,
- adminList: [adminCrossSub, adminCrossEth],
- },
- ).send();
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, true);
-
- // 1. Expect api.rpc.unique.adminlist returns admins:
- const adminListRpc = await helper.collection.getAdmins(collectionId);
- expect(adminListRpc).to.has.length(2);
- expect(adminListRpc).to.be.deep.contain.members([{Substrate: adminSub.address}, {Ethereum: adminEth}]);
-
- // 2. Expect methods.collectionAdmins == api.rpc.unique.adminlist
- let adminListEth = await collectionEvm.methods.collectionAdmins().call();
- adminListEth = adminListEth.map((element: IEthCrossAccountId) => helper.address.convertCrossAccountFromEthCrossAccount(element));
- expect(adminListRpc).to.be.like(adminListEth);
-
- // 3. check isOwnerOrAdminCross returns true:
- expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.true;
- expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.true;
- });
- });
-
- itEth('cross account admin can mint', async ({helper}) => {
- // arrange: create collection and accounts
- const owner = await helper.eth.createAccountWithBalance(donor);
- const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
- const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
- const [adminSub] = await helper.arrange.createAccounts([100n], donor);
- const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Mint collection',
- description: 'a',
- tokenPrefix: 'b',
- collectionMode: 'nft',
- adminList: [adminCrossSub, adminCrossEth],
- },
- 'uri',
- );
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
-
- // admin (sub and eth) can mint token:
- await collectionEvm.methods.mint(owner).send({from: adminEth});
- await helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}});
-
- expect(await helper.collection.getLastTokenId(collectionId)).to.eq(2);
- });
-
- itEth('cannot add invalid cross account admin', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const [admin] = await helper.arrange.createAccounts([100n, 100n], donor);
-
- const adminCross = {
- eth: helper.address.substrateToEth(admin.address),
- sub: admin.addressRaw,
- };
-
- await expect(helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft',
- adminList: [adminCross],
- },
- ).call()).to.be.rejected;
- });
-
- itEth('Remove [cross] admin by owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const [adminSub] = await helper.arrange.createAccounts([10n], donor);
- const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
- const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
- const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
-
- const {collectionAddress, collectionId} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft',
- adminList: [adminCrossSub, adminCrossEth],
- },
- ).send();
-
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- {
- const adminList = await helper.collection.getAdmins(collectionId);
- expect(adminList).to.deep.include({Substrate: adminSub.address});
- expect(adminList).to.deep.include({Ethereum: adminEth});
- }
-
- await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send();
- await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send();
- const adminList = await helper.collection.getAdmins(collectionId);
- expect(adminList.length).to.be.eq(0);
-
- // Non admin cannot mint:
- await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
- await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected;
- });
- });
-
- describe('Collection limits', () => {
- describe('Can set collection limits', () => {
- [
- {case: 'nft' as const},
- {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {case: 'ft' as const},
- ].map(testCase =>
- itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const limits = {
- accountTokenOwnershipLimit: 1000n,
- sponsoredDataSize: 1024n,
- sponsoredDataRateLimit: 30n,
- tokenLimit: 1000000n,
- sponsorTransferTimeout: 6n,
- sponsorApproveTimeout: 6n,
- ownerCanTransfer: 1n,
- ownerCanDestroy: 0n,
- transfersEnabled: 0n,
- };
-
- const {collectionId, collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Limits',
- description: 'absolutely anything',
- tokenPrefix: 'FLO',
- collectionMode: testCase.case,
- limits: [
- {field: CollectionLimitField.AccountTokenOwnership, value: limits.accountTokenOwnershipLimit},
- {field: CollectionLimitField.SponsoredDataSize, value: limits.sponsoredDataSize},
- {field: CollectionLimitField.SponsoredDataRateLimit, value: limits.sponsoredDataRateLimit},
- {field: CollectionLimitField.TokenLimit, value: limits.tokenLimit},
- {field: CollectionLimitField.SponsorTransferTimeout, value: limits.sponsorTransferTimeout},
- {field: CollectionLimitField.SponsorApproveTimeout, value: limits.sponsorApproveTimeout},
- {field: CollectionLimitField.OwnerCanTransfer, value: limits.ownerCanTransfer},
- {field: CollectionLimitField.OwnerCanDestroy, value: limits.ownerCanDestroy},
- {field: CollectionLimitField.TransferEnabled, value: limits.transfersEnabled},
- ],
- },
- ).send();
-
- const expectedLimits = {
- accountTokenOwnershipLimit: 1000,
- sponsoredDataSize: 1024,
- sponsoredDataRateLimit: {blocks: 30},
- tokenLimit: 1000000,
- sponsorTransferTimeout: 6,
- sponsorApproveTimeout: 6,
- ownerCanTransfer: true,
- ownerCanDestroy: false,
- transfersEnabled: false,
- };
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner);
-
- // Check limits from sub:
- const data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.limits).to.deep.eq(expectedLimits);
- expect(await helper.collection.getEffectiveLimits(collectionId)).to.deep.eq(expectedLimits);
- // Check limits from eth:
- const limitsEvm = await collectionEvm.methods.collectionLimits().call({from: owner});
- expect(limitsEvm).to.have.length(9);
- expect(limitsEvm[0]).to.deep.eq([CollectionLimitField.AccountTokenOwnership.toString(), [true, limits.accountTokenOwnershipLimit.toString()]]);
- expect(limitsEvm[1]).to.deep.eq([CollectionLimitField.SponsoredDataSize.toString(), [true, limits.sponsoredDataSize.toString()]]);
- expect(limitsEvm[2]).to.deep.eq([CollectionLimitField.SponsoredDataRateLimit.toString(), [true, limits.sponsoredDataRateLimit.toString()]]);
- expect(limitsEvm[3]).to.deep.eq([CollectionLimitField.TokenLimit.toString(), [true, limits.tokenLimit.toString()]]);
- expect(limitsEvm[4]).to.deep.eq([CollectionLimitField.SponsorTransferTimeout.toString(), [true, limits.sponsorTransferTimeout.toString()]]);
- expect(limitsEvm[5]).to.deep.eq([CollectionLimitField.SponsorApproveTimeout.toString(), [true, limits.sponsorApproveTimeout.toString()]]);
- expect(limitsEvm[6]).to.deep.eq([CollectionLimitField.OwnerCanTransfer.toString(), [true, limits.ownerCanTransfer.toString()]]);
- expect(limitsEvm[7]).to.deep.eq([CollectionLimitField.OwnerCanDestroy.toString(), [true, limits.ownerCanDestroy.toString()]]);
- expect(limitsEvm[8]).to.deep.eq([CollectionLimitField.TransferEnabled.toString(), [true, limits.transfersEnabled.toString()]]);
- }));
- });
-
- describe('(!negative test!) Cannot set invalid collection limits', () => {
- [
- {case: 'nft' as const},
- {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {case: 'ft' as const},
- ].map(testCase =>
- itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {
- const invalidLimits = {
- accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),
- transfersEnabled: 3,
- };
-
- const createCollectionData = {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'Limits',
- description: 'absolutely anything',
- tokenPrefix: 'ISNI',
- collectionMode: testCase.case,
- };
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- limits: [{field: 9 as CollectionLimitField, value: 1n}],
- },
- ).call()).to.be.rejectedWith('value not convertible into enum "CollectionLimitField"');
-
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- limits: [{field: CollectionLimitField.AccountTokenOwnership, value: invalidLimits.accountTokenOwnershipLimit}],
- },
- ).call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);
-
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- limits: [{field: CollectionLimitField.TransferEnabled, value: 3n}],
- },
- ).call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);
-
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- limits: [{field: CollectionLimitField.SponsoredDataSize, value: -1n}],
- },
- ).call()).to.be.rejectedWith('value out-of-bounds');
- }));
- });
- });
-
- describe('Collection properties', () => {
-
- [
- {mode: 'nft' as const, methodParams: [{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
- {mode: 'rft' as const, methodParams: [{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
- {mode: 'ft' as const, methodParams: [{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]},
- ].map(testCase =>
- itEth.ifWithPallets(`Collection properties can be set for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'name',
- description: 'test',
- tokenPrefix: 'test',
- collectionMode: testCase.mode,
- adminList: [callerCross],
- properties: testCase.methodParams,
- },
- ).send();
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, caller);
-
- const raw = (await helper[testCase.mode].getData(collectionId))?.raw;
- expect(raw.properties).to.deep.equal(testCase.expectedProps);
-
- // collectionProperties returns properties:
- expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like(testCase.expectedProps.map(prop => helper.ethProperty.property(prop.key, prop.value)));
- }));
-
- [
- {mode: 'nft' as const},
- {mode: 'rft' as const},
- {mode: 'ft' as const},
- ].map(testCase =>
- itEth.ifWithPallets(`Collection properties can be deleted for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'name',
- description: 'test',
- tokenPrefix: 'test',
- collectionMode: testCase.mode,
- adminList: [callerCross],
- properties:[
- {key: 'testKey1', value: Buffer.from('testValue1')},
- {key: 'testKey2', value: Buffer.from('testValue2')},
- {key: 'testKey3', value: Buffer.from('testValue3')}],
- },
- ).send();
-
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, caller);
-
- await collectionEvm.methods.deleteCollectionProperties(['testKey1', 'testKey2']).send({from: caller});
-
- const raw = (await helper[testCase.mode].getData(collectionId))?.raw;
-
- expect(raw.properties.length).to.equal(1);
- expect(raw.properties).to.deep.equal([{key: 'testKey3', value: 'testValue3'}]);
- }));
-
- itEth('(!negative test!) Cannot set invalid properties', async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const createCollectionData = {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'name',
- description: 'test',
- tokenPrefix: 'test',
- collectionMode: 'nft' as TCollectionMode,
- adminList: [callerCross],
- };
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- properties: [{key: '', value: Buffer.from('val1')}],
- },
- ).call()).to.be.rejected;
-
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- properties: [{key: 'déjà vu', value: Buffer.from('hmm...')}],
- },
- ).call()).to.be.rejected;
-
- await expect(helper.eth.createCollection(
- owner,
- {
- ...createCollectionData,
- properties: [{key: 'a'.repeat(257), value: Buffer.from('val3')}],
- },
- ).call()).to.be.rejected;
- });
-
- itEth('(!negative test!) cannot delete properties of non-owned collections', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'name',
- description: 'test',
- tokenPrefix: 'test',
- collectionMode: 'nft',
- properties:[
- {key: 'testKey1', value: Buffer.from('testValue1')},
- {key: 'testKey2', value: Buffer.from('testValue2')}],
- },
- ).send();
-
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
-
- await expect(collectionEvm.methods.deleteCollectionProperties(['testKey2']).send({from: caller})).to.be.rejected;
- });
- });
-
- describe('Token property permissions', () => {
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can set all possible token property permissions`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);
- for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {
- const {collectionId, collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: testCase.mode,
- adminList: [caller],
- tokenPropertyPermissions: [
- {
- key: 'testKey',
- permissions: [
- {code: TokenPermissionField.Mutable, value: mutable},
- {code: TokenPermissionField.TokenOwner, value: tokenOwner},
- {code: TokenPermissionField.CollectionAdmin, value: collectionAdmin},
- ],
- },
- ],
- },
- ).send();
- const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{
- key: 'testKey',
- permission: {mutable, collectionAdmin, tokenOwner},
- }]);
-
- expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([
- ['testKey', [
- [TokenPermissionField.Mutable.toString(), mutable],
- [TokenPermissionField.TokenOwner.toString(), tokenOwner],
- [TokenPermissionField.CollectionAdmin.toString(), collectionAdmin]],
- ],
- ]);
- }
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: testCase.mode,
- tokenPropertyPermissions: [
- {
- key: 'testKey_0',
- permissions: [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.TokenOwner, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true}],
- },
- {
- key: 'testKey_1',
- permissions: [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.TokenOwner, value: false},
- {code: TokenPermissionField.CollectionAdmin, value: true}],
- },
- {
- key: 'testKey_2',
- permissions: [
- {code: TokenPermissionField.Mutable, value: false},
- {code: TokenPermissionField.TokenOwner, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: false}],
- },
- ],
- },
- ).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([
- {
- key: 'testKey_0',
- permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
- },
- {
- key: 'testKey_1',
- permission: {mutable: true, tokenOwner: false, collectionAdmin: true},
- },
- {
- key: 'testKey_2',
- permission: {mutable: false, tokenOwner: true, collectionAdmin: false},
- },
- ]);
-
- expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([
- ['testKey_0', [
- [TokenPermissionField.Mutable.toString(), true],
- [TokenPermissionField.TokenOwner.toString(), true],
- [TokenPermissionField.CollectionAdmin.toString(), true]],
- ],
- ['testKey_1', [
- [TokenPermissionField.Mutable.toString(), true],
- [TokenPermissionField.TokenOwner.toString(), false],
- [TokenPermissionField.CollectionAdmin.toString(), true]],
- ],
- ['testKey_2', [
- [TokenPermissionField.Mutable.toString(), false],
- [TokenPermissionField.TokenOwner.toString(), true],
- [TokenPermissionField.CollectionAdmin.toString(), false]],
- ],
- ]);
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`Can be deleted for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(
- caller,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: testCase.mode,
- adminList: [receiver],
- tokenPropertyPermissions: [
- {
- key: 'testKey',
- permissions: [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true}],
- },
- {
- key: 'testKey_1',
- permissions: [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true}],
- },
- ],
- },
- ).send();
-
- const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, caller);
- const tokenId = (await collection.methods.mintCross(receiver, [{key: 'testKey', value: Buffer.from('testValue')}, {key: 'testKey_1', value: Buffer.from('testValue_1')}]).send()).events.Transfer.returnValues.tokenId;
- expect(await collection.methods.properties(tokenId, ['testKey', 'testKey_1']).call()).to.has.length(2);
-
- await collection.methods.deleteProperties(tokenId, ['testKey', 'testKey_1']).send({from: caller});
- expect(await collection.methods.properties(tokenId, ['testKey', 'testKey_1']).call()).to.has.length(0);
- }));
- });
-
- describe('Nesting', () => {
- itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft',
- nestingSettings: {token_owner: true, collection_admin: false, restricted: []},
- },
- ).send();
-
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- // Create a token to be nested to
- const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
-
- // Create a nested token
- const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});
- const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;
- expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Create a token to be nested and nest
- const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
-
- await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Unnest token back
- await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
- });
-
- itEth('NFT: collectionNesting()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress: unnestedCollectionAddress} = await helper.eth.createCollection(
- owner,
- new CreateCollectionData('A', 'B', 'C', 'nft'),
- ).send();
-
- const unnestedContract = helper.ethNativeContract.collection(unnestedCollectionAddress, 'nft', owner);
- expect(await unnestedContract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
-
- const {collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft',
- nestingSettings: {token_owner: true, collection_admin: false, restricted: [unnestedCollectionAddress.toString()]},
- },
- ).send();
-
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([true, false, [unnestedCollectionAddress.toString()]]);
- await contract.methods.setCollectionNesting([false, false, []]).send({from: owner});
- expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
- });
-
- itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId, collectionAddress} = await helper.eth.createCollection(
- owner,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft',
- nestingSettings: {token_owner: false, collection_admin: false, restricted: []},
- },
- ).send();
-
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- // Create a token to nest into
- const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
-
- // Create a token to nest
- const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;
-
- // Try to nest
- await expect(contract.methods
- .transfer(targetNftTokenAddress, nftTokenId)
- .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
- });
-
- describe('Flags', () => {
- const createCollectionData = {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft' as TCollectionMode,
- };
-
- itEth('NFT: use numbers for flags', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- {
- const {collectionId} = await helper.eth.createCollection(owner, {...createCollectionData, flags: 0}).send();
- expect((await helper.nft.getData(collectionId))?.raw.flags).to.be.deep.equal({foreign: false, erc721metadata: false});
- }
-
- {
- const {collectionId} = await helper.eth.createCollection(owner, {...createCollectionData, flags: 64}).send();
- expect((await helper.nft.getData(collectionId))?.raw.flags).to.be.deep.equal({foreign: false, erc721metadata: true});
- }
- });
-
- itEth('NFT: can\'t set foreign flag number', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- {
- await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: 128}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
- }
-
- {
- await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: 192}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
- }
- });
-
- itEth('NFT: use enum for flags', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- {
- const {collectionId} = await helper.eth.createCollection(owner, {...createCollectionData, flags: [CollectionFlag.Erc721metadata]}).send();
- expect((await helper.nft.getData(collectionId))?.raw.flags).to.be.deep.equal({foreign: false, erc721metadata: true});
- }
- });
-
- itEth('NFT: foreign flag enum is ignored', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- {
- await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: [CollectionFlag.Foreign]}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
- }
-
- {
- await expect(helper.eth.createCollection(owner, {...createCollectionData, flags: [CollectionFlag.Erc721metadata | CollectionFlag.Foreign]}).call({from: owner})).to.be.rejectedWith(/internal flags were used/);
- }
- });
- });
-});
js-packages/tests/src/eth/createFTCollection.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/createFTCollection.seqtest.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-
-const DECIMALS = 18;
-
-describe('Create FT collection from EVM', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Create collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
-
- // todo:playgrounds this might fail when in async environment.
- const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
-
- const {collectionId} = await helper.eth.createFungibleCollection(owner, name, DECIMALS, description, prefix);
-
- const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
- const data = (await helper.ft.getData(collectionId))!;
-
- expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
- expect(collectionId).to.be.eq(collectionCountAfter);
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.deep.eq({Fungible: DECIMALS.toString()});
- });
-
- // todo:playgrounds this test will fail when in async environment.
- itEth('Check collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
- const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers.methods
- .isCollectionExist(expectedCollectionAddress)
- .call()).to.be.false;
-
-
- await helper.eth.createFungibleCollection(owner, 'A', DECIMALS, 'A', 'A');
-
-
- expect(await collectionHelpers.methods
- .isCollectionExist(expectedCollectionAddress)
- .call()).to.be.true;
- });
-});
js-packages/tests/src/eth/createFTCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/createFTCollection.test.ts
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {evmToAddress} from '@polkadot/util-crypto';
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField} from './util/playgrounds/types.js';
-
-const DECIMALS = 18;
-
-describe('Create FT collection from EVM', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- // TODO move sponsorship tests to another file:
- // Soft-deprecated
- itEth('[eth] Set sponsorship', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const description = 'absolutely anything';
-
- const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');
-
- const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- await collection.methods.setCollectionSponsor(sponsor).send();
-
- let data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
- });
-
- itEth('[cross] Set sponsorship', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const description = 'absolutely anything';
- const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');
-
- const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await collection.methods.setCollectionSponsorCross(sponsorCross).send();
-
- let data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
- expect(await collection.methods.description().call()).to.deep.equal(description);
- });
-
- itEth('Collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
- .to.be.false;
-
- const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddress).call())
- .to.be.true;
-
- // check collectionOwner:
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- const collectionOwner = await collectionEvm.methods.collectionOwner().call();
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
- });
-
- itEth('destroyCollection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
-
- const result = await collectionHelper.methods
- .destroyCollection(collectionAddress)
- .send({from: owner});
-
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address: collectionHelper.options.address,
- event: 'CollectionDestroyed',
- args: {
- collectionId: collectionAddress,
- },
- },
- ]);
-
- expect(await collectionHelper.methods
- .isCollectionExist(collectionAddress)
- .call()).to.be.false;
- expect(await helper.collection.getData(collectionId)).to.be.null;
- });
-});
-
-describe('(!negative tests!) Create FT collection from EVM', () => {
- let donor: IKeyringPair;
- let nominal: bigint;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
- donor = await privateKey({url: import.meta.url});
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- {
- const MAX_NAME_LENGTH = 64;
- const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
- const description = 'A';
- const tokenPrefix = 'A';
-
- await expect(collectionHelper.methods
- .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
- }
- {
- const MAX_DESCRIPTION_LENGTH = 256;
- const collectionName = 'A';
- const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
- const tokenPrefix = 'A';
- await expect(collectionHelper.methods
- .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
- }
- {
- const MAX_TOKEN_PREFIX_LENGTH = 16;
- const collectionName = 'A';
- const description = 'A';
- const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
- await expect(collectionHelper.methods
- .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
- }
- });
-
- itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- const expects = [0n, 1n, 30n].map(async value => {
- await expect(collectionHelper.methods
- .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')
- .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
- await Promise.all(expects);
- });
-
- // Soft-deprecated
- itEth('(!negative test!) [eth] Check owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const peasant = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');
- const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant, true);
- const EXPECTED_ERROR = 'NoPermission';
- {
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- await expect(peasantCollection.methods
- .setCollectionSponsor(sponsor)
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor, true);
- await expect(sponsorCollection.methods
- .confirmCollectionSponsorship()
- .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- }
- {
- await expect(peasantCollection.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
- }
- });
-
- itEth('(!negative test!) [cross] Check owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const peasant = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');
- const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant);
- const EXPECTED_ERROR = 'NoPermission';
- {
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await expect(peasantCollection.methods
- .setCollectionSponsorCross(sponsorCross)
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor);
- await expect(sponsorCollection.methods
- .confirmCollectionSponsorship()
- .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- }
- {
- await expect(peasantCollection.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
- }
- });
-});
js-packages/tests/src/eth/createNFTCollection.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/createNFTCollection.seqtest.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-
-
-describe('Create NFT collection from EVM', () => {
- let donor: IKeyringPair;
-
- before(async function () {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Create collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
-
- // todo:playgrounds this might fail when in async environment.
- const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
- const {collectionId, collectionAddress, events} = await helper.eth.createNFTCollection(owner, name, description, prefix);
-
- expect(events).to.be.deep.equal([
- {
- address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',
- event: 'CollectionCreated',
- args: {
- owner: owner,
- collectionId: collectionAddress,
- },
- },
- ]);
-
- const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;
-
- const collection = helper.nft.getCollectionObject(collectionId);
- const data = (await collection.getData())!;
-
- expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
- expect(collectionId).to.be.eq(collectionCountAfter);
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('NFT');
-
- const options = await collection.getOptions();
-
- expect(options.tokenPropertyPermissions).to.be.empty;
- });
-
- // this test will occasionally fail when in async environment.
- itEth('Check collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
- const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers.methods
- .isCollectionExist(expectedCollectionAddress)
- .call()).to.be.false;
-
- await collectionHelpers.methods
- .createNFTCollection('A', 'A', 'A')
- .send({value: Number(2n * helper.balance.getOneTokenNominal())});
-
- expect(await collectionHelpers.methods
- .isCollectionExist(expectedCollectionAddress)
- .call()).to.be.true;
- });
-});
js-packages/tests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/createNFTCollection.test.ts
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {evmToAddress} from '@polkadot/util-crypto';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField} from './util/playgrounds/types.js';
-
-
-describe('Create NFT collection from EVM', () => {
- let donor: IKeyringPair;
-
- before(async function () {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Create collection with properties & get desctription', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
- const baseUri = 'BaseURI';
-
- const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- expect(events).to.be.deep.equal([
- {
- address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',
- event: 'CollectionCreated',
- args: {
- owner: owner,
- collectionId: collectionAddress,
- },
- },
- ]);
-
- const collection = helper.nft.getCollectionObject(collectionId);
- const data = (await collection.getData())!;
-
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('NFT');
-
- expect(await contract.methods.description().call()).to.deep.equal(description);
-
- const options = await collection.getOptions();
- expect(options.tokenPropertyPermissions).to.be.deep.equal([
- {
- key: 'URI',
- permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
- },
- {
- key: 'URISuffix',
- permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
- },
- ]);
- });
-
- // Soft-deprecated
- itEth('[eth] Set sponsorship', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
-
- const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
- await collection.methods.setCollectionSponsor(sponsor).send();
-
- let data = (await helper.nft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.nft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
- });
-
- itEth('[cross] Set sponsorship & get description', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const description = 'absolutely anything';
- const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', description, 'ROC');
-
- const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await collection.methods.setCollectionSponsorCross(sponsorCross).send();
-
- let data = (await helper.nft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.nft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- expect(await sponsorCollection.methods.description().call()).to.deep.equal(description);
- });
-
- itEth('Collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
- .to.be.false;
-
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Exister', 'absolutely anything', 'EVC');
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddress).call())
- .to.be.true;
-
- // check collectionOwner:
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- const collectionOwner = await collectionEvm.methods.collectionOwner().call();
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
- });
-});
-
-describe('(!negative tests!) Create NFT collection from EVM', () => {
- let donor: IKeyringPair;
- let nominal: bigint;
-
- before(async function () {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- {
- const MAX_NAME_LENGTH = 64;
- const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
- const description = 'A';
- const tokenPrefix = 'A';
-
- await expect(collectionHelper.methods
- .createNFTCollection(collectionName, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
-
- }
- {
- const MAX_DESCRIPTION_LENGTH = 256;
- const collectionName = 'A';
- const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
- const tokenPrefix = 'A';
- await expect(collectionHelper.methods
- .createNFTCollection(collectionName, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
- }
- {
- const MAX_TOKEN_PREFIX_LENGTH = 16;
- const collectionName = 'A';
- const description = 'A';
- const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
- await expect(collectionHelper.methods
- .createNFTCollection(collectionName, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
- }
- });
-
- itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- await expect(collectionHelper.methods
- .createNFTCollection('Peasantry', 'absolutely anything', 'CVE')
- .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
-
- // Soft-deprecated
- itEth('(!negative test!) [eth] Check owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const malfeasant = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR');
- const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant, true);
- const EXPECTED_ERROR = 'NoPermission';
- {
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- await expect(malfeasantCollection.methods
- .setCollectionSponsor(sponsor)
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);
- await expect(sponsorCollection.methods
- .confirmCollectionSponsorship()
- .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- }
- {
- await expect(malfeasantCollection.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
- }
- });
-
- itEth('(!negative test!) [cross] Check owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const malfeasant = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR');
- const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant);
- const EXPECTED_ERROR = 'NoPermission';
- {
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await expect(malfeasantCollection.methods
- .setCollectionSponsorCross(sponsorCross)
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
- await expect(sponsorCollection.methods
- .confirmCollectionSponsorship()
- .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- }
- {
- await expect(malfeasantCollection.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
- }
- });
-
- itEth('destroyCollection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
-
-
- const result = await collectionHelper.methods
- .destroyCollection(collectionAddress)
- .send({from: owner});
-
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address: collectionHelper.options.address,
- event: 'CollectionDestroyed',
- args: {
- collectionId: collectionAddress,
- },
- },
- ]);
-
- expect(await collectionHelper.methods
- .isCollectionExist(collectionAddress)
- .call()).to.be.false;
- expect(await helper.collection.getData(collectionId)).to.be.null;
- });
-});
js-packages/tests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/createRFTCollection.test.ts
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {evmToAddress} from '@polkadot/util-crypto';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField} from './util/playgrounds/types.js';
-
-
-describe('Create RFT collection from EVM', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Create collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
-
- const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix);
- const data = (await helper.rft.getData(collectionId))!;
- const collection = helper.rft.getCollectionObject(collectionId);
-
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('ReFungible');
-
- const options = await collection.getOptions();
-
- expect(options.tokenPropertyPermissions).to.be.empty;
- });
-
-
-
- itEth('Create collection with properties & get description', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const name = 'CollectionEVM';
- const description = 'Some description';
- const prefix = 'token prefix';
- const baseUri = 'BaseURI';
-
- const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const collection = helper.rft.getCollectionObject(collectionId);
- const data = (await collection.getData())!;
-
- expect(data.name).to.be.eq(name);
- expect(data.description).to.be.eq(description);
- expect(data.raw.tokenPrefix).to.be.eq(prefix);
- expect(data.raw.mode).to.be.eq('ReFungible');
-
- expect(await contract.methods.description().call()).to.deep.equal(description);
-
- const options = await collection.getOptions();
- expect(options.tokenPropertyPermissions).to.be.deep.equal([
- {
- key: 'URI',
- permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
- },
- {
- key: 'URISuffix',
- permission: {mutable: true, collectionAdmin: true, tokenOwner: false},
- },
- ]);
- });
-
- // Soft-deprecated
- itEth('[eth] Set sponsorship', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');
-
- const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);
- await collection.methods.setCollectionSponsor(sponsor).send();
-
- let data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
- });
-
- itEth('[cross] Set sponsorship', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');
-
- const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await collection.methods.setCollectionSponsorCross(sponsorCross).send();
-
- let data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
-
- await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
- await sponsorCollection.methods.confirmCollectionSponsorship().send();
-
- data = (await helper.rft.getData(collectionId))!;
- expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
- });
-
- itEth('Collection address exist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
- const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())
- .to.be.false;
-
- const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT');
- expect(await collectionHelpers
- .methods.isCollectionExist(collectionAddress).call())
- .to.be.true;
-
- // check collectionOwner:
- const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- const collectionOwner = await collectionEvm.methods.collectionOwner().call();
- expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
- });
-});
-
-describe('(!negative tests!) Create RFT collection from EVM', () => {
- let donor: IKeyringPair;
- let nominal: bigint;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- {
- const MAX_NAME_LENGTH = 64;
- const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);
- const description = 'A';
- const tokenPrefix = 'A';
-
- await expect(collectionHelper.methods
- .createRFTCollection(collectionName, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
- }
- {
- const MAX_DESCRIPTION_LENGTH = 256;
- const collectionName = 'A';
- const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);
- const tokenPrefix = 'A';
- await expect(collectionHelper.methods
- .createRFTCollection(collectionName, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
- }
- {
- const MAX_TOKEN_PREFIX_LENGTH = 16;
- const collectionName = 'A';
- const description = 'A';
- const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
- await expect(collectionHelper.methods
- .createRFTCollection(collectionName, description, tokenPrefix)
- .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
- }
- });
-
- itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
- await expect(collectionHelper.methods
- .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')
- .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
-
- // Soft-deprecated
- itEth('(!negative test!) [eth] Check owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const peasant = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');
- const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true);
- const EXPECTED_ERROR = 'NoPermission';
- {
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- await expect(peasantCollection.methods
- .setCollectionSponsor(sponsor)
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
- await expect(sponsorCollection.methods
- .confirmCollectionSponsorship()
- .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- }
- {
- await expect(peasantCollection.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
- }
- });
-
- itEth('(!negative test!) [cross] Check owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const peasant = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');
- const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant);
- const EXPECTED_ERROR = 'NoPermission';
- {
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
- await expect(peasantCollection.methods
- .setCollectionSponsorCross(sponsorCross)
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
-
- const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
- await expect(sponsorCollection.methods
- .confirmCollectionSponsorship()
- .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
- }
- {
- await expect(peasantCollection.methods
- .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})
- .call()).to.be.rejectedWith(EXPECTED_ERROR);
- }
- });
-
- itEth('destroyCollection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
- const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
-
- await expect(collectionHelper.methods
- .destroyCollection(collectionAddress)
- .send({from: owner})).to.be.fulfilled;
-
- expect(await collectionHelper.methods
- .isCollectionExist(collectionAddress)
- .call()).to.be.false;
- expect(await helper.collection.getData(collectionId)).to.be.null;
- });
-});
js-packages/tests/src/eth/crossTransfer.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/crossTransfer.test.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {itEth, usingEthPlaygrounds} from './util/index.js';
-import {CrossAccountId} from '@unique/playgrounds/src/unique.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-describe('Token transfer between substrate address and EVM address. Fungible', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => {
- const bobCA = CrossAccountId.fromKeyring(bob).toICrossAccountId();
- const charlieCA = CrossAccountId.fromKeyring(charlie).toICrossAccountId();
- const charlieCAEth = CrossAccountId.fromKeyring(charlie).toEthereum().toICrossAccountId();
-
- const collection = await helper.ft.mintCollection(alice);
- await collection.setLimits(alice, {ownerCanTransfer: true});
-
- await collection.mint(alice, 200n);
- await collection.transfer(alice, charlieCAEth, 200n);
- await collection.transferFrom(alice, charlieCAEth, charlieCA, 50n);
- await collection.transfer(charlie, bobCA, 50n);
- });
-
- itEth('The private key X create a EVM address. Alice sends a token to the substrate address corresponding to this EVM address, and X can send it to Bob in the EVM', async ({helper}) => {
- const aliceProxy = await helper.eth.createAccountWithBalance(donor);
- const bobProxy = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.ft.mintCollection(alice);
- await collection.setLimits(alice, {ownerCanTransfer: true});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'ft', aliceProxy);
-
- await collection.mint(alice, 200n, {Ethereum: aliceProxy});
- await contract.methods.transfer(bobProxy, 50).send({from: aliceProxy});
- await collection.transferFrom(alice, {Ethereum: bobProxy}, CrossAccountId.fromKeyring(bob).toICrossAccountId(), 50n);
- await collection.transfer(bob, CrossAccountId.fromKeyring(alice).toICrossAccountId(), 50n);
- });
-});
-
-describe('Token transfer between substrate address and EVM address. NFT', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => {
- const charlieEth = CrossAccountId.fromKeyring(charlie, 'Ethereum').toICrossAccountId();
-
- const collection = await helper.nft.mintCollection(alice);
- await collection.setLimits(alice, {ownerCanTransfer: true});
- const token = await collection.mintToken(alice);
- await token.transfer(alice, charlieEth);
- await token.transferFrom(alice, charlieEth, CrossAccountId.fromKeyring(charlie).toICrossAccountId());
- await token.transfer(charlie, CrossAccountId.fromKeyring(bob).toICrossAccountId());
- });
-
- itEth('The private key X create a EVM address. Alice sends a token to the substrate address corresponding to this EVM address, and X can send it to Bob in the EVM', async ({helper}) => {
- const aliceProxy = await helper.eth.createAccountWithBalance(donor);
- const bobProxy = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.nft.mintCollection(alice);
- await collection.setLimits(alice, {ownerCanTransfer: true});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', aliceProxy);
-
- const token = await collection.mintToken(alice);
- await token.transfer(alice, {Ethereum: aliceProxy});
- await contract.methods.transfer(bobProxy, 1).send({from: aliceProxy});
- await token.transferFrom(alice, {Ethereum: bobProxy}, {Substrate: bob.address});
- await token.transfer(bob, {Substrate: charlie.address});
- });
-});
js-packages/tests/src/eth/destroyCollection.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/destroyCollection.test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import type {TCollectionMode} from '@unique/playgrounds/src/types.js';
-import {CreateCollectionData} from './util/playgrounds/types.js';
-
-describe('Destroy Collection from EVM', function() {
- let donor: IKeyringPair;
- const testCases = [
- {case: 'rft' as const, params: ['Limits', 'absolutely anything', 'OLF', 'rft'], requiredPallets: [Pallets.ReFungible]},
- {case: 'nft' as const, params: ['Limits', 'absolutely anything', 'OLF', 'nft'], requiredPallets: [Pallets.NFT]},
- {case: 'ft' as const, params: ['Limits', 'absolutely anything', 'OLF', 'ft', 18], requiredPallets: [Pallets.Fungible]},
- ];
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- testCases.map((testCase) =>
- itEth.ifWithPallets(`Cannot burn non-owned or non-existing collection ${testCase.case}`, testCase.requiredPallets, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const signer = await helper.eth.createAccountWithBalance(donor);
-
- const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
-
- const collectionHelpers = await helper.ethNativeContract.collectionHelpers(signer);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData(...testCase.params as [string, string, string, TCollectionMode, number?])).send();
- // cannot burn collec
- await expect(collectionHelpers.methods
- .destroyCollection(collectionAddress)
- .send({from: signer})).to.be.rejected;
-
- await expect(collectionHelpers.methods
- .destroyCollection(unexistedCollection)
- .send({from: signer})).to.be.rejected;
-
- expect(await collectionHelpers.methods
- .isCollectionExist(unexistedCollection)
- .call()).to.be.false;
-
- expect(await collectionHelpers.methods
- .isCollectionExist(collectionAddress)
- .call()).to.be.true;
- }));
-});
js-packages/tests/src/eth/ethFeesAreCorrect.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/ethFeesAreCorrect.test.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://witww.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-
-describe('Eth fees are correct', () => {
- let donor: IKeyringPair;
- let minter: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async () => {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [minter, alice] = await helper.arrange.createAccounts([100n, 200n], donor);
- });
- });
-
-
- itEth('web3 fees are the same as evm.call fees', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const aliceEth = helper.address.substrateToEth(alice.address);
-
- const {tokenId: tokenA} = await collection.mintToken(minter, {Ethereum: owner});
- const {tokenId: tokenB} = await collection.mintToken(minter, {Ethereum: aliceEth});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- const balanceBeforeWeb3Transfer = await helper.balance.getEthereum(owner);
- await contract.methods.transfer(receiver, tokenA).send({from: owner, maxFeePerGas: ((await helper.eth.getGasPrice())!).toString()});
- const balanceAfterWeb3Transfer = await helper.balance.getEthereum(owner);
- const web3Diff = balanceBeforeWeb3Transfer - balanceAfterWeb3Transfer;
-
- const encodedCall = contract.methods.transfer(receiver, tokenB)
- .encodeABI();
-
- const balanceBeforeEvmCall = await helper.balance.getSubstrate(alice.address);
- await helper.eth.sendEVM(
- alice,
- collectionAddress,
- encodedCall,
- '0',
- );
- const balanceAfterEvmCall = await helper.balance.getSubstrate(alice.address);
- const evmCallDiff = balanceBeforeEvmCall - balanceAfterEvmCall;
-
- expect(web3Diff).to.be.equal(evmCallDiff);
- });
-});
js-packages/tests/src/eth/events.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/events.test.ts
+++ /dev/null
@@ -1,548 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect} from 'chai';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import type {IEvent, TCollectionMode} from '@unique/playgrounds/src/types.js';
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {CollectionLimitField, TokenPermissionField, CreateCollectionData} from './util/playgrounds/types.js';
-import type {NormalizedEvent} from './util/playgrounds/types.js';
-
-let donor: IKeyringPair;
-
-before(async function () {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
-});
-
-function clearEvents(ethEvents: NormalizedEvent[] | null, subEvents: IEvent[]) {
- if(ethEvents !== null) {
- ethEvents.splice(0);
- }
- subEvents.splice(0);
-}
-
-async function testCollectionCreatedAndDestroy(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionCreated', 'CollectionDestroyed']}]);
- const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
-
- await helper.wait.newBlocks(1);
- {
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionCreated',
- args: {
- owner: owner,
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionCreated'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner});
- await helper.wait.newBlocks(1);
- expect(result.events).to.containSubset({
- CollectionDestroyed: {
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- });
- expect(subEvents).to.containSubset([{method: 'CollectionDestroyed'}]);
- }
- unsubscribe();
-}
-
-async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
-
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPropertySet', 'CollectionPropertyDeleted']}]);
- {
- await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionPropertySet'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- await collection.methods.deleteCollectionProperties(['A']).send({from:owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionPropertyDeleted'}]);
- }
- unsubscribe();
-}
-
-async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);
- await collection.methods.setTokenPropertyPermissions([
- ['A', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'PropertyPermissionSet'}]);
- unsubscribe();
-}
-
-async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const user = helper.ethCrossAccount.createAccount();
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any[] = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
-
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['AllowListAddressAdded', 'AllowListAddressRemoved']}]);
- {
- await collection.methods.addToCollectionAllowListCross(user).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'AllowListAddressAdded'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'AllowListAddressRemoved'}]);
- }
- unsubscribe();
-}
-
-async function testCollectionAdminAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const user = helper.ethCrossAccount.createAccount();
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionAdminAdded', 'CollectionAdminRemoved']}]);
- {
- await collection.methods.addCollectionAdminCross(user).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionAdminAdded'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- await collection.methods.removeCollectionAdminCross(user).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionAdminRemoved'}]);
- }
- unsubscribe();
-}
-
-async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionLimitSet']}]);
- {
- await collection.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: 0}}).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionLimitSet'}]);
- }
- unsubscribe();
-}
-
-async function testCollectionOwnerChanged(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const newOwner = helper.ethCrossAccount.createAccount();
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnerChanged']}]);
- {
- await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionOwnerChanged'}]);
- }
- unsubscribe();
-}
-
-async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPermissionSet']}]);
- {
- await collection.methods.setCollectionMintMode(true).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- await collection.methods.setCollectionAccess(1).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);
- }
- unsubscribe();
-}
-
-async function testCollectionSponsorSetAndConfirmedAndThenRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
- const ethEvents: any = [];
- collectionHelper.events.allEvents((_: any, event: any) => {
- ethEvents.push(event);
- });
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{
- section: 'common', names: ['CollectionSponsorSet', 'SponsorshipConfirmed', 'CollectionSponsorRemoved',
- ]}]);
- {
- await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([{
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- }]);
- expect(subEvents).to.containSubset([{method: 'CollectionSponsorSet'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'SponsorshipConfirmed'}]);
- clearEvents(ethEvents, subEvents);
- }
- {
- await collection.methods.removeCollectionSponsor().send({from: owner});
- await helper.wait.newBlocks(1);
- expect(ethEvents).to.containSubset([
- {
- event: 'CollectionChanged',
- returnValues: {
- collectionId: collectionAddress,
- },
- },
- ]);
- expect(subEvents).to.containSubset([{method: 'CollectionSponsorRemoved'}]);
- }
- unsubscribe();
-}
-
-async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', mode, 18)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
- const result = await collection.methods.mint(owner).send({from: owner});
- const tokenId = result.events.Transfer.returnValues.tokenId;
- await collection.methods.setTokenPropertyPermissions([
- ['A', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).send({from: owner});
-
- const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]);
- {
- const result = await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(result.events.TokenChanged).to.be.like({
- event: 'TokenChanged',
- returnValues: {
- tokenId: tokenId,
- },
- });
- expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]);
- clearEvents(null, subEvents);
- }
- {
- const result = await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});
- await helper.wait.newBlocks(1);
- expect(result.events.TokenChanged).to.be.like({
- event: 'TokenChanged',
- returnValues: {
- tokenId: tokenId,
- },
- });
- expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]);
- }
- unsubscribe();
-}
-
-describe('[FT] Sync sub & eth events', () => {
- const mode: TCollectionMode = 'ft';
-
- itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
- await testCollectionCreatedAndDestroy(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {
- await testCollectionPropertySetAndDeleted(helper, mode);
- });
-
- itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {
- await testAllowListAddressAddedAndRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {
- await testCollectionAdminAddedAndRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {
- await testCollectionLimitSet(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
- await testCollectionOwnerChanged(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {
- await testCollectionPermissionSet(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {
- await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);
- });
-});
-
-describe('[NFT] Sync sub & eth events', () => {
- const mode: TCollectionMode = 'nft';
-
- itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
- await testCollectionCreatedAndDestroy(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {
- await testCollectionPropertySetAndDeleted(helper, mode);
- });
-
- itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {
- await testPropertyPermissionSet(helper, mode);
- });
-
- itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {
- await testAllowListAddressAddedAndRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {
- await testCollectionAdminAddedAndRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {
- await testCollectionLimitSet(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
- await testCollectionOwnerChanged(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {
- await testCollectionPermissionSet(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {
- await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {
- await testTokenPropertySetAndDeleted(helper, mode);
- });
-});
-
-describe('[RFT] Sync sub & eth events', () => {
- const mode: TCollectionMode = 'rft';
-
- before(async function() {
- await usingEthPlaygrounds((helper) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- return Promise.resolve();
- });
- });
-
- itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
- await testCollectionCreatedAndDestroy(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => {
- await testCollectionPropertySetAndDeleted(helper, mode);
- });
-
- itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => {
- await testPropertyPermissionSet(helper, mode);
- });
-
- itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => {
- await testAllowListAddressAddedAndRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => {
- await testCollectionAdminAddedAndRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => {
- await testCollectionLimitSet(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
- await testCollectionOwnerChanged(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => {
- await testCollectionPermissionSet(helper, mode);
- });
-
- itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => {
- await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode);
- });
-
- itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => {
- await testTokenPropertySetAndDeleted(helper, mode);
- });
-});
js-packages/tests/src/eth/evmCoder.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/evmCoder.test.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
-
-const getContractSource = (collectionAddress: string, contractAddress: string): string => `
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.0;
- interface ITest {
- function ztestzzzzzzz() external returns (uint256 n);
- }
- contract Test {
- event Result(bool, uint256);
- function test1() public {
- try
- ITest(${collectionAddress}).ztestzzzzzzz()
- returns (uint256 n) {
- // enters
- emit Result(true, n); // => [true, BigNumber { value: "43648854190028290368124427828690944273759144372138548774646036134290060795932" }]
- } catch {
- emit Result(false, 0);
- }
- }
- function test2() public {
- try
- ITest(${contractAddress}).ztestzzzzzzz()
- returns (uint256 n) {
- emit Result(true, n);
- } catch {
- // enters
- emit Result(false, 0); // => [ false, BigNumber { value: "0" } ]
- }
- }
- function test3() public {
- ITest(${collectionAddress}).ztestzzzzzzz();
- }
- }
- `;
-
-
-describe('Evm Coder tests', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Call non-existing function', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.eth.createNFTCollection(owner, 'EVMCODER', '', 'TEST');
- const contract = await helper.ethContract.deployByCode(owner, 'Test', getContractSource(collection.collectionAddress, '0x1bfed5D614b886b9Ab2eA4CBAc22A96B7EC29c9c'));
- const testContract = await helper.ethContract.deployByCode(owner, 'Test', getContractSource(collection.collectionAddress, contract.options.address));
- {
- const result = await testContract.methods.test1().send();
- expect(result.events.Result.returnValues).to.deep.equal({
- '0': false,
- '1': '0',
- });
- }
- {
- const result = await testContract.methods.test2().send();
- expect(result.events.Result.returnValues).to.deep.equal({
- '0': false,
- '1': '0',
- });
- }
- {
- await expect(testContract.methods.test3().call())
- .to.be.rejectedWith(/unrecognized selector: 0xd9f02b36$/g);
- }
- });
-});
js-packages/tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/fractionalizer/Fractionalizer.sol
+++ /dev/null
@@ -1,172 +0,0 @@
-// SPDX-License-Identifier: Apache License
-pragma solidity >=0.8.0;
-import {CollectionHelpers} from "../api/CollectionHelpers.sol";
-import {ContractHelpers} from "../api/ContractHelpers.sol";
-import {UniqueRefungibleToken} from "../api/UniqueRefungibleToken.sol";
-import {UniqueRefungible, CrossAddress} from "../api/UniqueRefungible.sol";
-import {UniqueNFT} from "../api/UniqueNFT.sol";
-
-/// @dev Fractionalization contract. It stores mappings between NFT and RFT tokens,
-/// stores allowlist of NFT tokens available for fractionalization, has methods
-/// for fractionalization and defractionalization of NFT tokens.
-contract Fractionalizer {
- struct Token {
- address _collection;
- uint256 _tokenId;
- }
- address rftCollection;
- mapping(address => bool) nftCollectionAllowList;
- mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;
- mapping(address => Token) public rft2nftMapping;
- //use constant to reduce gas cost
- bytes32 constant refungibleCollectionType = keccak256(bytes("ReFungible"));
-
- receive() external payable onlyOwner {}
-
- /// @dev Method modifier to only allow contract owner to call it.
- modifier onlyOwner() {
- address contracthelpersAddress = 0x842899ECF380553E8a4de75bF534cdf6fBF64049;
- ContractHelpers contractHelpers = ContractHelpers(contracthelpersAddress);
- address contractOwner = contractHelpers.contractOwner(address(this));
- require(msg.sender == contractOwner, "Only owner can");
- _;
- }
-
- /// @dev This emits when RFT collection setting is changed.
- event RFTCollectionSet(address _collection);
-
- /// @dev This emits when NFT collection is allowed or disallowed.
- event AllowListSet(address _collection, bool _status);
-
- /// @dev This emits when NFT token is fractionalized by contract.
- event Fractionalized(address _collection, uint256 _tokenId, address _rftToken, uint128 _amount);
-
- /// @dev This emits when NFT token is defractionalized by contract.
- event Defractionalized(address _rftToken, address _nftCollection, uint256 _nftTokenId);
-
- /// Set RFT collection that contract will work with. RFT tokens for fractionalized NFT tokens
- /// would be created in this collection.
- /// @dev Throws if RFT collection is already configured for this contract.
- /// Throws if collection of wrong type (NFT, Fungible) is provided instead
- /// of RFT collection.
- /// Throws if `msg.sender` is not owner or admin of provided RFT collection.
- /// Can only be called by contract owner.
- /// @param _collection address of RFT collection.
- function setRFTCollection(address _collection) external onlyOwner {
- require(rftCollection == address(0), "RFT collection is already set");
- UniqueRefungible refungibleContract = UniqueRefungible(_collection);
- string memory collectionType = refungibleContract.uniqueCollectionType();
-
- // compare hashed to reduce gas cost
- require(
- keccak256(bytes(collectionType)) == refungibleCollectionType,
- "Wrong collection type. Collection is not refungible."
- );
- require(
- refungibleContract.isOwnerOrAdminCross(CrossAddress({eth: address(this), sub: uint256(0)})),
- "Fractionalizer contract should be an admin of the collection"
- );
- rftCollection = _collection;
- emit RFTCollectionSet(rftCollection);
- }
-
- /// Creates and sets RFT collection that contract will work with. RFT tokens for fractionalized NFT tokens
- /// would be created in this collection.
- /// @dev Throws if RFT collection is already configured for this contract.
- /// Can only be called by contract owner.
- /// @param _name name for created RFT collection.
- /// @param _description description for created RFT collection.
- /// @param _tokenPrefix token prefix for created RFT collection.
- function createAndSetRFTCollection(
- string calldata _name,
- string calldata _description,
- string calldata _tokenPrefix
- ) external payable onlyOwner {
- require(rftCollection == address(0), "RFT collection is already set");
- address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
- rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection{value: msg.value}(
- _name,
- _description,
- _tokenPrefix
- );
- emit RFTCollectionSet(rftCollection);
- }
-
- /// Allow or disallow NFT collection tokens from being fractionalized by this contract.
- /// @dev Can only be called by contract owner.
- /// @param collection NFT token address.
- /// @param status `true` to allow and `false` to disallow NFT token.
- function setNftCollectionIsAllowed(address collection, bool status) external onlyOwner {
- nftCollectionAllowList[collection] = status;
- emit AllowListSet(collection, status);
- }
-
- /// Fractionilize NFT token.
- /// @dev Takes NFT token from `msg.sender` and transfers RFT token to `msg.sender`
- /// instead. Creates new RFT token if provided NFT token never was fractionalized
- /// by this contract or existing RFT token if it was.
- /// Throws if RFT collection isn't configured for this contract.
- /// Throws if fractionalization of provided NFT token is not allowed
- /// Throws if `msg.sender` is not owner of provided NFT token
- /// @param _collection NFT collection address
- /// @param _token id of NFT token to be fractionalized
- /// @param _pieces number of pieces new RFT token would have
- function nft2rft(
- address _collection,
- uint256 _token,
- uint128 _pieces
- ) external {
- require(rftCollection != address(0), "RFT collection is not set");
- UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
- require(
- nftCollectionAllowList[_collection] == true,
- "Fractionalization of this collection is not allowed by admin"
- );
- require(UniqueNFT(_collection).ownerOf(_token) == msg.sender, "Only token owner could fractionalize it");
- UniqueNFT(_collection).transferFrom(msg.sender, address(this), _token);
- uint256 rftTokenId;
- address rftTokenAddress;
- UniqueRefungibleToken rftTokenContract;
- if (nft2rftMapping[_collection][_token] == 0) {
- rftTokenId = rftCollectionContract.mint(address(this));
- rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);
- nft2rftMapping[_collection][_token] = rftTokenId;
- rft2nftMapping[rftTokenAddress] = Token(_collection, _token);
-
- rftTokenContract = UniqueRefungibleToken(rftTokenAddress);
- } else {
- rftTokenId = nft2rftMapping[_collection][_token];
- rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);
- rftTokenContract = UniqueRefungibleToken(rftTokenAddress);
- }
- rftTokenContract.repartition(_pieces);
- rftTokenContract.transfer(msg.sender, _pieces);
- emit Fractionalized(_collection, _token, rftTokenAddress, _pieces);
- }
-
- /// Defrationalize NFT token.
- /// @dev Takes RFT token from `msg.sender` and transfers corresponding NFT token
- /// to `msg.sender` instead.
- /// Throws if RFT collection isn't configured for this contract.
- /// Throws if provided RFT token is no from configured RFT collection.
- /// Throws if RFT token was not created by this contract.
- /// Throws if `msg.sender` isn't owner of all RFT token pieces.
- /// @param _collection RFT collection address
- /// @param _token id of RFT token
- function rft2nft(address _collection, uint256 _token) external {
- require(rftCollection != address(0), "RFT collection is not set");
- require(rftCollection == _collection, "Wrong RFT collection");
- UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
- address rftTokenAddress = rftCollectionContract.tokenContractAddress(_token);
- Token memory nftToken = rft2nftMapping[rftTokenAddress];
- require(nftToken._collection != address(0), "No corresponding NFT token found");
- UniqueRefungibleToken rftTokenContract = UniqueRefungibleToken(rftTokenAddress);
- require(
- rftTokenContract.balanceOf(msg.sender) == rftTokenContract.totalSupply(),
- "Not all pieces are owned by the caller"
- );
- rftCollectionContract.transferFrom(msg.sender, address(this), _token);
- UniqueNFT(nftToken._collection).transferFrom(address(this), msg.sender, nftToken._tokenId);
- emit Defractionalized(rftTokenAddress, nftToken._collection, nftToken._tokenId);
- }
-}
js-packages/tests/src/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/fractionalizer/fractionalizer.test.ts
+++ /dev/null
@@ -1,453 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-
-import {readFile} from 'fs/promises';
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {evmToAddress} from '@polkadot/util-crypto';
-
-import {Contract} from 'web3-eth-contract';
-
-import {usingEthPlaygrounds, expect, itEth} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
-import type {CompiledContract} from '../util/playgrounds/types.js';
-import {requirePalletsOrSkip, Pallets, makeNames} from '../../util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-let compiledFractionalizer: CompiledContract;
-
-const compileContract = async (helper: EthUniqueHelper): Promise<CompiledContract> => {
- if(!compiledFractionalizer) {
- compiledFractionalizer = await helper.ethContract.compile('Fractionalizer', (await readFile(`${dirname}/Fractionalizer.sol`)).toString(), [
- {solPath: 'api/CollectionHelpers.sol', fsPath: `${dirname}/../api/CollectionHelpers.sol`},
- {solPath: 'api/ContractHelpers.sol', fsPath: `${dirname}/../api/ContractHelpers.sol`},
- {solPath: 'api/UniqueRefungibleToken.sol', fsPath: `${dirname}/../api/UniqueRefungibleToken.sol`},
- {solPath: 'api/UniqueRefungible.sol', fsPath: `${dirname}/../api/UniqueRefungible.sol`},
- {solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`},
- ]);
- }
- return compiledFractionalizer;
-};
-
-
-const deployContract = async (helper: EthUniqueHelper, owner: string): Promise<Contract> => {
- const compiled = await compileContract(helper);
- return await helper.ethContract.deployByAbi(owner, compiled.abi, compiled.object);
-};
-
-
-const initContract = async (helper: EthUniqueHelper, owner: string): Promise<{contract: Contract, rftCollectionAddress: string}> => {
- const fractionalizer = await deployContract(helper, owner);
- const amount = 10n * helper.balance.getOneTokenNominal();
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: owner, to: fractionalizer.options.address, value: `${amount}`, gas: helper.eth.DEFAULT_GAS});
- const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({value: Number(2n * helper.balance.getOneTokenNominal())});
- const rftCollectionAddress = result.events.RFTCollectionSet.returnValues._collection;
- return {contract: fractionalizer, rftCollectionAddress};
-};
-
-const mintRFTToken = async (helper: EthUniqueHelper, owner: string, fractionalizer: Contract, amount: bigint): Promise<{
- nftCollectionAddress: string, nftTokenId: number, rftTokenAddress: string
-}> => {
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
- await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
- const result = await fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, amount).send({from: owner});
- const {_collection, _tokenId, _rftToken} = result.events.Fractionalized.returnValues;
- return {
- nftCollectionAddress: _collection,
- nftTokenId: _tokenId,
- rftTokenAddress: _rftToken,
- };
-};
-
-
-describe('Fractionalizer contract usage', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Set RFT collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const fractionalizer = await deployContract(helper, owner);
- const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
- const rftContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
-
- const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
- await rftContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
- const result = await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});
- expect(result.events).to.be.like({
- RFTCollectionSet: {
- returnValues: {
- _collection: rftCollection.collectionAddress,
- },
- },
- });
- });
-
- itEth('Mint RFT collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const fractionalizer = await deployContract(helper, owner);
- await helper.balance.transferToSubstrate(donor, evmToAddress(fractionalizer.options.address), 10n * helper.balance.getOneTokenNominal());
-
- const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({from: owner, value: Number(2n * helper.balance.getOneTokenNominal())});
- expect(result.events).to.be.like({
- RFTCollectionSet: {},
- });
- expect(result.events.RFTCollectionSet.returnValues._collection).to.be.ok;
- });
-
- itEth('Set Allowlist', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {contract: fractionalizer} = await initContract(helper, owner);
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
-
- const result1 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
- expect(result1.events).to.be.like({
- AllowListSet: {
- returnValues: {
- _collection: nftCollection.collectionAddress,
- _status: true,
- },
- },
- });
- const result2 = await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, false).send({from: owner});
- expect(result2.events).to.be.like({
- AllowListSet: {
- returnValues: {
- _collection: nftCollection.collectionAddress,
- _status: false,
- },
- },
- });
- });
-
- itEth('NFT to RFT', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- const {contract: fractionalizer} = await initContract(helper, owner);
-
- await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
- await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
- const result = await fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).send({from: owner});
- expect(result.events).to.be.like({
- Fractionalized: {
- returnValues: {
- _collection: nftCollection.collectionAddress,
- _tokenId: nftTokenId,
- _amount: '100',
- },
- },
- });
- const rftTokenAddress = result.events.Fractionalized.returnValues._rftToken;
-
- // FIXME: should work without the caller
- const rftTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress);
- expect(await rftTokenContract.methods.balanceOf(owner).call()).to.equal('100');
- });
-
- itEth('RFT to NFT', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);
- const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await mintRFTToken(helper, owner, fractionalizer, 100n);
-
- const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);
- const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId);
- expect(rftCollectionAddress).to.be.equal(refungibleAddress);
- const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner);
- await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner});
- const result = await fractionalizer.methods.rft2nft(refungibleAddress, tokenId).send({from: owner});
- expect(result.events).to.be.like({
- Defractionalized: {
- returnValues: {
- _rftToken: rftTokenAddress,
- _nftCollection: nftCollectionAddress,
- _nftTokenId: nftTokenId,
- },
- },
- });
- });
-
- itEth('Test fractionalizer NFT <-> RFT mapping ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);
- const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await mintRFTToken(helper, owner, fractionalizer, 100n);
-
- const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);
- const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId);
- expect(rftCollectionAddress).to.be.equal(refungibleAddress);
- const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner);
- await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner});
-
- const rft2nft = await fractionalizer.methods.rft2nftMapping(rftTokenAddress).call();
- expect(rft2nft).to.be.like({
- _collection: nftCollectionAddress,
- _tokenId: nftTokenId,
- });
-
- const nft2rft = await fractionalizer.methods.nft2rftMapping(nftCollectionAddress, nftTokenId).call();
- expect(nft2rft).to.be.eq(tokenId.toString());
- });
-});
-
-
-
-describe('Negative Integration Tests for fractionalizer', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('call setRFTCollection twice', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
- const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
-
- const fractionalizer = await deployContract(helper, owner);
- const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
- await refungibleContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
- await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});
-
- await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call())
- .to.be.rejectedWith(/RFT collection is already set$/g);
- });
-
- itEth('call setRFTCollection with NFT collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
-
- const fractionalizer = await deployContract(helper, owner);
- const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
- await nftContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
-
- await expect(fractionalizer.methods.setRFTCollection(nftCollection.collectionAddress).call())
- .to.be.rejectedWith(/Wrong collection type. Collection is not refungible.$/g);
- });
-
- itEth('call setRFTCollection while not collection admin', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const fractionalizer = await deployContract(helper, owner);
- const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
-
- await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call())
- .to.be.rejectedWith(/Fractionalizer contract should be an admin of the collection$/g);
- });
-
- itEth('call setRFTCollection after createAndSetRFTCollection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const fractionalizer = await deployContract(helper, owner);
- await helper.balance.transferToSubstrate(donor, evmToAddress(fractionalizer.options.address), 10n * helper.balance.getOneTokenNominal());
-
- const result = await fractionalizer.methods.createAndSetRFTCollection('A', 'B', 'C').send({from: owner, value: Number(2n * helper.balance.getOneTokenNominal())});
- const collectionIdAddress = result.events.RFTCollectionSet.returnValues._collection;
-
- await expect(fractionalizer.methods.setRFTCollection(collectionIdAddress).call())
- .to.be.rejectedWith(/RFT collection is already set$/g);
- });
-
- itEth('call nft2rft without setting RFT collection for contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- const fractionalizer = await deployContract(helper, owner);
-
- await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())
- .to.be.rejectedWith(/RFT collection is not set$/g);
- });
-
- itEth('call nft2rft while not owner of NFT token', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const nftOwner = await helper.eth.createAccountWithBalance(donor);
-
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
- await nftContract.methods.transfer(nftOwner, 1).send({from: owner});
-
-
- const {contract: fractionalizer} = await initContract(helper, owner);
- await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
-
- await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call({from: owner}))
- .to.be.rejectedWith(/Only token owner could fractionalize it$/g);
- });
-
- itEth('call nft2rft while not in list of allowed accounts', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- const {contract: fractionalizer} = await initContract(helper, owner);
-
- await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
- await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())
- .to.be.rejectedWith(/Fractionalization of this collection is not allowed by admin$/g);
- });
-
- itEth('call nft2rft while fractionalizer doesnt have approval for nft token', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- const {contract: fractionalizer} = await initContract(helper, owner);
-
- await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
- await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100).call())
- .to.be.rejectedWith(/ApprovedValueTooLow$/g);
- });
-
- itEth('call rft2nft without setting RFT collection for contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const fractionalizer = await deployContract(helper, owner);
- const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
- const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
- const mintResult = await refungibleContract.methods.mint(owner).send({from: owner});
- const rftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call({from: owner}))
- .to.be.rejectedWith(/RFT collection is not set$/g);
- });
-
- itEth('call rft2nft for RFT token that is not from configured RFT collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {contract: fractionalizer} = await initContract(helper, owner);
- const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
- const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
- const mintResult = await refungibleContract.methods.mint(owner).send({from: owner});
- const rftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call())
- .to.be.rejectedWith(/Wrong RFT collection$/g);
- });
-
- itEth('call rft2nft for RFT token that was not minted by fractionalizer contract', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT');
- const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner);
-
- const fractionalizer = await deployContract(helper, owner);
-
- const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address);
- await refungibleContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner});
- await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner});
-
- const mintResult = await refungibleContract.methods.mint(owner).send({from: owner});
- const rftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call())
- .to.be.rejectedWith(/No corresponding NFT token found$/g);
- });
-
- itEth('call rft2nft without owning all RFT pieces', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
-
- const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner);
- const {rftTokenAddress} = await mintRFTToken(helper, owner, fractionalizer, 100n);
-
- const {tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress);
- const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner);
- await refungibleTokenContract.methods.transfer(receiver, 50).send({from: owner});
- await refungibleTokenContract.methods.approve(fractionalizer.options.address, 50).send({from: receiver});
- await expect(fractionalizer.methods.rft2nft(rftCollectionAddress, tokenId).call({from: receiver}))
- .to.be.rejectedWith(/Not all pieces are owned by the caller$/g);
- });
-
- itEth('send QTZ/UNQ to contract from non owner', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const payer = await helper.eth.createAccountWithBalance(donor);
-
- const fractionalizer = await deployContract(helper, owner);
- const amount = 10n * helper.balance.getOneTokenNominal();
- const web3 = helper.getWeb3();
- await expect(web3.eth.sendTransaction({from: payer, to: fractionalizer.options.address, value: `${amount}`, gas: helper.eth.DEFAULT_GAS})).to.be.rejected;
- });
-
- itEth('fractionalize NFT with NFT transfers disallowed', async ({helper}) => {
- const nftCollection = await helper.nft.mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const nftToken = await nftCollection.mintToken(donor, {Ethereum: owner});
- await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [nftCollection.collectionId, false], true);
- const nftCollectionAddress = helper.ethAddress.fromCollectionId(nftCollection.collectionId);
- const {contract: fractionalizer} = await initContract(helper, owner);
- await fractionalizer.methods.setNftCollectionIsAllowed(nftCollectionAddress, true).send({from: owner});
-
- const nftContract = await helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);
- await nftContract.methods.approve(fractionalizer.options.address, nftToken.tokenId).send({from: owner});
- await expect(fractionalizer.methods.nft2rft(nftCollectionAddress, nftToken.tokenId, 100).call())
- .to.be.rejectedWith(/TransferNotAllowed$/g);
- });
-
- itEth('fractionalize NFT with RFT transfers disallowed', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const rftCollection = await helper.rft.mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const rftCollectionAddress = helper.ethAddress.fromCollectionId(rftCollection.collectionId);
- const fractionalizer = await deployContract(helper, owner);
- await rftCollection.addAdmin(donor, {Ethereum: fractionalizer.options.address});
-
- await fractionalizer.methods.setRFTCollection(rftCollectionAddress).send({from: owner});
- await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [rftCollection.collectionId, false], true);
-
- const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT');
- const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner);
- const mintResult = await nftContract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintResult.events.Transfer.returnValues.tokenId;
-
- await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner});
- await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner});
-
- await expect(fractionalizer.methods.nft2rft(nftCollection.collectionAddress, nftTokenId, 100n).call())
- .to.be.rejectedWith(/TransferNotAllowed$/g);
- });
-});
js-packages/tests/src/eth/fungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/fungible.test.ts
+++ /dev/null
@@ -1,643 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-describe('Fungible: Plain calls', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let owner: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, owner] = await helper.arrange.createAccounts([30n, 20n], donor);
- });
- });
-
- [
- 'substrate' as const,
- 'ethereum' as const,
- ].map(testCase => {
- itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
- // 1. Create receiver depending on the test case:
- const receiverEth = helper.eth.createAccount();
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const receiverSub = owner;
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(owner);
-
- const ethOwner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.ft.mintCollection(alice);
- await collection.addAdmin(alice, {Ethereum: ethOwner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner);
-
- // 2. Mint tokens:
- const result = await collectionEvm.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, 100).send();
-
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(receiverSub.address));
- expect(event.returnValues.value).to.equal('100');
-
- // 3. Get balance depending on the test case:
- let balance;
- if(testCase === 'ethereum') balance = await collection.getBalance({Ethereum: receiverEth});
- else if(testCase === 'substrate') balance = await collection.getBalance({Substrate: receiverSub.address});
- // 3.1 Check balance:
- expect(balance).to.eq(100n);
- });
- });
-
- itEth('Can perform mintBulk()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const bulkSize = 3;
- const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());
- const collection = await helper.ft.mintCollection(alice);
- await collection.addAdmin(alice, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (
- [receivers[i], (i + 1) * 10]
- ))).send();
- const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);
- for(let i = 0; i < bulkSize; i++) {
- const event = events[i];
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receivers[i]);
- expect(event.returnValues.value).to.equal(String(10 * (i + 1)));
- }
- });
-
- // Soft-deprecated
- itEth('Can perform burn()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.ft.mintCollection(alice);
- await collection.addAdmin(alice, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
- await contract.methods.mint(receiver, 100).send();
-
- const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});
-
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal(receiver);
- expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.value).to.equal('49');
-
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(balance).to.equal('51');
- });
-
- itEth('Can perform approve()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- {
- const result = await contract.methods.approve(spender, 100).send({from: owner});
-
- const event = result.events.Approval;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(spender);
- expect(event.returnValues.value).to.be.equal('100');
- }
-
- {
- const allowance = await contract.methods.allowance(owner, spender).call();
- expect(+allowance).to.equal(100);
- }
- {
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const spenderCross = helper.ethCrossAccount.fromAddress(spender);
- const allowance = await contract.methods.allowanceCross(ownerCross, spenderCross).call();
- expect(+allowance).to.equal(100);
- }
- });
-
- itEth('Can perform approveCross()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0];
- const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);
- const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub);
-
-
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- {
- const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});
- const event = result.events.Approval;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(spender);
- expect(event.returnValues.value).to.be.equal('100');
- }
-
- {
- const allowance = await contract.methods.allowance(owner, spender).call();
- expect(+allowance).to.equal(100);
- }
-
-
- {
- const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner});
- const event = result.events.Approval;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address));
- expect(event.returnValues.value).to.be.equal('100');
- }
-
- {
- const allowance = await collection.getApprovedTokens({Ethereum: owner}, {Substrate: spenderSub.address});
- expect(allowance).to.equal(100n);
- }
-
- {
- //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call()
- }
- });
-
- itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {
- const nonOwner = await helper.eth.createAccountWithBalance(donor);
- const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
- await collection.mint(alice, 100n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- await expect(collectionEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');
- });
-
-
- itEth('Can perform burnFromCross()', async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
-
- await collection.mint(owner, 200n, {Substrate: owner.address});
- await collection.approveTokens(owner, {Ethereum: sender}, 100n);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'ft');
-
- const fromBalanceBefore = await collection.getBalance({Substrate: owner.address});
-
- const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
- const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});
- const events = result.events;
-
- expect(events).to.be.like({
- Transfer: {
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: '0x0000000000000000000000000000000000000000',
- value: '49',
- },
- },
- Approval: {
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- returnValues: {
- owner: helper.address.substrateToEth(owner.address),
- spender: sender,
- value: '51',
- },
- event: 'Approval',
- },
- });
-
- const fromBalanceAfter = await collection.getBalance({Substrate: owner.address});
- expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);
- });
-
- itEth('Can perform transferFrom()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- await contract.methods.approve(spender, 100).send();
-
- {
- const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
-
- let event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('49');
-
- event = result.events.Approval;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(spender);
- expect(event.returnValues.value).to.be.equal('51');
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(49);
- }
-
- {
- const balance = await contract.methods.balanceOf(owner).call();
- expect(+balance).to.equal(151);
- }
- });
-
- itEth('Can perform transferCross()', async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
- const receiverEth = await helper.eth.createAccountWithBalance(donor);
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(donor);
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: sender});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
-
- {
- // Can transferCross to ethereum address:
- const result = await collectionEvm.methods.transferCross(receiverCrossEth, 50).send({from: sender});
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(sender);
- expect(event.returnValues.to).to.be.equal(receiverEth);
- expect(event.returnValues.value).to.be.equal('50');
- // Sender's balance decreased:
- const ownerBalance = await collectionEvm.methods.balanceOf(sender).call();
- expect(+ownerBalance).to.equal(150);
- // Receiver's balance increased:
- const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
- expect(+receiverBalance).to.equal(50);
- }
-
- {
- // Can transferCross to substrate address:
- const result = await collectionEvm.methods.transferCross(receiverCrossSub, 50).send({from: sender});
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(sender);
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address));
- expect(event.returnValues.value).to.be.equal('50');
- // Sender's balance decreased:
- const senderBalance = await collection.getBalance({Ethereum: sender});
- expect(senderBalance).to.equal(100n);
- // Receiver's balance increased:
- const balance = await collection.getBalance({Substrate: donor.address});
- expect(balance).to.equal(50n);
- }
- });
-
- ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} incorrect amount`, async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
- const receiverEth = await helper.eth.createAccountWithBalance(donor);
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const BALANCE = 200n;
- const BALANCE_TO_TRANSFER = BALANCE + 100n;
-
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, BALANCE, {Ethereum: sender});
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
-
- // 1. Cannot transfer more than have
- const receiver = testCase === 'transfer' ? receiverEth : receiverCrossEth;
- await expect(collectionEvm.methods[testCase](receiver, BALANCE_TO_TRANSFER).send({from: sender})).to.be.rejected;
- // 2. Zero transfer allowed (EIP-20):
- await collectionEvm.methods[testCase](receiver, 0n).send({from: sender});
- }));
-
-
- itEth('Can perform transfer()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- {
- const result = await contract.methods.transfer(receiver, 50).send({from: owner});
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('50');
- }
-
- {
- const balance = await contract.methods.balanceOf(owner).call();
- expect(+balance).to.equal(150);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(50);
- }
- });
-
- itEth('Can perform transferFromCross()', async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
-
- const receiver = helper.eth.createAccount();
-
- await collection.mint(owner, 200n, {Substrate: owner.address});
- await collection.approveTokens(owner, {Ethereum: sender}, 100n);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'ft');
-
- const from = helper.ethCrossAccount.fromKeyringPair(owner);
- const to = helper.ethCrossAccount.fromAddress(receiver);
-
- const fromBalanceBefore = await collection.getBalance({Substrate: owner.address});
- const toBalanceBefore = await collection.getBalance({Ethereum: receiver});
-
- const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});
-
- expect(result.events).to.be.like({
- Transfer: {
- address,
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: receiver,
- value: '51',
- },
- },
- Approval: {
- address,
- event: 'Approval',
- returnValues: {
- owner: helper.address.substrateToEth(owner.address),
- spender: sender,
- value: '49',
- },
- }});
-
- const fromBalanceAfter = await collection.getBalance({Substrate: owner.address});
- expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);
- const toBalanceAfter = await collection.getBalance({Ethereum: receiver});
- expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);
- });
-
- itEth('Check balanceOfCross()', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {});
- const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const other = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner.eth);
-
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
- expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
-
- await collection.mint(alice, 100n, {Ethereum: owner.eth});
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100');
- expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
-
- await collectionEvm.methods.transferCross(other, 50n).send({from: owner.eth});
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('50');
- expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('50');
-
- await collectionEvm.methods.transferCross(other, 50n).send({from: owner.eth});
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
- expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('100');
-
- await collectionEvm.methods.transferCross(owner, 100n).send({from: other.eth});
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100');
- expect(await collectionEvm.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
- });
-});
-
-describe('Fungible: Fees', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([20n], donor);
- });
- });
-
- itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-
- itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- await contract.methods.approve(spender, 100).send({from: owner});
-
- const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-
- itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-});
-
-describe('Fungible: Substrate calls', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let owner: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, owner] = await helper.arrange.createAccounts([20n, 20n], donor);
- });
- });
-
- itEth('Events emitted for approve()', async ({helper}) => {
- const receiver = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await collection.approveTokens(alice, {Ethereum: receiver}, 100n);
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Approval');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.spender).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('100');
- });
-
- itEth('Events emitted for transferFrom()', async ({helper}) => {
- const [bob] = await helper.arrange.createAccounts([10n], donor);
- const receiver = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n);
- await collection.approveTokens(alice, {Substrate: bob.address}, 100n);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);
- if(events.length == 0) await helper.wait.newBlocks(1);
- let event = events[0];
-
- expect(event.event).to.be.equal('Transfer');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('51');
-
- event = events[1];
- expect(event.event).to.be.equal('Approval');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
- expect(event.returnValues.value).to.be.equal('49');
- });
-
- itEth('Events emitted for transfer()', async ({helper}) => {
- const receiver = helper.eth.createAccount();
- const collection = await helper.ft.mintCollection(alice);
- await collection.mint(alice, 200n);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await collection.transfer(alice, {Ethereum:receiver}, 51n);
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Transfer');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('51');
- });
-
- itEth('Events emitted for transferFromCross()', async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
-
- const receiver = helper.eth.createAccount();
-
- await collection.mint(owner, 200n, {Substrate: owner.address});
- await collection.approveTokens(owner, {Ethereum: sender}, 100n);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'ft');
-
- const from = helper.ethCrossAccount.fromKeyringPair(owner);
- const to = helper.ethCrossAccount.fromAddress(receiver);
-
- const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});
-
- expect(result.events).to.be.like({
- Transfer: {
- address,
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: receiver,
- value: '51',
- },
- },
- Approval: {
- address,
- event: 'Approval',
- returnValues: {
- owner: helper.address.substrateToEth(owner.address),
- spender: sender,
- value: '49',
- },
- }});
- });
-});
js-packages/tests/src/eth/getCode.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/getCode.test.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {COLLECTION_HELPER, CONTRACT_HELPER} from '../util/index.js';
-
-describe('RPC eth_getCode', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {address: COLLECTION_HELPER},
- {address: CONTRACT_HELPER},
- ].map(testCase => {
- itEth(`returns value for native contract: ${testCase.address}`, async ({helper}) => {
- const contractCodeSub = (await helper.callRpc('api.rpc.eth.getCode', [testCase.address])).toJSON();
- const contractCodeEth = (await helper.getWeb3().eth.getCode(testCase.address));
-
- expect(contractCodeSub).to.has.length.greaterThan(4);
- expect(contractCodeEth).to.has.length.greaterThan(4);
- });
- });
-
- itEth('returns value for custom contract', async ({helper}) => {
- const signer = await helper.eth.createAccountWithBalance(donor);
- const flipper = await helper.eth.deployFlipper(signer);
-
- const contractCodeSub = (await helper.callRpc('api.rpc.eth.getCode', [flipper.options.address])).toJSON();
- const contractCodeEth = (await helper.getWeb3().eth.getCode(flipper.options.address));
-
- expect(contractCodeSub).to.has.length.greaterThan(4);
- expect(contractCodeEth).to.has.length.greaterThan(4);
- });
-});
js-packages/tests/src/eth/helpersSmoke.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/helpersSmoke.test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-describe('Helpers sanity check', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Contract owner is recorded', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await (await helper.ethNativeContract.contractHelpers(owner)).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner);
- });
-
- itEth('Flipper is working', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const flipper = await helper.eth.deployFlipper(owner);
-
- expect(await flipper.methods.getValue().call()).to.be.false;
- await flipper.methods.flip().send({from: owner});
- expect(await flipper.methods.getValue().call()).to.be.true;
- });
-});
js-packages/tests/src/eth/marketplace-v2/Market.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace-v2/Market.sol
+++ /dev/null
@@ -1,414 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.18;
-
-import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
-import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
-import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
-import { UniqueNFT, CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol";
-import { UniqueFungible, CrossAddress as CrossAddressF } from "@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol";
-import { CollectionHelpers } from "@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol";
-import "./royalty/UniqueRoyaltyHelper.sol";
-
-contract Market is Ownable, ReentrancyGuard {
- using ERC165Checker for address;
-
- struct Order {
- uint32 id;
- uint32 collectionId;
- uint32 tokenId;
- uint32 amount;
- uint256 price;
- CrossAddress seller;
- }
-
- uint32 public constant version = 0;
- uint32 public constant buildVersion = 3;
- bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd;
- bytes4 private constant InterfaceId_ERC165 = 0x5755c3f2;
- CollectionHelpers private constant collectionHelpers =
- CollectionHelpers(0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F);
-
- mapping(uint32 => mapping(uint32 => Order)) orders;
- uint32 private idCount = 1;
- uint32 public marketFee;
- uint64 public ctime;
- address public ownerAddress;
- mapping(address => bool) public admins;
-
- event TokenIsUpForSale(uint32 version, Order item);
- event TokenRevoke(uint32 version, Order item, uint32 amount);
- event TokenIsApproved(uint32 version, Order item);
- event TokenIsPurchased(
- uint32 version,
- Order item,
- uint32 salesAmount,
- CrossAddress buyer,
- RoyaltyAmount[] royalties
- );
- event Log(string message);
-
- error InvalidArgument(string info);
- error InvalidMarketFee();
- error SellerIsNotOwner();
- error TokenIsAlreadyOnSale();
- error TokenIsNotApproved();
- error CollectionNotFound();
- error CollectionNotSupportedERC721();
- error OrderNotFound();
- error TooManyAmountRequested();
- error NotEnoughMoneyError();
- error InvalidRoyaltiesError(uint256 totalRoyalty);
- error FailTransferToken(string reason);
-
- modifier onlyAdmin() {
- require(msg.sender == this.owner() || admins[msg.sender], "Only admin can");
- _;
- }
-
- modifier validCrossAddress(address eth, uint256 sub) {
- if (eth == address(0) && sub == 0) {
- revert InvalidArgument("Ethereum and Substrate addresses cannot be null at the same time");
- }
-
- if (eth != address(0) && sub != 0) {
- revert InvalidArgument("Ethereum and Substrate addresses cannot be not null at the same time");
- }
-
- _;
- }
-
- constructor(uint32 fee, uint64 timestamp) {
- marketFee = fee;
- ctime = timestamp;
-
- if (marketFee >= 100) {
- revert InvalidMarketFee();
- }
- }
-
- /**
- * Fallback that allows this contract to receive native token.
- * We need this for self-sponsoring
- */
- fallback() external payable {}
-
- /**
- * Receive also allows this contract to receive native token.
- * We need this for self-sponsoring
- */
- receive() external payable {}
-
- function getErc721(uint32 collectionId) private view returns (IERC721) {
- address collectionAddress = collectionHelpers.collectionAddress(
- collectionId
- );
-
- uint size;
- assembly {
- size := extcodesize(collectionAddress)
- }
-
- if (size == 0) {
- revert CollectionNotFound();
- }
-
- if (!collectionAddress.supportsInterface(InterfaceId_ERC721)) {
- revert CollectionNotSupportedERC721();
- }
-
- return IERC721(collectionAddress);
- }
-
- /**
- * Add new admin. Only owner or an existing admin can add admins.
- *
- * @param admin: Address of a new admin to add
- */
- function addAdmin(address admin) public onlyAdmin {
- admins[admin] = true;
- }
-
- /**
- * Remove an admin. Only owner or an existing admin can remove admins.
- *
- * @param admin: Address of a new admin to add
- */
- function removeAdmin(address admin) public onlyAdmin {
- delete admins[admin];
- }
-
- /**
- * Place an NFT or RFT token for sale. It must be pre-approved for transfers by this contract address.
- *
- * @param collectionId: ID of the token collection
- * @param tokenId: ID of the token
- * @param price: Price (with proper network currency decimals)
- * @param amount: Number of token fractions to list (must always be 1 for NFT)
- * @param seller: The seller cross-address (the beneficiary account to receive payment, may be different from transaction sender)
- */
- function put(
- uint32 collectionId,
- uint32 tokenId,
- uint256 price,
- uint32 amount,
- CrossAddress memory seller
- ) public validCrossAddress(seller.eth, seller.sub) {
- if (price == 0) {
- revert InvalidArgument("price must not be zero");
- }
- if (amount == 0) {
- revert InvalidArgument("amount must not be zero");
- }
-
- if (orders[collectionId][tokenId].price > 0) {
- revert TokenIsAlreadyOnSale();
- }
-
- IERC721 erc721 = getErc721(collectionId);
-
- if (erc721.ownerOf(tokenId) != msg.sender) {
- revert SellerIsNotOwner();
- }
-
- if (erc721.getApproved(tokenId) != address(this)) {
- revert TokenIsNotApproved();
- }
-
- Order memory order = Order(
- 0,
- collectionId,
- tokenId,
- amount,
- price,
- seller
- );
-
- order.id = idCount++;
- orders[collectionId][tokenId] = order;
-
- emit TokenIsUpForSale(version, order);
- }
-
- /**
- * Get information about the listed token order
- *
- * @param collectionId: ID of the token collection
- * @param tokenId: ID of the token
- * @return The order information
- */
- function getOrder(
- uint32 collectionId,
- uint32 tokenId
- ) external view returns (Order memory) {
- return orders[collectionId][tokenId];
- }
-
- /**
- * Revoke the token from the sale. Only the original lister can use this method.
- *
- * @param collectionId: ID of the token collection
- * @param tokenId: ID of the token
- * @param amount: Number of token fractions to de-list (must always be 1 for NFT)
- */
- function revoke(
- uint32 collectionId,
- uint32 tokenId,
- uint32 amount
- ) external {
- if (amount == 0) {
- revert InvalidArgument("amount must not be zero");
- }
-
- Order memory order = orders[collectionId][tokenId];
-
- if (order.price == 0) {
- revert OrderNotFound();
- }
-
- if (amount > order.amount) {
- revert TooManyAmountRequested();
- }
-
- IERC721 erc721 = getErc721(collectionId);
-
- address ethAddress;
- if (order.seller.eth != address(0)) {
- ethAddress = order.seller.eth;
- } else {
- ethAddress = payable(address(uint160(order.seller.sub >> 96)));
- }
- if (erc721.ownerOf(tokenId) != ethAddress) {
- revert SellerIsNotOwner();
- }
-
- order.amount -= amount;
- if (order.amount == 0) {
- delete orders[collectionId][tokenId];
- } else {
- orders[collectionId][tokenId] = order;
- }
-
- emit TokenRevoke(version, order, amount);
- }
-
- /**
- * Test if the token is still approved to be transferred by this contract and delete the order if not.
- *
- * @param collectionId: ID of the token collection
- * @param tokenId: ID of the token
- */
- function checkApproved(uint32 collectionId, uint32 tokenId) public onlyAdmin {
- Order memory order = orders[collectionId][tokenId];
- if (order.price == 0) {
- revert OrderNotFound();
- }
-
- IERC721 erc721 = getErc721(collectionId);
-
- if (erc721.getApproved(tokenId) != address(this) || erc721.ownerOf(tokenId) != getAddressFromCrossAccount(order.seller)) {
- uint32 amount = order.amount;
- order.amount = 0;
- emit TokenRevoke(version, order, amount);
-
- delete orders[collectionId][tokenId];
- } else {
- emit TokenIsApproved(version, order);
- }
- }
-
- function getAddressFromCrossAccount(CrossAddress memory account) private pure returns (address) {
- if (account.eth != address(0)) {
- return account.eth;
- } else {
- return address(uint160(account.sub >> 96));
- }
- }
-
- /**
- * Revoke the token from the sale. Only the contract admin can use this method.
- *
- * @param collectionId: ID of the token collection
- * @param tokenId: ID of the token
- */
- function revokeAdmin(uint32 collectionId, uint32 tokenId) public onlyAdmin {
- Order memory order = orders[collectionId][tokenId];
- if (order.price == 0) {
- revert OrderNotFound();
- }
-
- uint32 amount = order.amount;
- order.amount = 0;
- emit TokenRevoke(version, order, amount);
-
- delete orders[collectionId][tokenId];
- }
-
- /**
- * Buy a token (partially for an RFT).
- *
- * @param collectionId: ID of the token collection
- * @param tokenId: ID of the token
- * @param amount: Number of token fractions to buy (must always be 1 for NFT)
- * @param buyer: Cross-address of the buyer, eth part must be equal to the transaction signer address
- */
- function buy(
- uint32 collectionId,
- uint32 tokenId,
- uint32 amount,
- CrossAddress memory buyer
- ) public payable validCrossAddress(buyer.eth, buyer.sub) nonReentrant {
- if (msg.value == 0) {
- revert InvalidArgument("msg.value must not be zero");
- }
- if (amount == 0) {
- revert InvalidArgument("amount must not be zero");
- }
-
- Order memory order = orders[collectionId][tokenId];
- if (order.price == 0) {
- revert OrderNotFound();
- }
-
- if (amount > order.amount) {
- revert TooManyAmountRequested();
- }
-
- uint256 totalValue = order.price * amount;
- uint256 feeValue = (totalValue * marketFee) / 100;
-
- if (msg.value < totalValue) {
- revert NotEnoughMoneyError();
- }
-
- IERC721 erc721 = getErc721(order.collectionId);
- if (erc721.getApproved(tokenId) != address(this)) {
- revert TokenIsNotApproved();
- }
-
- order.amount -= amount;
- if (order.amount == 0) {
- delete orders[collectionId][tokenId];
- } else {
- orders[collectionId][tokenId] = order;
- }
-
- address collectionAddress = collectionHelpers.collectionAddress(collectionId);
- UniqueNFT nft = UniqueNFT(collectionAddress);
-
- nft.transferFromCross(
- order.seller,
- buyer,
- order.tokenId
- );
-
- (uint256 totalRoyalty, RoyaltyAmount[] memory royalties) = sendRoyalties(collectionAddress, tokenId, totalValue - feeValue);
-
- if (totalRoyalty >= totalValue - feeValue) {
- revert InvalidRoyaltiesError(totalRoyalty);
- }
-
- sendMoney(order.seller, totalValue - feeValue - totalRoyalty);
-
- if (msg.value > totalValue) {
- sendMoney(buyer, msg.value - totalValue);
- }
-
- emit TokenIsPurchased(version, order, amount, buyer, royalties);
- }
-
- function sendMoney(CrossAddress memory to, uint256 money) private {
- address collectionAddress = collectionHelpers.collectionAddress(0);
-
- UniqueFungible fungible = UniqueFungible(collectionAddress);
-
- CrossAddressF memory fromF = CrossAddressF(address(this), 0);
- CrossAddressF memory toF = CrossAddressF(to.eth, to.sub);
-
- fungible.transferFromCross(fromF, toF, money);
- }
-
- function sendRoyalties(address collection, uint tokenId, uint sellPrice) private returns (uint256, RoyaltyAmount[] memory) {
- RoyaltyAmount[] memory royalties = UniqueRoyaltyHelper.calculate(collection, tokenId, sellPrice);
-
- uint256 totalRoyalty = 0;
-
- for (uint256 i=0; i<royalties.length; i++) {
- RoyaltyAmount memory royalty = royalties[i];
-
- totalRoyalty += royalty.amount;
-
- sendMoney(royalty.crossAddress, royalty.amount);
- }
-
- return (totalRoyalty, royalties);
- }
-
- function withdraw(address transferTo) public onlyOwner {
- uint256 balance = address(this).balance;
-
- if (balance > 0) {
- payable(transferTo).transfer(balance);
- }
- }
-}
js-packages/tests/src/eth/marketplace-v2/marketplace.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace-v2/marketplace.test.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import Web3 from 'web3';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {readFile} from 'fs/promises';
-import {SponsoringMode, itEth, usingEthPlaygrounds} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
-import {makeNames} from '../../util/index.js';
-import {expect} from 'chai';
-
-const {dirname} = makeNames(import.meta.url);
-
-const MARKET_FEE = 1;
-
-describe('Market V2 Contract', () => {
- let donor: IKeyringPair;
-
- before(async () => {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
-
- const marketOwner = await helper.eth.createAccountWithBalance(donor, 600n);
-
- await deployMarket(helper, marketOwner);
- });
- });
-
- async function deployMarket(helper: EthUniqueHelper, marketOwner: string) {
- return await helper.ethContract.deployByCode(
- marketOwner,
- 'Market',
- (await readFile(`${dirname}/Market.sol`)).toString(),
- [
- {
- solPath: '@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol',
- fsPath: `${dirname}/../api/UniqueNFT.sol`,
- },
- {
- solPath: '@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol',
- fsPath: `${dirname}/../api/UniqueFungible.sol`,
- },
- {
- solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
- },
- {
- solPath: '@openzeppelin/contracts/access/Ownable.sol',
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/access/Ownable.sol`,
- },
- {
- solPath: '@openzeppelin/contracts/utils/Context.sol',
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
- },
- {
- solPath: '@openzeppelin/contracts/security/ReentrancyGuard.sol',
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol`,
- },
- {
- solPath: '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol',
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol`,
- },
- {
- solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
- fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
- },
- {
- solPath: '@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol',
- fsPath: `${dirname}/../api/CollectionHelpers.sol`,
- },
- {
- solPath: 'royalty/UniqueRoyaltyHelper.sol',
- fsPath: `${dirname}/royalty/UniqueRoyaltyHelper.sol`,
- },
- {
- solPath: 'royalty/UniqueRoyalty.sol',
- fsPath: `${dirname}/royalty/UniqueRoyalty.sol`,
- },
- {
- solPath: 'royalty/LibPart.sol',
- fsPath: `${dirname}/royalty/LibPart.sol`,
- },
- ],
- 15000000,
- [MARKET_FEE, 0],
- );
- }
-
- function substrateAddressToHex(sub: Uint8Array| string, web3: Web3.default) {
- if(typeof sub === 'string')
- return web3.utils.padLeft(web3.utils.toHex(web3.utils.toBN(sub)), 64);
- else if(sub instanceof Uint8Array)
- return web3.utils.padLeft(web3.utils.bytesToHex(Array.from(sub)), 64);
- throw Error('Infallible');
- }
-
- itEth('Put + Buy [eth]', async ({helper}) => {
- const ONE_TOKEN = helper.balance.getOneTokenNominal();
- const PRICE = 2n * ONE_TOKEN; // 2 UNQ
- const marketOwner = await helper.eth.createAccountWithBalance(donor, 60000n);
- const market = await deployMarket(helper, marketOwner);
- const contractHelpers = helper.ethNativeContract.contractHelpers(marketOwner);
-
- // Set external sponsoring
- await contractHelpers.methods.setSponsor(market.options.address, marketOwner).send({from: marketOwner});
- await contractHelpers.methods.confirmSponsorship(market.options.address).send({from: marketOwner});
-
- // Configure sponsoring
- await contractHelpers.methods.setSponsoringMode(market.options.address, SponsoringMode.Generous).send({from: marketOwner});
- await contractHelpers.methods.setSponsoringRateLimit(market.options.address, 0).send({from: marketOwner});
-
- const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(marketOwner, 'Sponsor', 'absolutely anything', 'ROC');
- const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', marketOwner, true);
-
- // Set collection sponsoring
- await collection.methods.setCollectionSponsor(marketOwner).send({from: marketOwner});
- await collection.methods.confirmCollectionSponsorship().send({from: marketOwner});
-
- const sellerCross = helper.ethCrossAccount.createAccount();
- const result = await collection.methods.mintCross(sellerCross, []).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- await collection.methods.approve(market.options.address, tokenId).send({from: sellerCross.eth});
-
- // Seller has no funds at all, his transactions are sponsored
- const sellerBalance = await helper.balance.getEthereum(sellerCross.eth);
- expect(sellerBalance).to.be.eq(0n);
-
- const putResult = await market.methods.put(collectionId, tokenId, PRICE.toString(), 1, sellerCross).send({
- from: sellerCross.eth, gasLimit: 1_000_000,
- });
- expect(putResult.events.TokenIsUpForSale).is.not.undefined;
-
- // Seller balance are still 0
- const sellerBalanceAfter = await helper.balance.getEthereum(sellerCross.eth);
- expect(sellerBalanceAfter).to.be.eq(0n);
-
- let ownerCross = await collection.methods.ownerOfCross(tokenId).call();
- expect(ownerCross.eth).to.be.eq(sellerCross.eth);
- expect(ownerCross.sub).to.be.eq(sellerCross.sub);
-
- const buyerCross = await helper.ethCrossAccount.createAccountWithBalance(donor, 10n);
-
- // Buyer has only 10 UNQ
- const buyerBalance = await helper.balance.getEthereum(buyerCross.eth);
- expect(buyerBalance).to.be.eq(10n * ONE_TOKEN);
-
- const buyResult = await market.methods.buy(collectionId, tokenId, 1, buyerCross).send({from: buyerCross.eth, value: PRICE.toString(), gasLimit: 1_000_000});
- expect(buyResult.events.TokenIsPurchased).is.not.undefined;
-
- // Buyer pays only value, transaction use sponsoring
- const buyerBalanceAfter = await helper.balance.getEthereum(buyerCross.eth);
- expect(buyerBalanceAfter).to.be.eq(10n * ONE_TOKEN - PRICE);
-
- ownerCross = await collection.methods.ownerOfCross(tokenId).call();
- expect(ownerCross.eth).to.be.eq(buyerCross.eth);
- expect(ownerCross.sub).to.be.eq(buyerCross.sub);
- });
-
- itEth('Put + Buy [sub]', async ({helper}) => {
- const ONE_TOKEN = helper.balance.getOneTokenNominal();
- const PRICE = 2n * ONE_TOKEN; // 2 UNQ
- const web3 = helper.getWeb3();
- const marketOwner = await helper.eth.createAccountWithBalance(donor, 600n);
- const market = await deployMarket(helper, marketOwner);
- const contractHelpers = helper.ethNativeContract.contractHelpers(marketOwner);
-
- // Set self sponsoring from contract balance
- await contractHelpers.methods.selfSponsoredEnable(market.options.address).send({from: marketOwner});
- await helper.eth.transferBalanceFromSubstrate(donor, market.options.address, 10n);
-
- // Configure sponsoring
- await contractHelpers.methods.setSponsoringMode(market.options.address, SponsoringMode.Generous).send({from: marketOwner});
- await contractHelpers.methods.setSponsoringRateLimit(market.options.address, 0).send({from: marketOwner});
-
- const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(marketOwner, 'Sponsor', 'absolutely anything', 'ROC');
- const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', marketOwner, true);
-
- // Set collection sponsoring
- await collection.methods.setCollectionSponsor(marketOwner).send({from: marketOwner});
- await collection.methods.confirmCollectionSponsorship().send({from: marketOwner});
-
- const seller = helper.util.fromSeed(`//Market-seller-${(new Date()).getTime()}`);
- const sellerCross = helper.ethCrossAccount.fromKeyringPair(seller);
-
- // Seller has no funds at all, his transactions are sponsored
- {
- const sellerBalance = await helper.balance.getSubstrate(seller.address);
- expect(sellerBalance).to.be.eq(0n);
- }
-
- const result = await collection.methods.mintCross(sellerCross, []).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- await helper.nft.approveToken(seller, collectionId, tokenId, {Ethereum: market.options.address});
-
- await helper.eth.sendEVM(seller, market.options.address, market.methods.put(collectionId, tokenId, PRICE, 1, sellerCross).encodeABI(), '0');
- // Seller balance is still zero
- {
- const sellerBalance = await helper.balance.getSubstrate(seller.address);
- expect(sellerBalance).to.be.eq(0n);
- }
- let ownerCross = await collection.methods.ownerOfCross(tokenId).call();
- expect(ownerCross.eth).to.be.eq(sellerCross.eth);
- expect(substrateAddressToHex(ownerCross.sub, web3)).to.be.eq(substrateAddressToHex(sellerCross.sub, web3));
-
- const [buyer] = await helper.arrange.createAccounts([600n], donor);
- // Buyer has only expected balance
- {
- const buyerBalance = await helper.balance.getSubstrate(buyer.address);
- expect(buyerBalance).to.be.eq(600n * ONE_TOKEN);
- }
- const buyerCross = helper.ethCrossAccount.fromKeyringPair(buyer);
-
- const buyerBalanceBefore = await helper.balance.getSubstrate(buyer.address);
- await helper.eth.sendEVM(buyer, market.options.address, market.methods.buy(collectionId, tokenId, 1, buyerCross).encodeABI(), PRICE.toString());
- const buyerBalanceAfter = await helper.balance.getSubstrate(buyer.address);
- // Buyer balance not changed: transaction is sponsored
- expect(buyerBalanceBefore).to.be.eq(buyerBalanceAfter + PRICE);
-
- const sellerBalanceAfterBuy = BigInt(await helper.balance.getSubstrate(seller.address));
- ownerCross = await collection.methods.ownerOfCross(tokenId).call();
- expect(ownerCross.eth).to.be.eq(buyerCross.eth);
- expect(substrateAddressToHex(ownerCross.sub, web3)).to.be.eq(substrateAddressToHex(buyerCross.sub, web3));
-
- // Seller got only PRICE - MARKET_FEE
- expect(sellerBalanceAfterBuy).to.be.eq(PRICE * BigInt(100 - MARKET_FEE) / 100n);
- });
-});
js-packages/tests/src/eth/marketplace-v2/royalty/LibPart.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace-v2/royalty/LibPart.sol
+++ /dev/null
@@ -1,111 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.0;
-
-import "./UniqueRoyalty.sol";
-
-library LibPart {
- bytes32 public constant TYPE_HASH = keccak256("Part(address account,uint96 value)");
-
- struct Part {
- address payable account;
- uint96 value;
- }
-
- function hash(Part memory part) internal pure returns (bytes32) {
- return keccak256(abi.encode(TYPE_HASH, part.account, part.value));
- }
-}
-
-library LibPartAdapter {
- function encode(LibPart.Part[] memory parts) internal pure returns (bytes memory) {
- if (parts.length == 0) return "";
-
- uint256[] memory encoded = new uint256[](parts.length * 2);
-
- for (uint i = 0; i < parts.length; i++) {
- encoded[i * 2] = 0x0100000000000000000000000000000000000000000000040000000000000000 | uint256(parts[i].value);
- encoded[i * 2 + 1] = uint256(uint160(address(parts[i].account)));
- }
-
- return abi.encodePacked(encoded);
- }
-
- function decode(bytes memory b) internal pure returns (LibPart.Part[] memory) {
- if (b.length == 0) return new LibPart.Part[](0);
-
- require((b.length % (32 * 2)) == 0, "Invalid bytes length, expected (32 * 2) * UniqueRoyaltyParts count");
- uint partsCount = b.length / (32 * 2);
- uint numbersCount = partsCount * 2;
-
- LibPart.Part[] memory parts = new LibPart.Part[](partsCount);
-
- // need this because numbers encoded via abi.encodePacked
- bytes memory prefix = new bytes(64);
-
- assembly {
- mstore(add(prefix, 32), 32)
- mstore(add(prefix, 64), numbersCount)
- }
-
- uint256[] memory encoded = abi.decode(bytes.concat(prefix, b), (uint256[]));
-
- for (uint i = 0; i < partsCount; i++) {
- uint96 value = uint96(encoded[i * 2] & 0xFFFFFFFFFFFFFFFF);
- address account = address(uint160(encoded[i * 2 + 1]));
-
- parts[i] = LibPart.Part({
- account: payable(account),
- value: value
- });
- }
-
- return parts;
- }
-}
-
-library LibPartAdapterComplex {
- function decodeSafe(bytes memory data) internal pure returns (LibPart.Part[] memory) {
- return fromUniqueRoyalties(UniqueRoyalty.decode(data));
- }
-
- function encodeSafe(LibPart.Part[] memory parts) internal pure returns (bytes memory) {
- return UniqueRoyalty.encode(toUniqueRoyalties(parts));
- }
-
- function fromUniqueRoyalties(UniqueRoyaltyPart[] memory royalties) internal pure returns (LibPart.Part[] memory) {
- LibPart.Part[] memory parts = new LibPart.Part[](royalties.length);
-
- for (uint i = 0; i < royalties.length; i++) {
- uint96 value = royalties[i].decimals >= 4
- ? uint96(royalties[i].value * (10 ** (royalties[i].decimals - 4)))
- : uint96(royalties[i].value / (10 ** (4 - royalties[i].decimals)));
-
- parts[i] = LibPart.Part({
- account: payable(CrossAddressLib.toAddress(royalties[i].crossAddress)),
- value: value
- });
- }
-
- return parts;
- }
-
- function toUniqueRoyalties(LibPart.Part[] memory parts) internal pure returns (UniqueRoyaltyPart[] memory) {
- UniqueRoyaltyPart[] memory royalties = new UniqueRoyaltyPart[](parts.length);
-
- for (uint i = 0; i < parts.length; i++) {
- royalties[i] = UniqueRoyaltyPart({
- version: 1,
- value: uint64(parts[i].value),
- decimals: 4,
- crossAddress: CrossAddress({
- sub: 0,
- eth: parts[i].account
- }),
- isPrimarySaleOnly: false
- });
- }
-
- return royalties;
- }
-}
\ No newline at end of file
js-packages/tests/src/eth/marketplace-v2/royalty/UniqueRoyalty.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace-v2/royalty/UniqueRoyalty.sol
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity >=0.8.17;
-
-import { CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol";
-
-struct UniqueRoyaltyPart {
- uint8 version;
- uint8 decimals;
- uint64 value;
- bool isPrimarySaleOnly;
- CrossAddress crossAddress;
-}
-
-library CrossAddressLib {
- function toAddress(CrossAddress memory crossAddress) internal pure returns (address) {
- return crossAddress.eth != address(0) ? crossAddress.eth : address(uint160(crossAddress.sub >> 96));
- }
-}
-
-library UniqueRoyalty {
- uint private constant DECIMALS_OFFSET = 4 * 16;
- uint private constant ADDRESS_TYPE_OFFSET = 4 * (16 + 2); // 0 - eth, 1 - sub
- uint private constant ROYALTY_TYPE_OFFSET = 4 * (16 + 2 + 1); // 0 - default, 1 - primary sale only
- uint private constant VERSION_OFFSET = 4 * (16 + 2 + 1 + 1 + 42);
-
- uint private constant PART_LENGTH = 32 * 2;
-
- function decode(bytes memory b) internal pure returns (UniqueRoyaltyPart[] memory) {
- if (b.length == 0) return new UniqueRoyaltyPart[](0);
-
- require((b.length % PART_LENGTH) == 0, "Invalid bytes length, expected (32 * 2) * UniqueRoyaltyParts count");
- uint partsCount = b.length / PART_LENGTH;
- uint numbersCount = partsCount * 2;
-
- UniqueRoyaltyPart[] memory parts = new UniqueRoyaltyPart[](partsCount);
-
- // need this because numbers encoded via abi.encodePacked
- bytes memory prefix = new bytes(64);
-
- assembly {
- mstore(add(prefix, 32), 32)
- mstore(add(prefix, 64), numbersCount)
- }
-
- uint256[] memory encoded = abi.decode(bytes.concat(prefix, b), (uint256[]));
-
- for (uint i = 0; i < partsCount; i++) {
- parts[i] = decodePart(encoded[i * 2], encoded[i * 2 + 1]);
- }
-
- return parts;
- }
-
- function encode(UniqueRoyaltyPart[] memory parts) internal pure returns (bytes memory) {
- if (parts.length == 0) return "";
-
- uint256[] memory encoded = new uint256[](parts.length * 2);
-
- for (uint i = 0; i < parts.length; i++) {
- (uint256 encodedMeta, uint256 encodedAddress) = encodePart(parts[i]);
-
- encoded[i * 2] = encodedMeta;
- encoded[i * 2 + 1] = encodedAddress;
- }
-
- return abi.encodePacked(encoded);
- }
-
- function decodePart(bytes memory b) internal pure returns (UniqueRoyaltyPart memory) {
- require(b.length == PART_LENGTH, "Invalid bytes length, expected 32 * 2");
-
- uint256[2] memory encoded = abi.decode(b, (uint256[2]));
-
- return decodePart(encoded[0], encoded[1]);
- }
-
- function decodePart(
- uint256 _meta,
- uint256 _address
- ) internal pure returns (UniqueRoyaltyPart memory) {
- uint256 version = _meta >> VERSION_OFFSET;
- bool isPrimarySaleOnly = (_meta & (1 << ROYALTY_TYPE_OFFSET)) > 0;
- bool isEthereumAddress = (_meta & (1 << ADDRESS_TYPE_OFFSET)) == 0;
- uint256 decimals = (_meta >> 4 * 16) & 0xFF;
- uint256 value = _meta & 0xFFFFFFFFFFFFFFFF;
-
- CrossAddress memory crossAddress = isEthereumAddress
- ? CrossAddress({ sub: 0, eth: address(uint160(_address)) })
- : CrossAddress({ sub: _address, eth: address(0) });
-
- UniqueRoyaltyPart memory royaltyPart = UniqueRoyaltyPart({
- version: uint8(version),
- decimals: uint8(decimals),
- value: uint64(value),
- isPrimarySaleOnly: isPrimarySaleOnly,
- crossAddress: crossAddress
- });
-
- return royaltyPart;
- }
-
- function encodePart(UniqueRoyaltyPart memory royaltyPart) internal pure returns (uint256, uint256) {
- uint256 encodedMeta = 0;
- uint256 encodedAddress = 0;
-
- encodedMeta |= uint256(royaltyPart.version) << VERSION_OFFSET;
- if (royaltyPart.isPrimarySaleOnly) encodedMeta |= 1 << ROYALTY_TYPE_OFFSET;
-
- if (royaltyPart.crossAddress.eth == address(0x0)) {
- encodedMeta |= 1 << ADDRESS_TYPE_OFFSET;
- encodedAddress = royaltyPart.crossAddress.sub;
- } else {
- encodedAddress = uint256(uint160(royaltyPart.crossAddress.eth));
- }
-
- encodedMeta |= uint256(royaltyPart.decimals) << DECIMALS_OFFSET;
- encodedMeta |= uint256(royaltyPart.value);
-
- return (encodedMeta, encodedAddress);
- }
-}
\ No newline at end of file
js-packages/tests/src/eth/marketplace-v2/royalty/UniqueRoyaltyHelper.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace-v2/royalty/UniqueRoyaltyHelper.sol
+++ /dev/null
@@ -1,107 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity >=0.8.17;
-
-import "./UniqueRoyalty.sol";
-import "./LibPart.sol";
-
-string constant ROYALTIES_PROPERTY = "royalties";
-
-interface ICollection {
- function collectionProperty(string memory key) external view returns (bytes memory);
- function property(uint256 tokenId, string memory key) external view returns (bytes memory);
-}
-
-struct RoyaltyAmount {
- CrossAddress crossAddress;
- uint amount;
-}
-
-library UniqueRoyaltyHelper {
- function encodePart(UniqueRoyaltyPart memory part) internal pure returns (bytes memory) {
- (uint256 encodedMeta, uint256 encodedAddress) = UniqueRoyalty.encodePart(part);
-
- return abi.encodePacked(encodedMeta, encodedAddress);
- }
-
- function decodePart(bytes memory data) internal pure returns (UniqueRoyaltyPart memory) {
- return UniqueRoyalty.decodePart(data);
- }
-
- // todo - implement smth better - check royalties sum is lte 100%
- function validatePart(bytes memory b) internal pure returns (bool isValid) {
- isValid = b.length == 64;
- }
-
- function encode(UniqueRoyaltyPart[] memory royalties) internal pure returns (bytes memory) {
- return UniqueRoyalty.encode(royalties);
- }
-
- function decode(bytes memory data) internal pure returns (UniqueRoyaltyPart[] memory) {
- return UniqueRoyalty.decode(data);
- }
-
- // todo - implement smth better - check royalties sum is lte 100%
- function validate(bytes memory b) internal pure returns (bool) {
- return b.length % 64 == 0;
- }
-
- function getTokenRoyalty(address collection, uint tokenId) internal view returns (UniqueRoyaltyPart[] memory) {
- try ICollection(collection).property(tokenId, ROYALTIES_PROPERTY) returns (bytes memory encoded) {
- return UniqueRoyalty.decode(encoded);
- } catch {
- return new UniqueRoyaltyPart[](0);
- }
- }
-
- function getCollectionRoyalty(address collection) internal view returns (UniqueRoyaltyPart[] memory) {
- try ICollection(collection).collectionProperty(ROYALTIES_PROPERTY) returns (bytes memory encoded) {
- return UniqueRoyalty.decode(encoded);
- } catch {
- return new UniqueRoyaltyPart[](0);
- }
- }
-
- function getRoyalty(address collection, uint tokenId) internal view returns (UniqueRoyaltyPart[] memory royalty) {
- royalty = getTokenRoyalty(collection, tokenId);
-
- if (royalty.length == 0) {
- royalty = getCollectionRoyalty(collection);
- }
- }
-
- function calculateRoyalties(UniqueRoyaltyPart[] memory royalties, bool isPrimarySale, uint sellPrice) internal pure returns (RoyaltyAmount[] memory) {
- RoyaltyAmount[] memory royaltyAmounts = new RoyaltyAmount[](royalties.length);
- uint amountsCount = 0;
-
- for (uint i = 0; i < royalties.length; i++) {
- if (isPrimarySale == royalties[i].isPrimarySaleOnly) {
- uint amount = (sellPrice * royalties[i].value) / (10 ** (royalties[i].decimals));
-
- royaltyAmounts[amountsCount] = RoyaltyAmount({
- crossAddress: royalties[i].crossAddress,
- amount: amount
- });
-
- amountsCount += 1;
- }
- }
-
- // shrink royaltyAmounts to amountsCount length
- assembly { mstore(royaltyAmounts, amountsCount) }
-
- return royaltyAmounts;
- }
-
- function calculateForPrimarySale(address collection, uint tokenId, uint sellPrice) internal view returns (RoyaltyAmount[] memory) {
- UniqueRoyaltyPart[] memory royalties = getRoyalty(collection, tokenId);
-
- return calculateRoyalties(royalties, true, sellPrice);
- }
-
- function calculate(address collection, uint tokenId, uint sellPrice) internal view returns (RoyaltyAmount[] memory) {
- UniqueRoyaltyPart[] memory royalties = getRoyalty(collection, tokenId);
-
- return calculateRoyalties(royalties, false, sellPrice);
- }
-}
\ No newline at end of file
js-packages/tests/src/eth/marketplace-v2/utils.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace-v2/utils.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.17;
-
-contract Utils {
- function toString(address account) public pure returns (string memory) {
- return toString(abi.encodePacked(account));
- }
-
- function toString(bool value) public pure returns (string memory) {
- return value ? "true" : "false";
- }
-
- function toString(uint256 value) public pure returns (string memory) {
- return toString(abi.encodePacked(value));
- }
-
- function toString(bytes32 value) public pure returns (string memory) {
- return toString(abi.encodePacked(value));
- }
-
- function toString(bytes memory data) public pure returns (string memory) {
- bytes memory alphabet = "0123456789abcdef";
-
- bytes memory str = new bytes(2 + data.length * 2);
- str[0] = "0";
- str[1] = "x";
- for (uint i = 0; i < data.length; i++) {
- str[2 + i * 2] = alphabet[uint(uint8(data[i] >> 4))];
- str[3 + i * 2] = alphabet[uint(uint8(data[i] & 0x0f))];
- }
- return string(str);
- }
-}
\ No newline at end of file
js-packages/tests/src/eth/marketplace/MarketPlace.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace/MarketPlace.sol
+++ /dev/null
@@ -1,414 +0,0 @@
-// SPDX-License-Identifier: Apache License
-pragma solidity >=0.8.0;
-import {UniqueNFT, Dummy, ERC165} from "../api/UniqueNFT.sol";
-
-// Inline
-interface ERC20Events {
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(
- address indexed owner,
- address indexed spender,
- uint256 value
- );
-}
-
-interface ERC20 is Dummy, ERC165, ERC20Events {
- // Selector: name() 06fdde03
- function name() external view returns (string memory);
-
- // Selector: symbol() 95d89b41
- function symbol() external view returns (string memory);
-
- // Selector: totalSupply() 18160ddd
- function totalSupply() external view returns (uint256);
-
- // Selector: decimals() 313ce567
- function decimals() external view returns (uint8);
-
- // Selector: balanceOf(address) 70a08231
- function balanceOf(address owner) external view returns (uint256);
-
- // Selector: transfer(address,uint256) a9059cbb
- function transfer(address to, uint256 amount) external returns (bool);
-
- // Selector: transferFrom(address,address,uint256) 23b872dd
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) external returns (bool);
-
- // Selector: approve(address,uint256) 095ea7b3
- function approve(address spender, uint256 amount) external returns (bool);
-
- // Selector: allowance(address,address) dd62ed3e
- function allowance(address owner, address spender)
- external
- view
- returns (uint256);
-}
-
-interface UniqueFungible is Dummy, ERC165, ERC20 {}
-
-contract MarketPlace {
- struct Order {
-
- uint256 idNFT;
- address currencyCode; // UNIQ tokens as address address (1); wKSM
- uint256 price;
- uint256 time;
- address idCollection;
- address ownerAddr;
- uint8 flagActive;
- string name;
- string symbol;
- string tokenURI;
- }
- Order[] public orders;
- uint test;
- mapping (address => uint256) public balanceKSM; // [ownerAddr][currency] => [KSMs]
- mapping (address => mapping (uint256 => uint256)) public asks ; // [buyer][idCollection][idNFT] => idorder
- mapping (address => mapping (uint => uint[])) public ordersbyNFT; // [addressCollection] =>idNFT =>idorder
-
- mapping (address => uint[]) public asksbySeller; // [addressSeller] =>idorder
-
- mapping (address =>bool) internal isEscrow;
-
- //address escrow;
- address owner;
- address nativecoin;
-
- // from abstract contract ReentrancyGuard
- // Booleans are more expensive than uint256 or any type that takes up a full
- // word because each write operation emits an extra SLOAD to first read the
- // slot's contents, replace the bits taken up by the boolean, and then write
- // back. This is the compiler's defense against contract upgrades and
- // pointer aliasing, and it cannot be disabled.
-
- // The values being non-zero value makes deployment a bit more expensive,
- // but in exchange the refund on every call to nonReentrant will be lower in
- // amount. Since refunds are capped to a percentage of the total
- // transaction's gas, it is best to keep them low in cases like this one, to
- // increase the likelihood of the full refund coming into effect.
- uint8 private constant _NOT_ENTERED = 1;
- uint8 private constant _ENTERED = 2;
-
- uint8 private _status;
-
- struct NFT {
- address collection;
- uint256 id;
- }
-
- //function initialize() public initializer {
- constructor () { // call setEscrow directly
- owner = msg.sender;
-
- orders.push(Order(
- 0,
- address(0),
- 0,
- 0,
- address(0),
- address(0),
- 0, "","",""));
- _status = _NOT_ENTERED;
-
- }
-
- modifier nonReentrant() { // from abstract contract ReentrancyGuard
- // On the first call to nonReentrant, _notEntered will be true
- require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
-
- // Any calls to nonReentrant after this point will fail
- _status = _ENTERED;
-
- _;
-
- // By storing the original value once again, a refund is triggered (see
- // https://eips.ethereum.org/EIPS/eip-2200)
- _status = _NOT_ENTERED;
- }
-
- modifier onlyEscrow () {
- require(isEscrow [msg.sender] , "Only escrow can");
- _;
- }
-
- modifier onlyOwner () {
- require(msg.sender == owner, "Only owner can");
- _;
- }
-
- /**
- * Make bids (orders) to sell NFTs
- */
-
-
- receive () external payable {
- // revert ("Can't accept payment without collection and IDs, use dApp to send");
- }
- fallback () external payable {
- revert ("No such function");
- }
-
- event AddedAsk (uint256 _price,
- address _currencyCode,
- address _idCollection,
- uint256 _idNFT,
- uint256 orderId
- );
- event EditedAsk (uint256 _price,
- address _currencyCode,
- address _idCollection,
- uint256 _idNFT,
- uint8 _active,
- uint orderId);
-
- event CanceledAsk (address _idCollection,
- uint256 _idNFT,
- uint orderId
- );
-
- event DepositedKSM (uint256 _amount, address _sender);
-
- event BoughtNFT4KSM (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );
-
- event BoughtNFT (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice );
-
- event WithdrawnAllKSM (address _sender, uint256 balance);
-
- event WithdrawnKSM (address _sender, uint256 balance);
-
- event Withdrawn (uint256 _amount, address _currencyCode, address _sender);
-
-
- function setOwner (address _newOwner) public onlyOwner {
- owner = _newOwner;
- }
-
- function setEscrow (address _escrow, bool _state) public onlyOwner returns (bool) {
- if (isEscrow[_escrow] != _state) {
- isEscrow[_escrow] = _state;
- return true;
- }
- return false;
- }
-
- function setNativeCoin (address _coin) public onlyOwner {
- nativecoin = _coin;
- }
-
-
- function addAsk (uint256 _price,
- address _currencyCode,
- address _idCollection,
- uint256 _idNFT
- ) public { //
- address ownerNFT = UniqueNFT(_idCollection).ownerOf(_idNFT);
- require (ownerNFT == msg.sender, "Only token owner can make ask");
- string memory nameNFT;
- string memory symbolNFT;
- string memory uriNFT;
- try UniqueNFT(_idCollection).name() returns (string memory name_) {
- nameNFT = name_;
- }
- catch {
- nameNFT="";
- }
- try UniqueNFT(_idCollection).symbol() returns (string memory symbol_) {
- symbolNFT = symbol_;
- }
- catch {
- symbolNFT="";
- }
- try UniqueNFT(_idCollection).tokenURI(_idNFT) returns (string memory uri_) {
- uriNFT = uri_;
- }
- catch {
- uriNFT="";
- }
- orders.push(Order(
- _idNFT,
- _currencyCode,
- _price,
- block.timestamp,
- _idCollection,
- msg.sender,
- 1, // 1 = is active
- nameNFT,
- symbolNFT,
- uriNFT
- ));
-
- uint orderId = orders.length-1;
- asks[_idCollection][_idNFT] = orderId;
- asksbySeller[msg.sender].push(orderId);
- UniqueNFT(_idCollection).transferFrom(msg.sender, address(this), _idNFT);
- emit AddedAsk(_price, _currencyCode, _idCollection, _idNFT, orderId);
- }
-
- function editAsk (uint256 _price,
- address _currencyCode,
- address _idCollection,
- uint256 _idNFT,
- uint8 _active) public {
-
-
- uint orderID = asks[_idCollection][_idNFT];
-
- require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");
- require (orders[orderID].flagActive != 0, "This ask is closed");
- if (_price> 0 ) {
- orders[orderID].price = _price ;
- }
-
- if (_currencyCode != address(0) ) {
- orders[orderID].currencyCode = _currencyCode ;
- }
-
- orders[orderID].time = block.timestamp;
- orders[orderID].flagActive = _active;
-
- emit EditedAsk(_price, _currencyCode, _idCollection, _idNFT, _active, orderID);
- }
-
-
- function cancelAsk (address _idCollection,
- uint256 _idNFT
- ) public {
-
- uint orderID = asks[_idCollection][_idNFT];
-
- require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask");
- require (orders[orderID].flagActive != 0, "This ask is closed");
-
- orders[orderID].time = block.timestamp;
- orders[orderID].flagActive = 0;
- UniqueNFT(_idCollection).transferFrom(address(this),orders[orderID].ownerAddr, _idNFT);
- emit CanceledAsk(_idCollection, _idNFT, orderID);
- }
-
-
- function depositKSM (uint256 _amount, address _sender) public onlyEscrow {
- balanceKSM[_sender] = balanceKSM[_sender] + _amount;
- emit DepositedKSM(_amount, _sender);
- }
-
- function buyKSM (address _idCollection, uint256 _idNFT, address _buyer, address _receiver ) public {
-
- Order memory order = orders[ asks[_idCollection][_idNFT]];
- require(isEscrow[msg.sender] || msg.sender == _buyer, "Only escrow or buyer can call buyKSM" );
- //1. reduce balance
-
- balanceKSM[_buyer] = balanceKSM[_buyer] - order.price;
- balanceKSM[order.ownerAddr] = balanceKSM[order.ownerAddr] + order.price;
- // 2. close order
- orders[ asks[_idCollection][_idNFT]].flagActive = 0;
- // 3. transfer NFT to buyer
- UniqueNFT(_idCollection).transferFrom(address(this), _receiver, _idNFT);
- emit BoughtNFT4KSM(_idCollection, _idNFT, asks[_idCollection][_idNFT], order.price);
-
- }
- function buy (address _idCollection, uint256 _idNFT ) public payable returns (bool result) { //buing for UNQ like as ethers
-
- Order memory order = orders[asks[_idCollection][_idNFT]];
- //1. check sent amount and send to seller
- require (msg.value == order.price, "Not right amount sent, have to be equal price" );
- // 2. close order
- orders[ asks[_idCollection][_idNFT]].flagActive = 0;
-
- // 3. transfer NFT to buyer
- UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT);
- //uint balance = address(this).balance;
- result = payable(order.ownerAddr).send (order.price);
- emit BoughtNFT(_idCollection, _idNFT, asks[_idCollection][_idNFT], order.price);
-
- }
-
-/*
- function buyOther (address _idCollection, uint256 _idNFT, address _currencyCode, uint _amount ) public { //buy for sny token if seller wants
-
- Order memory order = orders[ asks[_idCollection][_idNFT]];
- //1. check sent amount and transfer from buyer to seller
- require (order.price == _amount && order.currencyCode == _currencyCode, "Not right amount or currency sent, have to be equal currency and price" );
- // !!! transfer have to be approved to marketplace!
- UniqueFungible(order.currencyCode).transferFrom(msg.sender, address(this), order.price); //to not disclojure buyer's address
- UniqueFungible(order.currencyCode).transfer(order.ownerAddr, order.price);
- // 2. close order
- orders[ asks[_idCollection][_idNFT]].flagActive = 0;
- // 3. transfer NFT to buyer
- UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT);
-
-
- }
- */
-
- function withdrawAllKSM (address _sender) public nonReentrant returns (uint lastBalance ){
- require(isEscrow[msg.sender] || msg.sender == _sender, "Only escrow or balance owner can withdraw all KSM" );
-
- lastBalance = balanceKSM[_sender];
- balanceKSM[_sender] =0;
- emit WithdrawnAllKSM(_sender, lastBalance);
- }
-
- function withdrawKSM (uint _amount, address _sender) onlyEscrow public {
- balanceKSM[_sender] = balanceKSM[_sender] - _amount;
- emit WithdrawnKSM(_sender, balanceKSM[_sender]);
-
- }
-
- function withdraw (uint256 _amount, address _currencyCode) public nonReentrant returns (bool result ){ //onlyOwner
- address payable _sender = payable( msg.sender);
- if (_currencyCode != nativecoin ) { //erc20 compat. tokens on UNIQUE chain
- // uint balance = UniqueFungible(_currencyCode).balanceOf(address(this));
- UniqueFungible(_currencyCode).transfer(_sender, _amount);
- } else {
- // uint balance = address(this).balance;
-
- result = (_sender).send(_amount); // for UNQ like as ethers
- }
- emit Withdrawn(_amount, _currencyCode, _sender);
- return result;
-
- }
-
-
- // event GettedOrder(uint , Order);
- function getOrder (address _idCollection, uint256 _idNFT) public view returns (Order memory) {
- uint orderId = asks[_idCollection][_idNFT];
- Order memory order = orders[orderId];
- // emit GettedOrder (orderId, order);
- return order;
- }
-
- function getOrdersLen () public view returns (uint) {
- return orders.length;
- }
-
- function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) public pure returns(bytes4) {
- return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
- }
-
- //TODO make destructing function to return all
- function terminate(address[] calldata tokens, NFT[] calldata nfts) public onlyOwner {
- // Transfer tokens to owner (TODO: error handling)
- for (uint i = 0; i < tokens.length; i++) {
- address addr = tokens[i];
- UniqueFungible token = UniqueFungible(addr);
- uint256 balance = token.balanceOf(address(this));
- token.transfer(owner, balance);
- }
- for (uint i = 0; i < nfts.length; i++) {
- address addr = nfts[i].collection;
- UniqueNFT token = UniqueNFT(addr);
- token.transferFrom(address(this), owner, nfts[i].id);
- }
- // Transfer Eth to owner and terminate contract
- address payable owner1 = payable (owner);
- uint balance = address(this).balance;
- owner1.transfer(balance);
-
- }
-
-}
js-packages/tests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/marketplace/marketplace.test.ts
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {readFile} from 'fs/promises';
-import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from '../util/index.js';
-import {makeNames} from '../../util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-describe('Matcher contract usage', () => {
- const PRICE = 2000n;
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let aliceMirror: string;
- let aliceDoubleMirror: string;
- let seller: IKeyringPair;
- let sellerMirror: string;
-
- before(async () => {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- beforeEach(async () => {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- [alice] = await helper.arrange.createAccounts([1000n], donor);
- aliceMirror = helper.address.substrateToEth(alice.address).toLowerCase();
- aliceDoubleMirror = helper.address.ethToSubstrate(aliceMirror);
- seller = await privateKey(`//Seller/${Date.now()}`);
- sellerMirror = helper.address.substrateToEth(seller.address).toLowerCase();
-
- await helper.balance.transferToSubstrate(donor, aliceDoubleMirror, 10_000_000_000_000_000_000n);
- });
- });
-
- itEth('With UNQ', async ({helper}) => {
- const matcherOwner = await helper.eth.createAccountWithBalance(donor);
- const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
-
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);
- await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
- await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
-
- await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});
- await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});
-
- const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: {Substrate: alice.address}});
- await collection.confirmSponsorship(alice);
- await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});
- const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
- await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);
-
- await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});
- await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});
-
- const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
-
- // Token is owned by seller initially
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
-
- // Ask
- {
- await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
- await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
- }
-
- // Token is transferred to matcher
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
-
- // Buy
- {
- const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);
- await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());
- expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);
- }
-
- // Token is transferred to evm account of alice
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
-
- // Transfer token to substrate side of alice
- await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
-
- // Token is transferred to substrate account of alice, seller received funds
- expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itEth('With escrow', async ({helper}) => {
- const matcherOwner = await helper.eth.createAccountWithBalance(donor);
- const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
-
- const sponsor = await helper.eth.createAccountWithBalance(donor);
- const escrow = await helper.eth.createAccountWithBalance(donor);
- await matcher.methods.setEscrow(escrow, true).send({from: matcherOwner});
- const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);
- await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
- await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
-
- await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});
- await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});
-
- const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: {Substrate: alice.address}});
- await collection.confirmSponsorship(alice);
- await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});
- const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
- await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);
-
-
- await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});
-
- await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});
-
- const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
-
- // Token is owned by seller initially
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
-
- // Ask
- {
- await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
- await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
- }
-
- // Token is transferred to matcher
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
-
- // Give buyer KSM
- await matcher.methods.depositKSM(PRICE, aliceMirror).send({from: escrow});
-
- // Buy
- {
- expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal('0');
- expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal(PRICE.toString());
-
- await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buyKSM(evmCollection.options.address, token.tokenId, aliceMirror, aliceMirror).encodeABI(), '0');
-
- // Price is removed from buyer balance, and added to seller
- expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal('0');
- expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal(PRICE.toString());
- }
-
- // Token is transferred to evm account of alice
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
-
- // Transfer token to substrate side of alice
- await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
-
- // Token is transferred to substrate account of alice, seller received funds
- expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {
- const matcherOwner = await helper.eth.createAccountWithBalance(donor);
- const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
-
- await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);
-
- const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}});
- const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
-
- await helper.balance.transferToSubstrate(donor, seller.address, 100_000_000_000_000_000_000n);
-
- const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
-
- // Token is owned by seller initially
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
-
- // Ask
- {
- await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
- await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
- }
-
- // Token is transferred to matcher
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
-
- // Buy
- {
- const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);
- await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());
- expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);
- }
-
- // Token is transferred to evm account of alice
- expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
-
- // Transfer token to substrate side of alice
- await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
-
- // Token is transferred to substrate account of alice, seller received funds
- expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-});
js-packages/tests/src/eth/migration.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/migration.seqtest.ts
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Struct} from '@polkadot/types';
-
-import type {IEvent} from '@unique/playgrounds/src/types.js';
-import type {InterfaceTypes} from '@polkadot/types/types/registry';
-import {ApiPromise} from '@polkadot/api';
-
-const encodeEvent = (api: ApiPromise, pallet: string, palletEvents: string, event: string, fields: any) => {
- const palletIndex = api.runtimeMetadata.asV14.pallets.find(p => p.name.toString() == pallet)!.index.toNumber();
- const eventMeta = api.events[palletEvents][event].meta;
- const eventIndex = eventMeta.index.toNumber();
- const data = [
- palletIndex, eventIndex,
- ];
- const metaEvent = api.registry.findMetaEvent(new Uint8Array(data));
- data.push(...new Struct(api.registry, {data: metaEvent}, {data: fields}).toU8a());
-
- const typeName = api.registry.lookup.names.find(n => n.endsWith('RuntimeEvent'))!;
- const obj = api.registry.createType(typeName, new Uint8Array(data)) as InterfaceTypes['RuntimeEvent'];
- return obj.toHex();
-};
-
-describe('EVM Migrations', () => {
- let superuser: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- superuser = await privateKey('//Alice');
- charlie = await privateKey('//Charlie');
- });
- });
-
- // todo:playgrounds requires sudo, look into later
- itEth('Deploy contract saved state', async ({helper}) => {
- /*
- contract StatefulContract {
- uint counter;
- mapping (uint => uint) kv;
-
- function inc() public {
- counter = counter + 1;
- }
- function counterValue() public view returns (uint) {
- return counter;
- }
-
- function set(uint key, uint value) public {
- kv[key] = value;
- }
-
- function get(uint key) public view returns (uint) {
- return kv[key];
- }
- }
- */
- const ADDRESS = '0x4956bf52ef9ed8789f21bc600e915e0d961079f6';
- const CODE = '0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ab06ee514610051578063371303c01461006d5780637bfdec3b146100775780639507d39a14610095575b600080fd5b61006b60048036038101906100669190610160565b6100c5565b005b6100756100e1565b005b61007f6100f8565b60405161008c91906101af565b60405180910390f35b6100af60048036038101906100aa9190610133565b610101565b6040516100bc91906101af565b60405180910390f35b8060016000848152602001908152602001600020819055505050565b60016000546100f091906101ca565b600081905550565b60008054905090565b600060016000838152602001908152602001600020549050919050565b60008135905061012d8161025e565b92915050565b60006020828403121561014957610148610259565b5b60006101578482850161011e565b91505092915050565b6000806040838503121561017757610176610259565b5b60006101858582860161011e565b92505060206101968582860161011e565b9150509250929050565b6101a981610220565b82525050565b60006020820190506101c460008301846101a0565b92915050565b60006101d582610220565b91506101e083610220565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156102155761021461022a565b5b828201905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b61026781610220565b811461027257600080fd5b5056fea26469706673582212206a02d2fb5c244105ab884961479c1aee3b4c1011e4b5530ab483eb22344a865664736f6c63430008060033';
- const DATA = [
- // counter = 10
- ['0x0000000000000000000000000000000000000000000000000000000000000000', '0x000000000000000000000000000000000000000000000000000000000000000a'],
- // kv = {1: 1, 2: 2, 3: 3, 4: 4},
- ['0xcc69885fda6bcc1a4ace058b4a62bf5e179ea78fd58a1ccd71c22cc9b688792f', '0x0000000000000000000000000000000000000000000000000000000000000001'],
- ['0xd9d16d34ffb15ba3a3d852f0d403e2ce1d691fb54de27ac87cd2f993f3ec330f', '0x0000000000000000000000000000000000000000000000000000000000000002'],
- ['0x7dfe757ecd65cbd7922a9c0161e935dd7fdbcc0e999689c7d31633896b1fc60b', '0x0000000000000000000000000000000000000000000000000000000000000003'],
- ['0xedc95719e9a3b28dd8e80877cb5880a9be7de1a13fc8b05e7999683b6b567643', '0x0000000000000000000000000000000000000000000000000000000000000004'],
- ];
-
- const caller = await helper.eth.createAccountWithBalance(superuser);
-
- const txBegin = helper.constructApiCall('api.tx.evmMigration.begin', [ADDRESS]);
- const txSetData = helper.constructApiCall('api.tx.evmMigration.setData', [ADDRESS, DATA]);
- const txFinish = helper.constructApiCall('api.tx.evmMigration.finish', [ADDRESS, CODE]);
- await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txBegin])).to.be.fulfilled;
- await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txSetData])).to.be.fulfilled;
- await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txFinish])).to.be.fulfilled;
-
- const web3 = helper.getWeb3();
- const contract = new web3.eth.Contract([
- {
- inputs: [],
- name: 'counterValue',
- outputs: [{
- internalType: 'uint256',
- name: '',
- type: 'uint256',
- }],
- stateMutability: 'view',
- type: 'function',
- },
- {
- inputs: [{
- internalType: 'uint256',
- name: 'key',
- type: 'uint256',
- }],
- name: 'get',
- outputs: [{
- internalType: 'uint256',
- name: '',
- type: 'uint256',
- }],
- stateMutability: 'view',
- type: 'function',
- },
- ], ADDRESS, {from: caller, gas: helper.eth.DEFAULT_GAS});
-
- expect(await contract.methods.counterValue().call()).to.be.equal('10');
- for(let i = 1; i <= 4; i++) {
- expect(await contract.methods.get(i).call()).to.be.equal(i.toString());
- }
- });
- itEth('Fake collection creation on substrate side', async ({helper}) => {
- const txInsertEvents = helper.constructApiCall('api.tx.evmMigration.insertEvents', [[
- encodeEvent(helper.getApi(), 'Common', 'common', 'CollectionCreated', [
- // Collection Id
- 9999,
- // Collection mode: NFT
- 1,
- // Owner
- charlie.address,
- ]),
- ]]);
- await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEvents]);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contain('common.CollectionCreated');
- });
- itEth('Fake token creation on substrate side', async ({helper}) => {
- const txInsertEvents = helper.constructApiCall('api.tx.evmMigration.insertEvents', [[
- encodeEvent(helper.getApi(), 'Common', 'common', 'ItemCreated', [
- // Collection Id
- 9999,
- // TokenId
- 9999,
- // Owner
- {Substrate: charlie.address},
- // Amount
- 1,
- ]),
- ]]);
- await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEvents]);
- const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
- const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
- expect(eventStrings).to.contain('common.ItemCreated');
- });
- itEth('Fake token creation on ethereum side', async ({helper}) => {
- const collection = await helper.nft.mintCollection(superuser);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const caller = await helper.eth.createAccountWithBalance(superuser);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- {
- const txInsertEthLogs = helper.constructApiCall('api.tx.evmMigration.insertEthLogs', [[
- {
- // Contract, which has emitted this log
- address: collectionAddress,
-
- topics: [
- // First topic - event signature
- helper.getWeb3().eth.abi.encodeEventSignature('Transfer(address,address,uint256)'),
- // Rest of topics - indexed event fields in definition order
- helper.getWeb3().eth.abi.encodeParameter('address', '0x' + '00'.repeat(20)),
- helper.getWeb3().eth.abi.encodeParameter('address', caller),
- helper.getWeb3().eth.abi.encodeParameter('uint256', 9999),
- ],
-
- // Every field coming from event, which is not marked as indexed, should be encoded here
- // NFT transfer has no such fields, but here is an example for some other possible event:
- // data: helper.getWeb3().eth.abi.encodeParameters(['uint256', 'address'], [22, collectionAddress])
- data: [],
- },
- ]]);
- await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEthLogs]);
- }
-
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x' + '00'.repeat(20));
- expect(event.returnValues.to).to.be.equal(caller);
- expect(event.returnValues.tokenId).to.be.equal('9999');
- });
-});
js-packages/tests/src/eth/nativeFungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/nativeFungible.test.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-
-describe('NativeFungible: ERC20 calls', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('approve()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- await expect(contract.methods.approve(spender, 100).call({from: owner})).to.be.rejectedWith('approve not supported');
- });
-
- itEth('balanceOf()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor, 123n);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const balance = await contract.methods.balanceOf(owner).call({from: owner});
- expect(balance).to.be.eq('123000000000000000000');
- });
-
- itEth('decimals()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const realDecimals = (await helper.chain.getChainProperties().tokenDecimals)[0].toString();
- const decimals = await contract.methods.decimals().call({from: owner});
- expect(decimals).to.be.eq(realDecimals);
- });
-
- itEth('name()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const realName = await UniqueHelper.detectNetwork(helper.getApi());
- const name = await contract.methods.name().call({from: owner});
- expect(name).to.be.eq(realName);
- });
-
- itEth('symbol()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const realName = (await helper.chain.getChainProperties().tokenSymbol)[0];
- const name = await contract.methods.symbol().call({from: owner});
- expect(name).to.be.eq(realName);
- });
-
- itEth('totalSupply()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const totalSupplyEth = BigInt(await contract.methods.totalSupply().call({from: owner}));
- const totalSupplySub = await helper.balance.getTotalIssuance();
- expect(totalSupplyEth).to.be.eq(totalSupplySub);
- });
-
- itEth('transfer()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const balanceOwnerBefore = await helper.balance.getEthereum(owner);
- const balanceReceiverBefore = await helper.balance.getEthereum(receiver);
-
- await contract.methods.transfer(receiver, 50).send({from: owner});
-
- const balanceOwnerAfter = await helper.balance.getEthereum(owner);
- const balanceReceiverAfter = await helper.balance.getEthereum(receiver);
-
- expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
- expect(balanceReceiverBefore + 50n).to.be.equal(balanceReceiverAfter);
- });
-
- itEth('transferFrom()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const balanceOwnerBefore = await helper.balance.getEthereum(owner);
- const balanceReceiverBefore = await helper.balance.getEthereum(receiver);
-
- await contract.methods.transferFrom(owner, receiver, 50).send({from: owner});
-
- const balanceOwnerAfter = await helper.balance.getEthereum(owner);
- const balanceReceiverAfter = await helper.balance.getEthereum(receiver);
-
- expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
- expect(balanceReceiverBefore === balanceReceiverAfter - 50n).to.be.true;
-
- await expect(contract.methods.transferFrom(receiver, receiver, 50).call({from: owner})).to.be.rejectedWith('ApprovedValueTooLow');
- });
-});
-
-describe('NativeFungible: ERC20UniqueExtensions calls', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('transferCross()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-
- const balanceOwnerBefore = await helper.balance.getEthereum(owner);
- const balanceReceiverBefore = await helper.balance.getEthereum(receiver.eth);
-
- await contract.methods.transferCross(receiver, 50).send({from: owner});
-
- const balanceOwnerAfter = await helper.balance.getEthereum(owner);
- const balanceReceiverAfter = await helper.balance.getEthereum(receiver.eth);
-
- expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
- expect(balanceReceiverBefore === balanceReceiverAfter - 50n).to.be.true;
- });
-
- itEth('transferFromCross()', async ({helper}) => {
- const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const receiver = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner.eth);
-
- const balanceOwnerBefore = await helper.balance.getEthereum(owner.eth);
- const balanceReceiverBefore = await helper.balance.getEthereum(receiver.eth);
-
- await contract.methods.transferFromCross(owner, receiver, 50).send({from: owner.eth});
-
- const balanceOwnerAfter = await helper.balance.getEthereum(owner.eth);
- const balanceReceiverAfter = await helper.balance.getEthereum(receiver.eth);
-
- expect(balanceOwnerBefore - 50n > balanceOwnerAfter).to.be.true;
- expect(balanceReceiverBefore === balanceReceiverAfter - 50n).to.be.true;
-
- await expect(contract.methods.transferFromCross(receiver, receiver, 50).call({from: owner.eth})).to.be.rejectedWith('no permission');
- });
-});
js-packages/tests/src/eth/nativeRpc/estimateGas.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/nativeRpc/estimateGas.test.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-
-describe('Ethereum native RPC calls', () => {
- let donor: IKeyringPair;
- const NATIVE_TOKEN_ADDRESS = '0x17c4e6453cc49aaaaeaca894e6d9683e00000000';
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('estimate gas', async ({helper}) => {
- const BALANCE = 100n;
- const BALANCE_TO_TRANSFER = 90n;
-
- const owner = await helper.eth.createAccountWithBalance(donor, BALANCE);
- const recepient = helper.eth.createAccount();
-
- const web3 = helper.getWeb3();
- // data: transfer(recepient, 90);
- const data = web3.eth.abi.encodeFunctionCall({
- name: 'transfer',
- type: 'function',
- inputs: [{
- type: 'address',
- name: 'to',
- },{
- type: 'uint256',
- name: 'amount',
- }],
- }, [recepient, (BALANCE_TO_TRANSFER * (10n ** 18n)).toString()]);
-
- const estimateGas = await web3.eth.estimateGas({
- to: NATIVE_TOKEN_ADDRESS,
- value: '0x0',
- data,
- from: owner,
- maxFeePerGas: '0x14c9338c61d',
- });
-
- expect(estimateGas).to.be.greaterThan(35000).and.to.be.lessThan(50000);
- });
-});
js-packages/tests/src/eth/nesting/nest.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/nesting/nest.test.ts
+++ /dev/null
@@ -1,289 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Contract} from 'web3-eth-contract';
-
-import {itEth, usingEthPlaygrounds, expect} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
-
-const createNestingCollection = async (
- helper: EthUniqueHelper,
- owner: string,
- mergeDeprecated = false,
-): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
- const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, mergeDeprecated);
- await contract.methods.setCollectionNesting([true, false, []]).send({from: owner});
-
- return {collectionId, collectionAddress, contract};
-};
-
-
-describe('EVM nesting tests group', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- describe('Integration Test: EVM Nesting', () => {
- itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, contract} = await createNestingCollection(helper, owner);
-
- // Create a token to be nested to
- const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
-
- // Create a nested token
- const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});
- const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;
- expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Create a token to be nested and nest
- const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;
-
- await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Unnest token back
- await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
- });
-
- itEth('NFT: collectionNesting()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress: unnestedCollectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const unnestedContract = await helper.ethNativeContract.collection(unnestedCollectionAddress, 'nft', owner);
- expect(await unnestedContract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
-
- const {contract} = await createNestingCollection(helper, owner);
- expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([true, false, []]);
- await contract.methods.setCollectionNesting([true, false, [unnestedCollectionAddress]]).send({from: owner});
- expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([true, false, [unnestedCollectionAddress]]);
- await contract.methods.setCollectionNesting([false, true, [unnestedCollectionAddress]]).send({from: owner});
- expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([false, true, [unnestedCollectionAddress]]);
- await contract.methods.setCollectionNesting([false, false, []]).send({from: owner});
- expect(await contract.methods.collectionNesting().call({from: owner})).to.be.like([false, false, []]);
- });
-
- // Sof-deprecated
- itEth('NFT: collectionNestingRestrictedCollectionIds() & collectionNestingPermissions', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId: unnestedCollsectionId, collectionAddress: unnsetedCollectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
- const unnestedContract = await helper.ethNativeContract.collection(unnsetedCollectionAddress, 'nft', owner, true);
- expect(await unnestedContract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([false, []]);
-
- const {contract} = await createNestingCollection(helper, owner, true);
- expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, []]);
- await contract.methods['setCollectionNesting(bool,address[])'](true, [unnsetedCollectionAddress]).send({from: owner});
- expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, [unnestedCollsectionId.toString()]]);
- expect(await contract.methods.collectionNestingPermissions().call({from: owner})).to.be.like([['1', false], ['0', true]]);
- await contract.methods['setCollectionNesting(bool)'](false).send({from: owner});
- expect(await contract.methods.collectionNestingPermissions().call({from: owner})).to.be.like([['1', false], ['0', false]]);
- });
-
- itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId: collectionIdA, contract: contractA} = await createNestingCollection(helper, owner);
- const {contract: contractB} = await createNestingCollection(helper, owner);
- await contractA.methods.setCollectionNesting([true, false, [contractA.options.address, contractB.options.address]]).send({from: owner});
-
- // Create a token to nest into
- const mintingtargetNftTokenIdResult = await contractA.methods.mint(owner).send({from: owner});
- const targetNftTokenId = mintingtargetNftTokenIdResult.events.Transfer.returnValues.tokenId;
- const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);
-
- // Create a token for nesting in the same collection as the target
- const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
- const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
-
- // Create a token for nesting in a different collection
- const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});
- const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
-
- // Nest
- await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
- expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
-
- await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
- expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
- });
- });
-
- describe('Negative Test: EVM Nesting', () => {
- itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId, contract} = await createNestingCollection(helper, owner);
- await contract.methods.setCollectionNesting([false, false, []]).send({from: owner});
-
- // Create a token to nest into
- const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
-
- // Create a token to nest
- const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;
-
- // Try to nest
- await expect(contract.methods
- .transfer(targetNftTokenAddress, nftTokenId)
- .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const malignant = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId, contract} = await createNestingCollection(helper, owner);
-
- // Mint a token
- const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});
- const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
-
- // Mint a token belonging to a different account
- const mintingTokenIdResult = await contract.methods.mint(malignant).send({from: owner});
- const tokenId = mintingTokenIdResult.events.Transfer.returnValues.tokenId;
-
- // Try to nest one token in another as a non-owner account
- await expect(contract.methods
- .transfer(targetTokenAddress, tokenId)
- .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const malignant = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId: collectionIdA, contract: contractA} = await createNestingCollection(helper, owner);
- const {contract: contractB} = await createNestingCollection(helper, owner);
-
- await contractA.methods.setCollectionNesting([true, false, [contractA.options.address, contractB.options.address]]).send({from: owner});
-
- // Create a token in one collection
- const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
- const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
- const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
-
- // Create a token in another collection
- const mintingTokenIdBResult = await contractB.methods.mint(malignant).send({from: owner});
- const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
-
- // Try to drag someone else's token into the other collection and nest
- await expect(contractB.methods
- .transfer(nftTokenAddressA, nftTokenIdB)
- .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId: collectionIdA, contract: contractA} = await createNestingCollection(helper, owner);
- const {contract: contractB} = await createNestingCollection(helper, owner);
-
- await contractA.methods.setCollectionNesting([true, false, [contractA.options.address]]).send({from: owner});
-
- // Create a token in one collection
- const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});
- const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;
- const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
-
- // Create a token in another collection
- const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});
- const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;
-
-
- // Try to nest into a token in the other collection, disallowed in the first
- await expect(contractB.methods
- .transfer(nftTokenAddressA, nftTokenIdB)
- .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
- });
- });
-
- describe('Fungible', () => {
- async function createFungibleCollection(helper: EthUniqueHelper, owner: string, mode: 'ft' | 'native ft') {
- if(mode === 'ft') {
- const {collectionAddress} = await helper.eth.createFungibleCollection(owner, '', 18, '', '');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
- await contract.methods.mint(owner, 100n).send({from: owner});
- return {collectionAddress, contract};
- }
-
- // native ft
- const collectionAddress = helper.ethAddress.fromCollectionId(0);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
- return {collectionAddress, contract};
- }
-
- [
- {mode: 'ft' as const},
- {mode: 'native ft' as const},
- ].map(testCase => {
- itEth(`Allow nest [${testCase.mode}]`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
- const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
-
- const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
- const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
-
- await ftContract.methods.transfer(targetTokenAddress, 10n).send({from: owner});
- expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('10');
- });
- });
-
- [
- {mode: 'ft' as const},
- {mode: 'native ft' as const},
- ].map(testCase => {
- itEth(`Allow partial/full unnest [${testCase.mode}]`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
- const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
-
- const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
- const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
-
- await ftContract.methods.transfer(targetTokenAddress, 10n).send({from: owner});
-
- await ftContract.methods.transferFrom(targetTokenAddress, owner, 5n).send({from: owner});
- expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('5');
-
- await ftContract.methods.transferFrom(targetTokenAddress, owner, 5n).send({from: owner});
- expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('0');
- });
- });
-
- [
- {mode: 'ft' as const},
- {mode: 'native ft' as const},
- ].map(testCase => {
- itEth(`Disallow nest into collection without nesting permission [${testCase.mode}] (except for native fungible collection)`, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
- await targetContract.methods.setCollectionNesting([false, false, []]).send({from: owner});
-
- const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
-
- const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
- const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
- const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
-
- if(testCase.mode === 'ft') {
- await expect(ftContract.methods.transfer(targetTokenAddress, 10n).call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
- } else {
- await expect(ftContract.methods.transfer(targetTokenAddress, 10n).call({from: owner})).to.be.not.rejected;
- }
- });
- });
- });
-});
js-packages/tests/src/eth/nonFungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/nonFungible.test.ts
+++ /dev/null
@@ -1,1127 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Contract} from 'web3-eth-contract';
-import type {ITokenPropertyPermission} from '@unique/playgrounds/src/types.js';
-import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from './util/playgrounds/types.js';
-
-describe('Check ERC721 token URI for NFT', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- async function setup(helper: EthUniqueHelper, baseUri: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- const result = await contract.methods.mint(receiver).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
-
- if(propertyKey && propertyValue) {
- // Set URL or suffix
- await contract.methods.setProperties(tokenId, [{key: propertyKey, value: Buffer.from(propertyValue)}]).send();
- }
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(tokenId);
-
- return {contract, nextTokenId: tokenId};
- }
-
- itEth('Empty tokenURI', async ({helper}) => {
- const {contract, nextTokenId} = await setup(helper, '');
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
- });
-
- itEth('TokenURI from url', async ({helper}) => {
- const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URI', 'Token URI');
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
- });
-
- itEth('TokenURI from baseURI', async ({helper}) => {
- const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_');
- });
-
- itEth('TokenURI from baseURI + suffix', async ({helper}) => {
- const suffix = '/some/suffix';
- const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URISuffix', suffix);
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
- });
-});
-
-describe('NFT: Plain calls', () => {
- let donor: IKeyringPair;
- let minter: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- // TODO combine all minting tests in one place
- [
- 'substrate' as const,
- 'ethereum' as const,
- ].map(testCase => {
- itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
- const collectionAdmin = await helper.eth.createAccountWithBalance(donor);
-
- const receiverEth = helper.eth.createAccount();
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const receiverSub = bob;
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
-
- // const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);
- const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
- const permissions: ITokenPropertyPermission[] = properties
- .map(p => ({
- key: p.key, permission: {
- tokenOwner: false,
- collectionAdmin: true,
- mutable: false,
- },
- }));
-
- const collection = await helper.nft.mintCollection(minter, {
- tokenPrefix: 'ethp',
- tokenPropertyPermissions: permissions,
- });
- await collection.addAdmin(minter, {Ethereum: collectionAdmin});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', collectionAdmin, true);
- let expectedTokenId = await contract.methods.nextTokenId().call();
- let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();
- let tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal(expectedTokenId);
-
- let event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
-
- expectedTokenId = await contract.methods.nextTokenId().call();
- result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();
- event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
-
- tokenId = result.events.Transfer.returnValues.tokenId;
-
- expect(tokenId).to.be.equal(expectedTokenId);
-
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
- .map(p => helper.ethProperty.property(p.key, p.value.toString())));
-
- expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))
- .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});
- });
- });
-
- itEth('Non-owner and non admin cannot mintCross', async ({helper}) => {
- const nonOwner = await helper.eth.createAccountWithBalance(donor);
- const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
-
- const collection = await helper.nft.mintCollection(minter);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- await expect(collectionEvm.methods.mintCross(nonOwnerCross, []).call({from: nonOwner}))
- .to.be.rejectedWith('PublicMintingNotAllowed');
- });
-
- //TODO: CORE-302 add eth methods
- itEth.skip('Can perform mintBulk()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(minter);
- await collection.addAdmin(minter, {Ethereum: caller});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
- {
- const bulkSize = 3;
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const result = await contract.methods.mintBulkWithTokenURI(
- receiver,
- Array.from({length: bulkSize}, (_, i) => (
- [+nextTokenId + i, `Test URI ${i}`]
- )),
- ).send({from: caller});
-
- const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);
- for(let i = 0; i < bulkSize; i++) {
- const event = events[i];
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);
-
- expect(await contract.methods.tokenURI(+nextTokenId + i).call()).to.be.equal(`Test URI ${i}`);
- }
- }
- });
-
- itEth('Can perform mintBulkCross()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const receiver = helper.eth.createAccount();
- const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
-
- const permissions = [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.TokenOwner, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true},
- ];
- const {collectionAddress} = await helper.eth.createCollection(
- caller,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'nft',
- adminList: [callerCross],
- tokenPropertyPermissions: [
- {key: 'key_0_0', permissions},
- {key: 'key_1_0', permissions},
- {key: 'key_1_1', permissions},
- {key: 'key_2_0', permissions},
- {key: 'key_2_1', permissions},
- {key: 'key_2_2', permissions},
- ],
- },
- ).send();
-
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
- {
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const result = await contract.methods.mintBulkCross([
- {
- owner: receiverCross,
- properties: [
- {key: 'key_0_0', value: Buffer.from('value_0_0')},
- ],
- },
- {
- owner: receiverCross,
- properties: [
- {key: 'key_1_0', value: Buffer.from('value_1_0')},
- {key: 'key_1_1', value: Buffer.from('value_1_1')},
- ],
- },
- {
- owner: receiverCross,
- properties: [
- {key: 'key_2_0', value: Buffer.from('value_2_0')},
- {key: 'key_2_1', value: Buffer.from('value_2_1')},
- {key: 'key_2_2', value: Buffer.from('value_2_2')},
- ],
- },
- ]).send({from: caller});
- const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);
- const bulkSize = 3;
- for(let i = 0; i < bulkSize; i++) {
- const event = events[i];
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);
- }
-
- const properties = [
- await contract.methods.properties(+nextTokenId, []).call(),
- await contract.methods.properties(+nextTokenId + 1, []).call(),
- await contract.methods.properties(+nextTokenId + 2, []).call(),
- ];
- expect(properties).to.be.deep.equal([
- [
- ['key_0_0', helper.getWeb3().utils.toHex('value_0_0')],
- ],
- [
- ['key_1_0', helper.getWeb3().utils.toHex('value_1_0')],
- ['key_1_1', helper.getWeb3().utils.toHex('value_1_1')],
- ],
- [
- ['key_2_0', helper.getWeb3().utils.toHex('value_2_0')],
- ['key_2_1', helper.getWeb3().utils.toHex('value_2_1')],
- ['key_2_2', helper.getWeb3().utils.toHex('value_2_2')],
- ],
- ]);
- }
- });
-
- itEth('Can perform burn()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.nft.mintCollection(minter, {});
- const {tokenId} = await collection.mintToken(minter, {Ethereum: caller});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
-
- {
- const result = await contract.methods.burn(tokenId).send({from: caller});
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(caller);
- expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
- }
- });
-
- itEth('Can perform approve()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(minter, {});
- const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- {
- const badTokenId = await contract.methods.nextTokenId().call() + 1;
- await expect(contract.methods.getApproved(badTokenId).call()).to.be.rejectedWith('revert TokenNotFound');
- }
- {
- const approved = await contract.methods.getApproved(tokenId).call();
- expect(approved).to.be.equal('0x0000000000000000000000000000000000000000');
- }
- {
- const result = await contract.methods.approve(spender, tokenId).send({from: owner});
-
- const event = result.events.Approval;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.approved).to.be.equal(spender);
- expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
- }
- {
- const approved = await contract.methods.getApproved(tokenId).call();
- expect(approved).to.be.equal(spender);
- }
- });
-
- itEth('Can perform setApprovalForAll()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(minter, {});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
- expect(approvedBefore).to.be.equal(false);
-
- {
- const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
-
- expect(result.events.ApprovalForAll).to.be.like({
- address: collectionAddress,
- event: 'ApprovalForAll',
- returnValues: {
- owner,
- operator,
- approved: true,
- },
- });
-
- const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
- expect(approvedAfter).to.be.equal(true);
- }
-
- {
- const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
-
- expect(result.events.ApprovalForAll).to.be.like({
- address: collectionAddress,
- event: 'ApprovalForAll',
- returnValues: {
- owner,
- operator,
- approved: false,
- },
- });
-
- const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
- expect(approvedAfter).to.be.equal(false);
- }
- });
-
- itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft');
-
- {
- await contract.methods.setApprovalForAll(operator, true).send({from: owner});
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
- const events = result.events.Transfer;
-
- expect(events).to.be.like({
- address,
- event: 'Transfer',
- returnValues: {
- from: owner,
- to: '0x0000000000000000000000000000000000000000',
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await helper.nft.doesTokenExist(collection.collectionId, token.tokenId)).to.be.false;
- });
-
- itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = await helper.eth.createAccountWithBalance(donor);
- const receiver = charlie;
-
- const token = await collection.mintToken(minter, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft');
-
- {
- await contract.methods.setApprovalForAll(operator, true).send({from: owner});
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
- const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: owner,
- to: helper.address.substrateToEth(receiver.address),
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
- });
-
- itEth('Can perform burnFromCross()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const ownerSub = bob;
- const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
- const ownerEth = await helper.eth.createAccountWithBalance(donor);
- const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
-
- const burnerEth = await helper.eth.createAccountWithBalance(donor);
- const burnerCrossEth = helper.ethCrossAccount.fromAddress(burnerEth);
-
- const token1 = await collection.mintToken(minter, {Substrate: ownerSub.address});
- const token2 = await collection.mintToken(minter, {Ethereum: ownerEth});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- // Approve tokens from substrate and ethereum:
- await token1.approve(ownerSub, {Ethereum: burnerEth});
- await collectionEvm.methods.approveCross(burnerCrossEth, token2.tokenId).send({from: ownerEth});
-
- // can burnFromCross:
- const result1 = await collectionEvm.methods.burnFromCross(ownerCrossSub, token1.tokenId).send({from: burnerEth});
- const result2 = await collectionEvm.methods.burnFromCross(ownerCrossEth, token2.tokenId).send({from: burnerEth});
- const events1 = result1.events.Transfer;
- const events2 = result2.events.Transfer;
-
- // Check events for burnFromCross (substrate and ethereum):
- [
- [events1, token1, helper.address.substrateToEth(ownerSub.address)],
- [events2, token2, ownerEth],
- ].map(burnData => {
- expect(burnData[0]).to.be.like({
- address: collectionAddress,
- event: 'Transfer',
- returnValues: {
- from: burnData[2],
- to: '0x0000000000000000000000000000000000000000',
- tokenId: burnData[1].tokenId.toString(),
- },
- });
- });
-
- expect(await token1.doesExist()).to.be.false;
- expect(await token2.doesExist()).to.be.false;
- });
-
- // TODO combine all approve tests in one place
- itEth('Can perform approveCross()', async ({helper}) => {
- // arrange: create accounts
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const receiverSub = charlie;
- const recieverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
- const receiverEth = await helper.eth.createAccountWithBalance(donor);
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
-
- // arrange: create collection and tokens:
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const token1 = await collection.mintToken(minter, {Ethereum: owner});
- const token2 = await collection.mintToken(minter, {Ethereum: owner});
-
- const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
-
- // Can approveCross substrate and ethereum address:
- const resultSub = await collectionEvm.methods.approveCross(recieverCrossSub, token1.tokenId).send({from: owner});
- const resultEth = await collectionEvm.methods.approveCross(receiverCrossEth, token2.tokenId).send({from: owner});
- const eventSub = resultSub.events.Approval;
- const eventEth = resultEth.events.Approval;
- expect(eventSub).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Approval',
- returnValues: {
- owner,
- approved: helper.address.substrateToEth(receiverSub.address),
- tokenId: token1.tokenId.toString(),
- },
- });
- expect(eventEth).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Approval',
- returnValues: {
- owner,
- approved: receiverEth,
- tokenId: token2.tokenId.toString(),
- },
- });
-
- // Substrate address can transferFrom approved tokens:
- await helper.nft.transferTokenFrom(receiverSub, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiverSub.address});
- expect(await helper.nft.getTokenOwner(collection.collectionId, token1.tokenId)).to.deep.eq({Substrate: receiverSub.address});
- // Ethereum address can transferFromCross approved tokens:
- await collectionEvm.methods.transferFromCross(ownerCross, receiverCrossEth, token2.tokenId).send({from: receiverEth});
- expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
- });
-
- itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {
- const nonOwner = await helper.eth.createAccountWithBalance(donor);
- const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
- const token = await collection.mintToken(minter, {Ethereum: owner});
-
- await expect(collectionEvm.methods.approveCross(nonOwnerCross, token.tokenId).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');
- });
-
- itEth('Can reaffirm approved address', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
- const [receiver1, receiver2] = await helper.arrange.createAccounts([100n, 100n], donor);
- const receiver1Cross = helper.ethCrossAccount.fromKeyringPair(receiver1);
- const receiver2Cross = helper.ethCrossAccount.fromKeyringPair(receiver2);
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const token1 = await collection.mintToken(minter, {Ethereum: owner});
- const token2 = await collection.mintToken(minter, {Ethereum: owner});
- const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
-
- // Can approve and reaffirm approved address:
- await collectionEvm.methods.approveCross(receiver1Cross, token1.tokenId).send({from: owner});
- await collectionEvm.methods.approveCross(receiver2Cross, token1.tokenId).send({from: owner});
-
- // receiver1 cannot transferFrom:
- await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
- // receiver2 can transferFrom:
- await helper.nft.transferTokenFrom(receiver2, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver2.address});
-
- // can set approved address to self address to remove approval:
- await collectionEvm.methods.approveCross(receiver1Cross, token2.tokenId).send({from: owner});
- await collectionEvm.methods.approveCross(ownerCrossEth, token2.tokenId).send({from: owner});
-
- // receiver1 cannot transfer token anymore:
- await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token2.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
- });
-
- itEth('Can perform transferFrom()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(minter, {});
- const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- await contract.methods.approve(spender, tokenId).send({from: owner});
-
- {
- const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(1);
- }
-
- {
- const balance = await contract.methods.balanceOf(owner).call();
- expect(+balance).to.equal(0);
- }
- });
-
- itEth('Can perform transferFromCross()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const [owner, receiver] = await helper.arrange.createAccounts([100n, 100n], donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, {Substrate: owner.address});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft');
-
- await token.approve(owner, {Ethereum: spender});
-
- {
- const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
- const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: helper.address.substrateToEth(receiver.address),
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
- });
-
- itEth('Can perform transfer()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {});
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- {
- const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
- }
-
- {
- const balance = await contract.methods.balanceOf(owner).call();
- expect(+balance).to.equal(0);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(1);
- }
- });
-
- itEth('Can perform transferCross()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {});
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiverEth = await helper.eth.createAccountWithBalance(donor);
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
-
- const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-
- {
- // Can transferCross to ethereum address:
- const result = await collectionEvm.methods.transferCross(receiverCrossEth, tokenId).send({from: owner});
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal(receiverEth);
- expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
-
- // owner has balance = 0:
- const ownerBalance = await collectionEvm.methods.balanceOf(owner).call();
- expect(+ownerBalance).to.equal(0);
- // receiver owns token:
- const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
- expect(+receiverBalance).to.equal(1);
- expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
- }
-
- {
- // Can transferCross to substrate address:
- const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, tokenId).send({from: receiverEth});
- // Check events:
- const event = substrateResult.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(receiverEth);
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
- expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
-
- // owner has balance = 0:
- const ownerBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
- expect(+ownerBalance).to.equal(0);
- // receiver owns token:
- const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
- expect(receiverBalance).to.contain(tokenId);
- }
- });
-
- ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
- const tokenOwner = await helper.eth.createAccountWithBalance(donor);
- const receiverSub = minter;
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
-
- const collection = await helper.nft.mintCollection(minter, {});
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', sender);
-
- await collection.mintToken(minter, {Ethereum: sender});
- const nonSendersToken = await collection.mintToken(minter, {Ethereum: tokenOwner});
-
- // Cannot transferCross someone else's token:
- const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;
- await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;
- // Cannot transfer token if it does not exist:
- await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;
- }));
-
- itEth('Check balanceOfCross()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {});
- const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
-
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
-
- for(let i = 1; i < 10; i++) {
- await collection.mintToken(minter, {Ethereum: owner.eth});
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq(i.toString());
- }
- });
-
- itEth('Check ownerOfCross()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {});
- let owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
- const {tokenId} = await collection.mintToken(minter, {Ethereum: owner.eth});
-
- for(let i = 1n; i < 10n; i++) {
- const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth});
- expect(ownerCross.eth).to.be.eq(owner.eth);
- expect(ownerCross.sub).to.be.eq(owner.sub);
-
- const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- await collectionEvm.methods.transferCross(newOwner, tokenId).send({from: owner.eth});
- owner = newOwner;
- }
- });
-});
-
-describe('NFT: Fees', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(alice, {});
- const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
-
- const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
-
- const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-
- itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const collection = await helper.nft.mintCollection(alice, {});
- const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
-
- const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
-
- await contract.methods.approve(spender, tokenId).send({from: owner});
-
- const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-
- itEth('Can perform transferFromCross()', async ({helper}) => {
- const collectionMinter = alice;
- const owner = bob;
- const receiver = charlie;
- const collection = await helper.nft.mintCollection(collectionMinter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(collectionMinter, {Substrate: owner.address});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft');
-
- await token.approve(owner, {Ethereum: spender});
-
- {
- const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
- const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: helper.address.substrateToEth(receiver.address),
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
- });
-
- itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(alice, {});
- const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
-
- const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
-
- const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-});
-
-describe('NFT: Substrate calls', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([20n], donor);
- });
- });
-
- itEth('Events emitted for mint()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- const {tokenId} = await collection.mintToken(alice);
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Transfer');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.tokenId).to.be.equal(tokenId.toString());
- });
-
- itEth('Events emitted for burn()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- const token = await collection.mintToken(alice);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await token.burn(alice);
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Transfer');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
- });
-
- itEth('Events emitted for approve()', async ({helper}) => {
- const receiver = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(alice, {});
- const token = await collection.mintToken(alice);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await token.approve(alice, {Ethereum: receiver});
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Approval');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.approved).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
- });
-
- itEth('Events emitted for transferFrom()', async ({helper}) => {
- const [bob] = await helper.arrange.createAccounts([10n], donor);
- const receiver = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(alice, {});
- const token = await collection.mintToken(alice);
- await token.approve(alice, {Substrate: bob.address});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver});
-
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
- });
-
- itEth('Events emitted for transfer()', async ({helper}) => {
- const receiver = helper.eth.createAccount();
-
- const collection = await helper.nft.mintCollection(alice, {});
- const token = await collection.mintToken(alice);
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft');
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await token.transfer(alice, {Ethereum: receiver});
-
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
- });
-});
-
-describe('Common metadata', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([20n], donor);
- });
- });
-
- itEth('Returns collection name', async ({helper}) => {
- const caller = helper.eth.createAccount();
- const tokenPropertyPermissions = [{
- key: 'URI',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: false,
- },
- }];
- const collection = await helper.nft.mintCollection(
- alice,
- {
- name: 'oh River',
- tokenPrefix: 'CHANGE',
- properties: [{key: 'ERC721Metadata', value: '1'}],
- tokenPropertyPermissions,
- },
- );
-
- const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
- const name = await contract.methods.name().call();
- expect(name).to.equal('oh River');
- });
-
- itEth('Returns symbol name', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const tokenPropertyPermissions = [{
- key: 'URI',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: false,
- },
- }];
- const collection = await helper.nft.mintCollection(
- alice,
- {
- name: 'oh River',
- tokenPrefix: 'CHANGE',
- properties: [{key: 'ERC721Metadata', value: '1'}],
- tokenPropertyPermissions,
- },
- );
-
- const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
- const symbol = await contract.methods.symbol().call();
- expect(symbol).to.equal('CHANGE');
- });
-});
-
-describe('Negative tests', () => {
- let donor: IKeyringPair;
- let minter: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itEth('[negative] Cant perform burn without approval', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft');
-
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
-
- await contract.methods.setApprovalForAll(spender, true).send({from: owner});
- await contract.methods.setApprovalForAll(spender, false).send({from: owner});
-
- await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
- });
-
- itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
- const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const receiver = alice;
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft');
-
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
-
- await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
-
- await contract.methods.setApprovalForAll(spender, true).send({from: owner});
- await contract.methods.setApprovalForAll(spender, false).send({from: owner});
-
- await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
- });
-});
js-packages/tests/src/eth/payable.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/payable.test.ts
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import {makeNames} from '../util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-describe('EVM payable contracts', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Evm contract can receive wei from eth account', async ({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const contract = await helper.eth.deployCollectorContract(deployer);
-
- const web3 = helper.getWeb3();
-
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', gas: helper.eth.DEFAULT_GAS});
-
- expect(await contract.methods.getCollected().call()).to.be.equal('10000');
- });
-
- itEth('Evm contract can receive wei from substrate account', async ({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const contract = await helper.eth.deployCollectorContract(deployer);
- const [alice] = await helper.arrange.createAccounts([40n], donor);
-
- const weiCount = '10000';
-
- // Transaction fee/value will be payed from subToEth(sender) evm balance,
- // which is backed by evmToAddress(subToEth(sender)) substrate balance
- await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address), 5n);
-
-
- await helper.eth.sendEVM(alice, contract.options.address, contract.methods.giveMoney().encodeABI(), weiCount);
-
- expect(await contract.methods.getCollected().call()).to.be.equal(weiCount);
- });
-
- // We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible
- itEth('Wei sent directly to backing storage of evm contract balance is unaccounted', async({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const contract = await helper.eth.deployCollectorContract(deployer);
- const [alice] = await helper.arrange.createAccounts([10n], donor);
-
- const weiCount = 10_000n;
-
- await helper.eth.transferBalanceFromSubstrate(alice, contract.options.address, weiCount, false);
-
- expect(await contract.methods.getUnaccounted().call()).to.be.equal(weiCount.toString());
- });
-
- itEth('Balance can be retrieved from evm contract', async({helper}) => {
- const FEE_BALANCE = 10n * helper.balance.getOneTokenNominal();
- const CONTRACT_BALANCE = 1n * helper.balance.getOneTokenNominal();
-
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const contract = await helper.eth.deployCollectorContract(deployer);
- const [alice] = await helper.arrange.createAccounts([20n], donor);
-
- const web3 = helper.getWeb3();
-
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
-
- const [receiver] = await helper.arrange.createAccounts([0n], donor);
-
- // First receive balance on eth balance of bob
- {
- const ethReceiver = helper.address.substrateToEth(receiver.address);
- expect(await web3.eth.getBalance(ethReceiver)).to.be.equal('0');
- await contract.methods.withdraw(ethReceiver).send({from: deployer});
- expect(await web3.eth.getBalance(ethReceiver)).to.be.equal(CONTRACT_BALANCE.toString());
- }
-
- // Some balance is required to pay fee for evm.withdraw call
- await helper.balance.transferToSubstrate(alice, receiver.address, FEE_BALANCE);
- // await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString());
-
- // Withdraw balance from eth to substrate
- {
- const initialReceiverBalance = await helper.balance.getSubstrate(receiver.address);
- await helper.executeExtrinsic(receiver, 'api.tx.evm.withdraw', [helper.address.substrateToEth(receiver.address), CONTRACT_BALANCE.toString()], true);
- const finalReceiverBalance = await helper.balance.getSubstrate(receiver.address);
-
- expect(finalReceiverBalance > initialReceiverBalance).to.be.true;
- }
- });
-});
-
-describe('EVM transaction fees', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Fee is withdrawn from the user', async({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const contract = await helper.eth.deployFlipper(deployer);
-
- const initialCallerBalance = await helper.balance.getEthereum(caller);
- await contract.methods.flip().send({from: caller});
- const finalCallerBalance = await helper.balance.getEthereum(caller);
- expect(finalCallerBalance < initialCallerBalance).to.be.true;
- });
-
- itEth('Fee for nested calls is withdrawn from the user', async({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const contract = await deployProxyContract(helper, deployer);
-
- const initialCallerBalance = await helper.balance.getEthereum(caller);
- const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
- await contract.methods.flip().send({from: caller});
- const finalCallerBalance = await helper.balance.getEthereum(caller);
- const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
- expect(finalCallerBalance < initialCallerBalance).to.be.true;
- expect(finalContractBalance == initialContractBalance).to.be.true;
- });
-
- itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {
- const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
-
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const contract = await deployProxyContract(helper, deployer);
-
- const collectionAddress = (await contract.methods.createNFTCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection;
- const initialCallerBalance = await helper.balance.getEthereum(caller);
- const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
- await contract.methods.mintNftToken(collectionAddress).send({from: caller});
- const finalCallerBalance = await helper.balance.getEthereum(caller);
- const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
- expect(finalCallerBalance < initialCallerBalance).to.be.true;
- expect(finalContractBalance == initialContractBalance).to.be.true;
- });
-
- itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {
- const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const contract = await deployProxyContract(helper, deployer);
-
- const initialCallerBalance = await helper.balance.getEthereum(caller);
- const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
- await contract.methods.createNFTCollection().send({from: caller, value: Number(CONTRACT_BALANCE)});
- const finalCallerBalance = await helper.balance.getEthereum(caller);
- const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
- expect(finalCallerBalance < initialCallerBalance).to.be.true;
- expect(finalContractBalance == initialContractBalance).to.be.true;
- });
-
- itEth('Negative test: call createNFTCollection with wrong fee', async({helper}) => {
- const SMALL_FEE = 1n * helper.balance.getOneTokenNominal();
- const BIG_FEE = 3n * helper.balance.getOneTokenNominal();
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(caller);
-
- await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
-
- itEth('Negative test: call createRFTCollection with wrong fee', async({helper}) => {
- const SMALL_FEE = 1n * helper.balance.getOneTokenNominal();
- const BIG_FEE = 3n * helper.balance.getOneTokenNominal();
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collectionHelper = await helper.ethNativeContract.collectionHelpers(caller);
-
- await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
- });
-
- itEth('Get collection creation fee', async({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- expect(await helper.eth.getCollectionCreationFee(deployer)).to.be.equal(String(2n * helper.balance.getOneTokenNominal()));
- });
-
- async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
- return await helper.ethContract.deployByCode(
- deployer,
- 'ProxyContract',
- `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- import {CollectionHelpers} from "../api/CollectionHelpers.sol";
- import {UniqueNFT} from "../api/UniqueNFT.sol";
-
- error Value(uint256 value);
-
- contract ProxyContract {
- bool value = false;
- address innerContract;
-
- event CollectionCreated(address collection);
- event TokenMinted(uint256 tokenId);
-
- receive() external payable {}
-
- constructor() {
- innerContract = address(new InnerContract());
- }
-
- function flip() public {
- value = !value;
- InnerContract(innerContract).flip();
- }
-
- function createNFTCollection() external payable {
- address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
- address nftCollection = CollectionHelpers(collectionHelpers).createNFTCollection{value: msg.value}("A", "B", "C");
- emit CollectionCreated(nftCollection);
- }
-
- function mintNftToken(address collectionAddress) external {
- UniqueNFT collection = UniqueNFT(collectionAddress);
- uint256 tokenId = collection.mint(msg.sender);
- emit TokenMinted(tokenId);
- }
-
- function getValue() external view returns (bool) {
- return InnerContract(innerContract).getValue();
- }
- }
-
- contract InnerContract {
- bool value = false;
- function flip() external {
- value = !value;
- }
- function getValue() external view returns (bool) {
- return value;
- }
- }
- `,
- [
- {
- solPath: 'api/CollectionHelpers.sol',
- fsPath: `${dirname}/api/CollectionHelpers.sol`,
- },
- {
- solPath: 'api/UniqueNFT.sol',
- fsPath: `${dirname}/api/UniqueNFT.sol`,
- },
- ],
- );
- }
-});
js-packages/tests/src/eth/precompile.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/precompile.test.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-
-describe('Precompiles', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('ecrecover is supported', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ecrecoverCompiledСontract = await helper.ethContract.compile(
- 'ECRECOVER',
- `
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.17;
-
- contract ECRECOVER{
- address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd;
- bytes32 msgHash1 = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50;
- bytes32 msgHash2 = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d51;
- uint8 v = 0x1b;
- bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef;
- bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4;
-
-
- function verifyValid() public view returns(bool) {
- // Use ECRECOVER to verify address
- return ecrecover(msgHash1, v, r, s) == (addressTest);
- }
-
- function verifyInvalid() public view returns(bool) {
- // Use ECRECOVER to verify address
- return ecrecover(msgHash2, v, r, s) == (addressTest);
- }
- }
- `,
- );
-
- const ecrecoverСontract = await helper.ethContract.deployByAbi(owner, ecrecoverCompiledСontract.abi, ecrecoverCompiledСontract.object);
- expect(await ecrecoverСontract.methods.verifyValid().call({from: owner})).to.be.true;
- expect(await ecrecoverСontract.methods.verifyInvalid().call({from: owner})).to.be.false;
- });
-
- itEth('sr25519 is supported', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const sr25519CompiledСontract = await helper.ethContract.compile(
- 'SR25519Contract',
- `
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.17;
-
- /**
- * @title SR25519 signature interface.
- */
- interface SR25519 {
- /**
- * @dev Verify signed message using SR25519 crypto.
- * @return A boolean confirming whether the public key is signer for the message.
- */
- function verify(
- bytes32 public_key,
- bytes calldata signature,
- bytes calldata message
- ) external view returns (bool);
- }
-
- contract SR25519Contract{
- SR25519 public constant sr25519 = SR25519(0x0000000000000000000000000000000000005002);
-
- bytes32 public_key = 0x96b2f9237ed0890fbeed891ebb81b91ac0d5d5b6e3afcdbc95df1b68d9f14036;
- bytes signature = hex"4a5d733d7c568f2e88abf0467fd497f87c1be3e940ed897efdf9da72eaad394ef9918cb574ee99c54485775b17a0deaf46ff7a1f10346cea39fff0e4ede97689";
- bytes message1 = hex"7372323535313920697320737570706f72746564";
- bytes message2 = hex"7372323535313920697320737570706f7274656401";
-
-
- function verifyValid() public view returns(bool) {
- return sr25519.verify(public_key, signature, message1);
- }
-
- function verifyInvalid() public view returns(bool) {
- return sr25519.verify(public_key, signature, message2);
- }
- }
- `,
- );
-
- const sr25519Сontract = await helper.ethContract.deployByAbi(owner, sr25519CompiledСontract.abi, sr25519CompiledСontract.object);
- expect(await sr25519Сontract.methods.verifyValid().call({from: owner})).to.be.true;
- expect(await sr25519Сontract.methods.verifyInvalid().call({from: owner})).to.be.false;
- });
-});
js-packages/tests/src/eth/proxy/UniqueFungibleProxy.abidiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/UniqueFungibleProxy.abi
+++ /dev/null
@@ -1 +0,0 @@
-[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"interfaceId","type":"uint32"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/tests/src/eth/proxy/UniqueFungibleProxy.bindiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/UniqueFungibleProxy.bin
+++ /dev/null
@@ -1 +0,0 @@
-608060405234801561001057600080fd5b5060405161098038038061098083398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b6108ed806100936000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806370a082311161006657806370a082311461012757806395d89b411461013a578063a9059cbb14610142578063dd62ed3e14610155578063f4f4b5001461016857600080fd5b806306fdde03146100a3578063095ea7b3146100c157806318160ddd146100e457806323b872dd146100fa578063313ce5671461010d575b600080fd5b6100ab61017b565b6040516100b8919061083e565b60405180910390f35b6100d46100cf3660046106e3565b610200565b60405190151581526020016100b8565b6100ec61028f565b6040519081526020016100b8565b6100d46101083660046106a7565b610316565b6101156103ad565b60405160ff90911681526020016100b8565b6100ec610135366004610659565b610434565b6100ab6104b8565b6100d46101503660046106e3565b6104fc565b6100ec610163366004610674565b610536565b6100d46101763660046107f5565b6105bc565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b1580156101bf57600080fd5b505afa1580156101d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101fb919081019061072f565b905090565b6000805460405163095ea7b360e01b81526001600160a01b038581166004830152602482018590529091169063095ea7b3906044015b602060405180830381600087803b15801561025057600080fd5b505af1158015610264573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610288919061070d565b9392505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156102de57600080fd5b505afa1580156102f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101fb91906107dc565b600080546040516323b872dd60e01b81526001600160a01b038681166004830152858116602483015260448201859052909116906323b872dd90606401602060405180830381600087803b15801561036d57600080fd5b505af1158015610381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a5919061070d565b949350505050565b60008060009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156103fc57600080fd5b505afa158015610410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101fb919061081b565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a082319060240160206040518083038186803b15801561047a57600080fd5b505afa15801561048e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b291906107dc565b92915050565b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b1580156101bf57600080fd5b6000805460405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529091169063a9059cbb90604401610236565b60008054604051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301529091169063dd62ed3e9060440160206040518083038186803b15801561058457600080fd5b505afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028891906107dc565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b15801561060557600080fd5b505afa158015610619573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b2919061070d565b80356001600160a01b038116811461065457600080fd5b919050565b60006020828403121561066b57600080fd5b6102888261063d565b6000806040838503121561068757600080fd5b6106908361063d565b915061069e6020840161063d565b90509250929050565b6000806000606084860312156106bc57600080fd5b6106c58461063d565b92506106d36020850161063d565b9150604084013590509250925092565b600080604083850312156106f657600080fd5b6106ff8361063d565b946020939093013593505050565b60006020828403121561071f57600080fd5b8151801515811461028857600080fd5b60006020828403121561074157600080fd5b815167ffffffffffffffff8082111561075957600080fd5b818401915084601f83011261076d57600080fd5b81518181111561077f5761077f6108a1565b604051601f8201601f19908116603f011681019083821181831017156107a7576107a76108a1565b816040528281528760208487010111156107c057600080fd5b6107d1836020830160208801610871565b979650505050505050565b6000602082840312156107ee57600080fd5b5051919050565b60006020828403121561080757600080fd5b813563ffffffff8116811461028857600080fd5b60006020828403121561082d57600080fd5b815160ff8116811461028857600080fd5b602081526000825180602084015261085d816040850160208701610871565b601f01601f19169190910160400192915050565b60005b8381101561088c578181015183820152602001610874565b8381111561089b576000848401525b50505050565b634e487b7160e01b600052604160045260246000fdfea2646970667358221220c05e4cb7ab439b86c0b6ac8a84eec6a230b592fa63d1ab2e3a7f1474c27338f364736f6c63430008070033
\ No newline at end of file
js-packages/tests/src/eth/proxy/UniqueFungibleProxy.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/UniqueFungibleProxy.sol
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: OTHER
-
-pragma solidity >=0.8.0 <0.9.0;
-
-import "../api/UniqueFungible.sol";
-
-contract UniqueFungibleProxy is UniqueFungible {
- UniqueFungible proxied;
-
- constructor(address _proxied) UniqueFungible() {
- proxied = UniqueFungible(_proxied);
- }
-
- function name() external view override returns (string memory) {
- return proxied.name();
- }
-
- function symbol() external view override returns (string memory) {
- return proxied.symbol();
- }
-
- function totalSupply() external view override returns (uint256) {
- return proxied.totalSupply();
- }
-
- function supportsInterface(uint32 interfaceId)
- external
- view
- override
- returns (bool)
- {
- return proxied.supportsInterface(interfaceId);
- }
-
- function decimals() external view override returns (uint8) {
- return proxied.decimals();
- }
-
- function balanceOf(address owner) external view override returns (uint256) {
- return proxied.balanceOf(owner);
- }
-
- function transfer(address to, uint256 amount)
- external
- override
- returns (bool)
- {
- return proxied.transfer(to, amount);
- }
-
- function transferFrom(
- address from,
- address to,
- uint256 amount
- ) external override returns (bool) {
- return proxied.transferFrom(from, to, amount);
- }
-
- function approve(address spender, uint256 amount)
- external
- override
- returns (bool)
- {
- return proxied.approve(spender, amount);
- }
-
- function allowance(address owner, address spender)
- external
- view
- override
- returns (uint256)
- {
- return proxied.allowance(owner, spender);
- }
-}
js-packages/tests/src/eth/proxy/UniqueNFTProxy.abidiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/UniqueNFTProxy.abi
+++ /dev/null
@@ -1 +0,0 @@
-[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"}],"name":"deleteProperty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"mintBulk","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256","name":"field_0","type":"uint256"},{"internalType":"string","name":"field_1","type":"string"}],"internalType":"struct Tuple0[]","name":"tokens","type":"tuple[]"}],"name":"mintBulkWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setProperty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
js-packages/tests/src/eth/proxy/UniqueNFTProxy.bindiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/UniqueNFTProxy.bin
+++ /dev/null
@@ -1 +0,0 @@
-608060405234801561001057600080fd5b506040516116bb3803806116bb83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b611628806100936000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80634f6ccce7116100f957806379cc679011610097578063a22cb46511610071578063a22cb46514610399578063a9059cbb146103ac578063c87b56dd146103bf578063e985e9c5146103d257600080fd5b806379cc6790146103765780637d64bcb41461038957806395d89b411461039157600080fd5b806362d9491f116100d357806362d9491f146103355780636352211e1461034857806370a082311461035b57806375794a3c1461036e57600080fd5b80634f6ccce7146102fc57806350bb4e7f1461030f57806360a116721461032257600080fd5b80632f745c591161016657806340c10f191161014057806340c10f19146102b057806342842e0e146102c357806342966c68146102d657806344a9945e146102e957600080fd5b80632f745c5914610277578063342419141461028a578063365430061461029d57600080fd5b8063081812fc116101a2578063081812fc1461020e578063095ea7b31461023957806318160ddd1461024e57806323b872dd1461026457600080fd5b806301ffc9a7146101c957806305d2035b146101f157806306fdde03146101f9575b600080fd5b6101dc6101d7366004610dca565b6103e5565b60405190151581526020015b60405180910390f35b6101dc610462565b6102016104df565b6040516101e89190610e4c565b61022161021c366004610e5f565b610550565b6040516001600160a01b0390911681526020016101e8565b61024c610247366004610e90565b6105bf565b005b61025661062a565b6040519081526020016101e8565b61024c610272366004610ebc565b6106a2565b610256610285366004610e90565b610716565b61024c610298366004610ff3565b610793565b6101dc6102ab36600461104c565b6107f8565b6101dc6102be366004610e90565b61086e565b61024c6102d1366004610ebc565b6108a8565b61024c6102e4366004610e5f565b6108e9565b6101dc6102f736600461114f565b61091a565b61025661030a366004610e5f565b61094d565b6101dc61031d3660046111f5565b6109bc565b61024c61033036600461124e565b610a3c565b61024c6103433660046112ce565b610aab565b610221610356366004610e5f565b610add565b610256610369366004611332565b610b0f565b610256610b42565b61024c610384366004610e90565b610b96565b6101dc610bcf565b610201610c25565b61024c6103a736600461135d565b610c6e565b61024c6103ba366004610e90565b610ca8565b6102016103cd366004610e5f565b610ce1565b6102216103e0366004611396565b610d53565b600080546040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b03909116906301ffc9a790602401602060405180830381865afa158015610438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c91906113c4565b92915050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da91906113c4565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde0392600480820193918290030181865afa158015610528573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104da91908101906113e1565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b602060405180830381865afa15801561059b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c9190611458565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b15801561060e57600080fd5b505af1158015610622573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da9190611475565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b1580156106f957600080fd5b505af115801561070d573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c5990604401602060405180830381865afa158015610768573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c9190611475565b9392505050565b600054604051630d09064560e21b81526001600160a01b03909116906334241914906107c3908490600401610e4c565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b5050505050565b60008054604051631b2a180360e11b81526001600160a01b039091169063365430069061082b908690869060040161148e565b6020604051808303816000875af115801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c91906113c4565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f199060440161082b565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e906064016106df565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c68906024016107c3565b60008054604051632254ca2f60e11b81526001600160a01b03909116906344a9945e9061082b9086908690600401611513565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c9190611475565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f906109f190879087908790600401611569565b6020604051808303816000875af1158015610a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3491906113c4565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a1167290610a72908790879087908790600401611590565b600060405180830381600087803b158015610a8c57600080fd5b505af1158015610aa0573d6000803e3d6000fd5b505050505b50505050565b6000546040516362d9491f60e01b81526001600160a01b03909116906362d9491f906105f490859085906004016115cd565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e9060240161057e565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a082319060240161097b565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b60005460405163079cc67960e41b81526001600160a01b03848116600483015260248201849052909116906379cc6790906044016105f4565b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b81526004016020604051808303816000875af11580156104b6573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b4192600480820193918290030181865afa158015610528573d6000803e3d6000fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb465906044016105f4565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016105f4565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610d2b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261045c91908101906113e1565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c590604401602060405180830381865afa158015610da6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c9190611458565b600060208284031215610ddc57600080fd5b81356001600160e01b03198116811461078c57600080fd5b60005b83811015610e0f578181015183820152602001610df7565b83811115610aa55750506000910152565b60008151808452610e38816020860160208601610df4565b601f01601f19169290920160200192915050565b60208152600061078c6020830184610e20565b600060208284031215610e7157600080fd5b5035919050565b6001600160a01b0381168114610e8d57600080fd5b50565b60008060408385031215610ea357600080fd5b8235610eae81610e78565b946020939093013593505050565b600080600060608486031215610ed157600080fd5b8335610edc81610e78565b92506020840135610eec81610e78565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610f3657610f36610efd565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610f6557610f65610efd565b604052919050565b600067ffffffffffffffff821115610f8757610f87610efd565b50601f01601f191660200190565b6000610fa8610fa384610f6d565b610f3c565b9050828152838383011115610fbc57600080fd5b828260208301376000602084830101529392505050565b600082601f830112610fe457600080fd5b61078c83833560208501610f95565b60006020828403121561100557600080fd5b813567ffffffffffffffff81111561101c57600080fd5b610a3484828501610fd3565b600067ffffffffffffffff82111561104257611042610efd565b5060051b60200190565b600080604080848603121561106057600080fd5b833561106b81610e78565b925060208481013567ffffffffffffffff8082111561108957600080fd5b818701915087601f83011261109d57600080fd5b81356110ab610fa382611028565b81815260059190911b8301840190848101908a8311156110ca57600080fd5b8585015b8381101561113d578035858111156110e65760008081fd5b8601808d03601f19018913156110fc5760008081fd5b611104610f13565b888201358152898201358781111561111c5760008081fd5b61112a8f8b83860101610fd3565b828b0152508452509186019186016110ce565b50809750505050505050509250929050565b6000806040838503121561116257600080fd5b823561116d81610e78565b915060208381013567ffffffffffffffff81111561118a57600080fd5b8401601f8101861361119b57600080fd5b80356111a9610fa382611028565b81815260059190911b820183019083810190888311156111c857600080fd5b928401925b828410156111e6578335825292840192908401906111cd565b80955050505050509250929050565b60008060006060848603121561120a57600080fd5b833561121581610e78565b925060208401359150604084013567ffffffffffffffff81111561123857600080fd5b61124486828701610fd3565b9150509250925092565b6000806000806080858703121561126457600080fd5b843561126f81610e78565b9350602085013561127f81610e78565b925060408501359150606085013567ffffffffffffffff8111156112a257600080fd5b8501601f810187136112b357600080fd5b6112c287823560208401610f95565b91505092959194509250565b600080604083850312156112e157600080fd5b823567ffffffffffffffff808211156112f957600080fd5b61130586838701610fd3565b9350602085013591508082111561131b57600080fd5b5061132885828601610fd3565b9150509250929050565b60006020828403121561134457600080fd5b813561078c81610e78565b8015158114610e8d57600080fd5b6000806040838503121561137057600080fd5b823561137b81610e78565b9150602083013561138b8161134f565b809150509250929050565b600080604083850312156113a957600080fd5b82356113b481610e78565b9150602083013561138b81610e78565b6000602082840312156113d657600080fd5b815161078c8161134f565b6000602082840312156113f357600080fd5b815167ffffffffffffffff81111561140a57600080fd5b8201601f8101841361141b57600080fd5b8051611429610fa382610f6d565b81815285602083850101111561143e57600080fd5b61144f826020830160208601610df4565b95945050505050565b60006020828403121561146a57600080fd5b815161078c81610e78565b60006020828403121561148757600080fd5b5051919050565b6001600160a01b0383168152604060208083018290528351828401819052600092916060600583901b860181019290860190878301865b8281101561150457888603605f190184528151805187528501518587018890526114f188880182610e20565b96505092840192908401906001016114c5565b50939998505050505050505050565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b8181101561155c57845183529383019391830191600101611540565b5090979650505050505050565b60018060a01b038416815282602082015260606040820152600061144f6060830184610e20565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906115c390830184610e20565b9695505050505050565b6040815260006115e06040830185610e20565b828103602084015261144f8185610e2056fea26469706673582212205bdf4275f4b714a1029ccfe77c0f9a0e20e121a932e1e5840cace97dfa886da964736f6c634300080d0033
\ No newline at end of file
js-packages/tests/src/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/UniqueNFTProxy.sol
+++ /dev/null
@@ -1,186 +0,0 @@
-// SPDX-License-Identifier: OTHER
-
-pragma solidity >=0.8.0 <0.9.0;
-
-import "../api/UniqueNFT.sol";
-
-contract UniqueNFTProxy is UniqueNFT {
- UniqueNFT proxied;
-
- constructor(address _proxied) UniqueNFT() {
- proxied = UniqueNFT(_proxied);
- }
-
- function name() external view override returns (string memory) {
- return proxied.name();
- }
-
- function symbol() external view override returns (string memory) {
- return proxied.symbol();
- }
-
- function totalSupply() external view override returns (uint256) {
- return proxied.totalSupply();
- }
-
- function balanceOf(address owner) external view override returns (uint256) {
- return proxied.balanceOf(owner);
- }
-
- function ownerOf(uint256 tokenId) external view override returns (address) {
- return proxied.ownerOf(tokenId);
- }
-
- function safeTransferFromWithData(
- address from,
- address to,
- uint256 tokenId,
- bytes memory data
- ) external override {
- return proxied.safeTransferFromWithData(from, to, tokenId, data);
- }
-
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external override {
- return proxied.safeTransferFrom(from, to, tokenId);
- }
-
- function transferFrom(
- address from,
- address to,
- uint256 tokenId
- ) external override {
- return proxied.transferFrom(from, to, tokenId);
- }
-
- function approve(address approved, uint256 tokenId) external override {
- return proxied.approve(approved, tokenId);
- }
-
- function setApprovalForAll(address operator, bool approved)
- external
- override
- {
- return proxied.setApprovalForAll(operator, approved);
- }
-
- function getApproved(uint256 tokenId)
- external
- view
- override
- returns (address)
- {
- return proxied.getApproved(tokenId);
- }
-
- function isApprovedForAll(address owner, address operator)
- external
- view
- override
- returns (address)
- {
- return proxied.isApprovedForAll(owner, operator);
- }
-
- function burn(uint256 tokenId) external override {
- return proxied.burn(tokenId);
- }
-
- function tokenByIndex(uint256 index)
- external
- view
- override
- returns (uint256)
- {
- return proxied.tokenByIndex(index);
- }
-
- function tokenOfOwnerByIndex(address owner, uint256 index)
- external
- view
- override
- returns (uint256)
- {
- return proxied.tokenOfOwnerByIndex(owner, index);
- }
-
- function tokenURI(uint256 tokenId)
- external
- view
- override
- returns (string memory)
- {
- return proxied.tokenURI(tokenId);
- }
-
- function mintingFinished() external view override returns (bool) {
- return proxied.mintingFinished();
- }
-
- function mint(address to)
- external
- override
- returns (uint256)
- {
- return proxied.mint(to);
- }
-
- function mintWithTokenURI(
- address to,
- string memory tokenUri
- ) external override returns (uint256) {
- return proxied.mintWithTokenURI(to, tokenUri);
- }
-
- function finishMinting() external override returns (bool) {
- return proxied.finishMinting();
- }
-
- function transfer(address to, uint256 tokenId) external override {
- return proxied.transfer(to, tokenId);
- }
-
- function nextTokenId() external view override returns (uint256) {
- return proxied.nextTokenId();
- }
-
- function burnFrom(address from, uint256 tokenId) external override {
- return proxied.burnFrom(from, tokenId);
- }
-
- function supportsInterface(bytes4 interfaceId)
- external
- view
- override
- returns (bool)
- {
- return proxied.supportsInterface(interfaceId);
- }
-
- function mintBulk(address to, uint256[] memory tokenIds)
- external
- override
- returns (bool)
- {
- return proxied.mintBulk(to, tokenIds);
- }
-
- function mintBulkWithTokenURI(address to, TokenUri[] memory tokens)
- external
- override
- returns (bool)
- {
- return proxied.mintBulkWithTokenURI(to, tokens);
- }
-
- function setProperty(string memory key, string memory value) external override {
- return proxied.setProperty(key, value);
- }
-
- function deleteProperty(string memory key) external override {
- return proxied.deleteProperty(key);
- }
-}
js-packages/tests/src/eth/proxy/fungibleProxy.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/fungibleProxy.test.ts
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect} from 'chai';
-import {readFile} from 'fs/promises';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
-import {makeNames} from '../../util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-async function proxyWrap(helper: EthUniqueHelper, wrapped: any, donor: IKeyringPair) {
- // Proxy owner has no special privilegies, we don't need to reuse them
- const owner = await helper.eth.createAccountWithBalance(donor);
- const web3 = helper.getWeb3();
- const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${dirname}/UniqueFungibleProxy.abi`)).toString()), undefined, {
- from: owner,
- gas: helper.eth.DEFAULT_GAS,
- });
- const proxy = await proxyContract.deploy({data: (await readFile(`${dirname}/UniqueFungibleProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});
- return proxy;
-}
-
-describe('Fungible (Via EVM proxy): Information getting', () => {
- let alice: IKeyringPair;
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itEth('totalSupply', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
- const caller = await helper.eth.createAccountWithBalance(donor);
- await collection.mint(alice, 200n, {Substrate: alice.address});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const totalSupply = await contract.methods.totalSupply().call();
-
- expect(totalSupply).to.equal('200');
- });
-
- itEth('balanceOf', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- await collection.mint(alice, 200n, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const balance = await contract.methods.balanceOf(caller).call();
-
- expect(balance).to.equal('200');
- });
-});
-
-describe('Fungible (Via EVM proxy): Plain calls', () => {
- let alice: IKeyringPair;
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itEth('Can perform approve()', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- await collection.mint(alice, 200n, {Ethereum: contract.options.address});
-
- {
- const result = await contract.methods.approve(spender, 100).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Approval',
- args: {
- owner: contract.options.address,
- spender,
- value: '100',
- },
- },
- ]);
- }
-
- {
- const allowance = await contract.methods.allowance(contract.options.address, spender).call();
- expect(+allowance).to.equal(100);
- }
- });
-
- itEth('Can perform transferFrom()', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- await collection.mint(alice, 200n, {Ethereum: owner});
- const receiver = helper.eth.createAccount();
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
-
- await evmCollection.methods.approve(contract.options.address, 100).send({from: owner});
-
- {
- const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Transfer',
- args: {
- from: owner,
- to: receiver,
- value: '49',
- },
- },
- {
- address,
- event: 'Approval',
- args: {
- owner,
- spender: contract.options.address,
- value: '51',
- },
- },
- ]);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(49);
- }
-
- {
- const balance = await contract.methods.balanceOf(owner).call();
- expect(+balance).to.equal(151);
- }
- });
-
- itEth('Can perform transfer()', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- await collection.mint(alice, 200n, {Ethereum: contract.options.address});
-
- {
- const result = await contract.methods.transfer(receiver, 50).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Transfer',
- args: {
- from: contract.options.address,
- to: receiver,
- value: '50',
- },
- },
- ]);
- }
-
- {
- const balance = await contract.methods.balanceOf(contract.options.address).call();
- expect(+balance).to.equal(150);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(50);
- }
- });
-});
js-packages/tests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ /dev/null
@@ -1,372 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {readFile} from 'fs/promises';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds, expect} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
-import {makeNames} from '../../util/index.js';
-
-const {dirname} = makeNames(import.meta.url);
-
-
-async function proxyWrap(helper: EthUniqueHelper, wrapped: any, donor: IKeyringPair) {
- // Proxy owner has no special privilegies, we don't need to reuse them
- const owner = await helper.eth.createAccountWithBalance(donor);
- const web3 = helper.getWeb3();
- const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${dirname}/UniqueNFTProxy.abi`)).toString()), undefined, {
- from: owner,
- gas: helper.eth.DEFAULT_GAS,
- });
- const proxy = await proxyContract.deploy({data: (await readFile(`${dirname}/UniqueNFTProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});
- return proxy;
-}
-
-describe('NFT (Via EVM proxy): Information getting', () => {
- let alice: IKeyringPair;
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itEth('totalSupply', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const caller = await helper.eth.createAccountWithBalance(donor);
- await collection.mintToken(alice, {Substrate: alice.address});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const totalSupply = await contract.methods.totalSupply().call();
-
- expect(totalSupply).to.equal('1');
- });
-
- itEth('balanceOf', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const caller = await helper.eth.createAccountWithBalance(donor);
- await collection.mintMultipleTokens(alice, [
- {owner: {Ethereum: caller}},
- {owner: {Ethereum: caller}},
- {owner: {Ethereum: caller}},
- ]);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const balance = await contract.methods.balanceOf(caller).call();
-
- expect(balance).to.equal('3');
- });
-
- itEth('ownerOf', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const caller = await helper.eth.createAccountWithBalance(donor);
- const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const owner = await contract.methods.ownerOf(tokenId).call();
-
- expect(owner).to.equal(caller);
- });
-});
-
-describe('NFT (Via EVM proxy): Plain calls', () => {
- let alice: IKeyringPair;
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- // Soft-deprecated
- itEth('[eth] Can perform mint()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'A', 'A', '');
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const collectionEvmOwned = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller, true);
- const contract = await proxyWrap(helper, collectionEvm, donor);
- await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send();
-
- {
- const nextTokenId = await contract.methods.nextTokenId().call();
- const result = await contract.methods.mintWithTokenURI(receiver, nextTokenId, 'Test URI').send({from: caller});
- const tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
-
- const event = helper.eth.normalizeEvents(result.events)
- .find(event => event.event === 'Transfer')!;
- event.address = event.address.toLocaleLowerCase();
-
- expect(event).to.be.deep.equal({
- address: collectionAddress.toLocaleLowerCase(),
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: receiver,
- tokenId,
- },
- });
-
- expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
- }
- });
-
- itEth('[cross] Can perform mint()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'A', 'A', '');
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const collectionEvmOwned = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
- const contract = await proxyWrap(helper, collectionEvm, donor);
- const contractAddressCross = helper.ethCrossAccount.fromAddress(contract.options.address);
- await collectionEvmOwned.methods.addCollectionAdminCross(contractAddressCross).send();
-
- {
- const nextTokenId = await contract.methods.nextTokenId().call();
- const result = await contract.methods.mintWithTokenURI(receiver, nextTokenId, 'Test URI').send({from: caller});
- const tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
-
- const event = helper.eth.normalizeEvents(result.events)
- .find(event => event.event === 'Transfer')!;
- event.address = event.address.toLocaleLowerCase();
-
- expect(event).to.be.deep.equal({
- address: collectionAddress.toLocaleLowerCase(),
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: receiver,
- tokenId,
- },
- });
-
- expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
- }
- });
-
- //TODO: CORE-302 add eth methods
- itEth.skip('Can perform mintBulk()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(donor, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
-
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- await collection.addAdmin(donor, {Ethereum: contract.options.address});
-
- {
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const result = await contract.methods.mintBulkWithTokenURI(
- receiver,
- [
- [nextTokenId, 'Test URI 0'],
- [+nextTokenId + 1, 'Test URI 1'],
- [+nextTokenId + 2, 'Test URI 2'],
- ],
- ).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: receiver,
- tokenId: nextTokenId,
- },
- },
- {
- address,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: receiver,
- tokenId: String(+nextTokenId + 1),
- },
- },
- {
- address,
- event: 'Transfer',
- args: {
- from: '0x0000000000000000000000000000000000000000',
- to: receiver,
- tokenId: String(+nextTokenId + 2),
- },
- },
- ]);
-
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
- expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
- expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
- }
- });
-
- itEth('Can perform burn()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
- await collection.addAdmin(alice, {Ethereum: contract.options.address});
-
- {
- const result = await contract.methods.burn(tokenId).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Transfer',
- args: {
- from: contract.options.address,
- to: '0x0000000000000000000000000000000000000000',
- tokenId: tokenId.toString(),
- },
- },
- ]);
- }
- });
-
- itEth('Can perform approve()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const caller = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
-
- {
- const result = await contract.methods.approve(spender, tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS});
- const events = helper.eth.normalizeEvents(result.events);
-
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Approval',
- args: {
- owner: contract.options.address,
- approved: spender,
- tokenId: tokenId.toString(),
- },
- },
- ]);
- }
- });
-
- itEth('Can perform transferFrom()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const caller = await helper.eth.createAccountWithBalance(donor);
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const receiver = helper.eth.createAccount();
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
-
- await evmCollection.methods.approve(contract.options.address, tokenId).send({from: owner});
-
- {
- const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Transfer',
- args: {
- from: owner,
- to: receiver,
- tokenId: tokenId.toString(),
- },
- },
- ]);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(1);
- }
-
- {
- const balance = await contract.methods.balanceOf(contract.options.address).call();
- expect(+balance).to.equal(0);
- }
- });
-
- itEth('Can perform transfer()', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller);
- const contract = await proxyWrap(helper, evmCollection, donor);
- const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
-
- {
- const result = await contract.methods.transfer(receiver, tokenId).send({from: caller});
- const events = helper.eth.normalizeEvents(result.events);
- expect(events).to.be.deep.equal([
- {
- address,
- event: 'Transfer',
- args: {
- from: contract.options.address,
- to: receiver,
- tokenId: tokenId.toString(),
- },
- },
- ]);
- }
-
- {
- const balance = await contract.methods.balanceOf(contract.options.address).call();
- expect(+balance).to.equal(0);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(1);
- }
- });
-});
js-packages/tests/src/eth/proxyContract.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/proxyContract.test.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-
-describe('EVM payable contracts', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Update proxy contract', async({helper}) => {
- const deployer = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
- const proxyContract = await deployProxyContract(helper, deployer);
-
- const realContractV1 = await deployRealContractV1(helper, deployer);
- const realContractV1proxy = new helper.web3!.eth.Contract(realContractV1.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS});
- await proxyContract.methods.updateVersion(realContractV1.options.address).send();
-
- await realContractV1proxy.methods.flip().send();
- await realContractV1proxy.methods.flip().send();
- await realContractV1proxy.methods.flip().send();
- const value1 = await realContractV1proxy.methods.getValue().call();
- const flipCount1 = await realContractV1proxy.methods.getFlipCount().call();
- expect(flipCount1).to.be.equal('3');
- expect(value1).to.be.equal(true);
-
- const realContractV2 = await deployRealContractV2(helper, deployer);
- const realContractV2proxy = new helper.web3!.eth.Contract(realContractV2.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS});
- await proxyContract.methods.updateVersion(realContractV2.options.address).send();
-
- await realContractV2proxy.methods.flip().send();
- await realContractV2proxy.methods.flip().send();
- await realContractV2proxy.methods.setStep(5).send();
- await realContractV2proxy.methods.increaseFlipCount().send();
- const value2 = await realContractV2proxy.methods.getValue().call();
- const flipCount2 = await realContractV2proxy.methods.getFlipCount().call();
- expect(value2).to.be.equal(true);
- expect(flipCount2).to.be.equal('6');
- });
-
- async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
- return await helper.ethContract.deployByCode(deployer, 'ProxyContract', `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- contract ProxyContract {
- event NewEvent(uint data);
- receive() external payable {}
- bytes32 private constant implementationSlot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1);
- constructor() {}
- function updateVersion(address newContractAddress) external {
- bytes32 slot = implementationSlot;
- assembly {
- sstore(slot, newContractAddress)
- }
- }
- fallback() external {
- bytes32 slot = implementationSlot;
- assembly {
- let ptr := mload(0x40)
- let contractAddress := sload(slot)
-
- calldatacopy(ptr, 0, calldatasize())
-
- let result := delegatecall(gas(), contractAddress, ptr, calldatasize(), 0, 0)
- let size := returndatasize()
-
- returndatacopy(ptr, 0, size)
-
- switch result
- case 0 { revert(ptr, size) }
- default { return(ptr, size) }
- }
- }
- }
-
- interface RealContract {
- function flip() external;
- function getValue() external view returns (bool);
- function getFlipCount() external view returns (uint);
- }`);
- }
-
- async function deployRealContractV1(helper: EthUniqueHelper, deployer: string) {
- return await helper.ethContract.deployByCode(deployer, 'RealContractV1', `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- contract RealContractV1 {
- bool value = false;
- uint flipCount = 0;
- function flip() external {
- value = !value;
- flipCount++;
- }
- function getValue() external view returns (bool) {
- return value;
- }
- function getFlipCount() external view returns (uint) {
- return flipCount;
- }
- }`);
- }
-
- async function deployRealContractV2(helper: EthUniqueHelper, deployer: string) {
- return await helper.ethContract.deployByCode(deployer, 'RealContractV2', `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- contract RealContractV2 {
- bool value = false;
- uint flipCount = 10;
- uint step = 1;
- function flip() external {
- value = !value;
- flipCount--;
- }
- function setStep(uint value) external {
- step = value;
- }
- function increaseFlipCount() external {
- flipCount = flipCount + step;
- }
- function getValue() external view returns (bool) {
- return value;
- }
- function getFlipCount() external view returns (uint) {
- return flipCount;
- }
- }`);
- }
-});
js-packages/tests/src/eth/reFungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/reFungible.test.ts
+++ /dev/null
@@ -1,1019 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import type {ITokenPropertyPermission} from '@unique/playgrounds/src/types.js';
-import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from './util/playgrounds/types.js';
-
-describe('Refungible: Plain calls', () => {
- let donor: IKeyringPair;
- let minter: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- [
- 'substrate' as const,
- 'ethereum' as const,
- ].map(testCase => {
- itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
- const collectionAdmin = await helper.eth.createAccountWithBalance(donor);
-
- const receiverEth = helper.eth.createAccount();
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const receiverSub = bob;
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
-
- const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
- const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {
- tokenOwner: false,
- collectionAdmin: true,
- mutable: false}}));
-
-
- const collection = await helper.rft.mintCollection(minter, {
- tokenPrefix: 'ethp',
- tokenPropertyPermissions: permissions,
- });
- await collection.addAdmin(minter, {Ethereum: collectionAdmin});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', collectionAdmin, true);
- let expectedTokenId = await contract.methods.nextTokenId().call();
- let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();
- let tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal(expectedTokenId);
-
- let event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
-
- expectedTokenId = await contract.methods.nextTokenId().call();
- result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();
- event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
-
- tokenId = result.events.Transfer.returnValues.tokenId;
-
- expect(tokenId).to.be.equal(expectedTokenId);
-
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
- .map(p => helper.ethProperty.property(p.key, p.value.toString())));
-
- expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))
- .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});
- });
- });
-
- itEth.skip('Can perform mintBulk()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'MintBulky', '6', '6', '');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- {
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const result = await contract.methods.mintBulkWithTokenURI(
- receiver,
- [
- [nextTokenId, 'Test URI 0'],
- [+nextTokenId + 1, 'Test URI 1'],
- [+nextTokenId + 2, 'Test URI 2'],
- ],
- ).send();
-
- const events = result.events.Transfer;
- for(let i = 0; i < 2; i++) {
- const event = events[i];
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(String(+nextTokenId + i));
- }
-
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
- expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
- expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
- }
- });
-
- itEth('Can perform mintBulkCross() with multiple tokens', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const receiver = helper.eth.createAccount();
- const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
-
- const permissions = [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.TokenOwner, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true},
- ];
- const {collectionAddress} = await helper.eth.createCollection(
- caller,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'rft',
- adminList: [callerCross],
- tokenPropertyPermissions: [
- {key: 'key_0_0', permissions},
- {key: 'key_1_0', permissions},
- {key: 'key_1_1', permissions},
- {key: 'key_2_0', permissions},
- {key: 'key_2_1', permissions},
- {key: 'key_2_2', permissions},
- ],
- },
- ).send();
-
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const result = await contract.methods.mintBulkCross([
- {
- owners: [{
- owner: receiverCross,
- pieces: 1,
- }],
- properties: [
- {key: 'key_0_0', value: Buffer.from('value_0_0')},
- ],
- },
- {
- owners: [{
- owner: receiverCross,
- pieces: 2,
- }],
- properties: [
- {key: 'key_1_0', value: Buffer.from('value_1_0')},
- {key: 'key_1_1', value: Buffer.from('value_1_1')},
- ],
- },
- {
- owners: [{
- owner: receiverCross,
- pieces: 1,
- }],
- properties: [
- {key: 'key_2_0', value: Buffer.from('value_2_0')},
- {key: 'key_2_1', value: Buffer.from('value_2_1')},
- {key: 'key_2_2', value: Buffer.from('value_2_2')},
- ],
- },
- ]).send({from: caller});
- const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);
- const bulkSize = 3;
- for(let i = 0; i < bulkSize; i++) {
- const event = events[i];
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);
- }
-
- const properties = [
- await contract.methods.properties(+nextTokenId, []).call(),
- await contract.methods.properties(+nextTokenId + 1, []).call(),
- await contract.methods.properties(+nextTokenId + 2, []).call(),
- ];
- expect(properties).to.be.deep.equal([
- [
- ['key_0_0', helper.getWeb3().utils.toHex('value_0_0')],
- ],
- [
- ['key_1_0', helper.getWeb3().utils.toHex('value_1_0')],
- ['key_1_1', helper.getWeb3().utils.toHex('value_1_1')],
- ],
- [
- ['key_2_0', helper.getWeb3().utils.toHex('value_2_0')],
- ['key_2_1', helper.getWeb3().utils.toHex('value_2_1')],
- ['key_2_2', helper.getWeb3().utils.toHex('value_2_2')],
- ],
- ]);
- });
-
- itEth('Can perform mintBulkCross() with multiple owners', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const receiver = helper.eth.createAccount();
- const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
- const receiver2 = helper.eth.createAccount();
- const receiver2Cross = helper.ethCrossAccount.fromAddress(receiver2);
-
- const permissions = [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.TokenOwner, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true},
- ];
- const {collectionAddress} = await helper.eth.createCollection(
- caller,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'rft',
- adminList: [callerCross],
- tokenPropertyPermissions: [
- {key: 'key_2_0', permissions},
- {key: 'key_2_1', permissions},
- {key: 'key_2_2', permissions},
- ],
- },
- ).send();
-
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const result = await contract.methods.mintBulkCross([{
- owners: [
- {
- owner: receiverCross,
- pieces: 1,
- },
- {
- owner: receiver2Cross,
- pieces: 2,
- },
- ],
- properties: [
- {key: 'key_2_0', value: Buffer.from('value_2_0')},
- {key: 'key_2_1', value: Buffer.from('value_2_1')},
- {key: 'key_2_2', value: Buffer.from('value_2_2')},
- ],
- }]).send({from: caller});
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
- expect(event.returnValues.tokenId).to.equal(`${+nextTokenId}`);
-
- const properties = [
- await contract.methods.properties(+nextTokenId, []).call(),
- ];
- expect(properties).to.be.deep.equal([[
- ['key_2_0', helper.getWeb3().utils.toHex('value_2_0')],
- ['key_2_1', helper.getWeb3().utils.toHex('value_2_1')],
- ['key_2_2', helper.getWeb3().utils.toHex('value_2_2')],
- ]]);
- });
-
- itEth('Can perform setApprovalForAll()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = helper.eth.createAccount();
-
- const collection = await helper.rft.mintCollection(minter, {});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
- expect(approvedBefore).to.be.equal(false);
-
- {
- const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
-
- expect(result.events.ApprovalForAll).to.be.like({
- address: collectionAddress,
- event: 'ApprovalForAll',
- returnValues: {
- owner,
- operator,
- approved: true,
- },
- });
-
- const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
- expect(approvedAfter).to.be.equal(true);
- }
-
- {
- const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
-
- expect(result.events.ApprovalForAll).to.be.like({
- address: collectionAddress,
- event: 'ApprovalForAll',
- returnValues: {
- owner,
- operator,
- approved: false,
- },
- });
-
- const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
- expect(approvedAfter).to.be.equal(false);
- }
- });
-
- itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- {
- await contract.methods.setApprovalForAll(operator, true).send({from: owner});
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
- const events = result.events.Transfer;
-
- expect(events).to.be.like({
- address,
- event: 'Transfer',
- returnValues: {
- from: owner,
- to: '0x0000000000000000000000000000000000000000',
- tokenId: token.tokenId.toString(),
- },
- });
- }
- });
-
- itEth('Can perform burn with approve and approvalForAll', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner, true);
-
- {
- await rftToken.methods.approve(operator, 15n).send({from: owner});
- await contract.methods.setApprovalForAll(operator, true).send({from: owner});
- await rftToken.methods.burnFrom(owner, 10n).send({from: operator});
- }
- {
- const allowance = await rftToken.methods.allowance(owner, operator).call();
- expect(+allowance).to.be.equal(5);
- }
- {
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const operatorCross = helper.ethCrossAccount.fromAddress(operator);
- const allowance = await rftToken.methods.allowanceCross(ownerCross, operatorCross).call();
- expect(+allowance).to.equal(5);
- }
- });
-
- itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const operator = await helper.eth.createAccountWithBalance(donor);
- const receiver = charlie;
-
- const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- {
- await contract.methods.setApprovalForAll(operator, true).send({from: owner});
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
- const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: owner,
- to: helper.address.substrateToEth(receiver.address),
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);
- });
-
- itEth('Can perform burn()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- {
- const result = await contract.methods.burn(tokenId).send();
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal(caller);
- expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.tokenId).to.equal(tokenId.toString());
- }
- });
-
- itEth('Can perform transferFrom()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
-
- const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller);
- await tokenContract.methods.repartition(15).send();
-
- {
- const tokenEvents: any = [];
- tokenContract.events.allEvents((_: any, event: any) => {
- tokenEvents.push(event);
- });
- const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
- if(tokenEvents.length == 0) await helper.wait.newBlocks(1);
-
- let event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal(caller);
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(tokenId.toString());
-
- event = tokenEvents[0];
- expect(event.address).to.equal(tokenAddress);
- expect(event.returnValues.from).to.equal(caller);
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.value).to.equal('15');
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(1);
- }
-
- {
- const balance = await contract.methods.balanceOf(caller).call();
- expect(+balance).to.equal(0);
- }
- });
-
- // Soft-deprecated
- itEth('Can perform burnFrom()', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft', spender, true);
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
- const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
- await tokenContract.methods.repartition(15).send();
- await tokenContract.methods.approve(spender, 15).send();
-
- {
- const result = await contract.methods.burnFrom(owner, token.tokenId).send();
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: owner,
- to: '0x0000000000000000000000000000000000000000',
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await collection.getTokenBalance(token.tokenId, {Ethereum: owner})).to.be.eq(0n);
- });
-
- itEth('Can perform burnFromCross()', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = bob;
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, 100n, {Substrate: owner.address});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- await token.repartition(owner, 15n);
- await token.approve(owner, {Ethereum: spender}, 15n);
-
- {
- const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
- const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: '0x0000000000000000000000000000000000000000',
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await collection.getTokenBalance(token.tokenId, {Substrate: owner.address})).to.be.eq(0n);
- });
-
- itEth('Can perform transferFromCross()', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = bob;
- const spender = await helper.eth.createAccountWithBalance(donor);
- const receiver = charlie;
-
- const token = await collection.mintToken(minter, 100n, {Substrate: owner.address});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- await token.repartition(owner, 15n);
- await token.approve(owner, {Ethereum: spender}, 15n);
-
- {
- const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
- const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});
- const event = result.events.Transfer;
- expect(event).to.be.like({
- address: helper.ethAddress.fromCollectionId(collection.collectionId),
- event: 'Transfer',
- returnValues: {
- from: helper.address.substrateToEth(owner.address),
- to: helper.address.substrateToEth(receiver.address),
- tokenId: token.tokenId.toString(),
- },
- });
- }
-
- expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);
- });
-
- itEth('Can perform transfer()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- {
- const result = await contract.methods.transfer(receiver, tokenId).send();
-
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal(caller);
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(tokenId.toString());
- }
-
- {
- const balance = await contract.methods.balanceOf(caller).call();
- expect(+balance).to.equal(0);
- }
-
- {
- const balance = await contract.methods.balanceOf(receiver).call();
- expect(+balance).to.equal(1);
- }
- });
-
- itEth('Can perform transferCross()', async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
- const receiverEth = await helper.eth.createAccountWithBalance(donor);
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
-
- const collection = await helper.rft.mintCollection(minter, {});
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
-
- const token = await collection.mintToken(minter, 50n, {Ethereum: sender});
-
- {
- // Can transferCross to ethereum address:
- const result = await collectionEvm.methods.transferCross(receiverCrossEth, token.tokenId).send({from: sender});
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal(sender);
- expect(event.returnValues.to).to.equal(receiverEth);
- expect(event.returnValues.tokenId).to.equal(token.tokenId.toString());
- // Sender's balance decreased:
- const senderBalance = await collectionEvm.methods.balanceOf(sender).call();
- expect(+senderBalance).to.equal(0);
- expect(await token.getBalance({Ethereum: sender})).to.eq(0n);
- // Receiver's balance increased:
- const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
- expect(+receiverBalance).to.equal(1);
- expect(await token.getBalance({Ethereum: receiverEth})).to.eq(50n);
- }
-
- {
- // Can transferCross to substrate address:
- const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, token.tokenId).send({from: receiverEth});
- // Check events:
- const event = substrateResult.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal(receiverEth);
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
- expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
- // Sender's balance decreased:
- const senderBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
- expect(+senderBalance).to.equal(0);
- expect(await token.getBalance({Ethereum: receiverEth})).to.eq(0n);
- // Receiver's balance increased:
- const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
- expect(receiverBalance).to.contain(token.tokenId);
- expect(await token.getBalance({Substrate: minter.address})).to.eq(50n);
- }
- });
-
- ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {
- const sender = await helper.eth.createAccountWithBalance(donor);
- const tokenOwner = await helper.eth.createAccountWithBalance(donor);
- const receiverSub = minter;
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
-
- const collection = await helper.rft.mintCollection(minter, {});
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
-
- await collection.mintToken(minter, 50n, {Ethereum: sender});
- const nonSendersToken = await collection.mintToken(minter, 50n, {Ethereum: tokenOwner});
-
- // Cannot transferCross someone else's token:
- const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;
- await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;
- // Cannot transfer token if it does not exist:
- await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;
- }));
-
- itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
-
- await tokenContract.methods.repartition(2).send();
- await tokenContract.methods.transfer(receiver, 1).send();
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await tokenContract.methods.transfer(receiver, 1).send();
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
- expect(event.returnValues.to).to.equal(receiver);
- expect(event.returnValues.tokenId).to.equal(tokenId.toString());
- });
-
- itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
-
- await tokenContract.methods.repartition(2).send();
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- await tokenContract.methods.transfer(receiver, 1).send();
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal(caller);
- expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
- expect(event.returnValues.tokenId).to.equal(tokenId.toString());
- });
-
- itEth('Check balanceOfCross()', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {});
- const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
-
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
-
- for(let i = 1n; i < 10n; i++) {
- await collection.mintToken(minter, 100n, {Ethereum: owner.eth});
- expect(await collectionEvm.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq(i.toString());
- }
- });
-
- itEth('Check ownerOfCross()', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {});
- let owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner.eth);
- const {tokenId} = await collection.mintToken(minter, 100n,{Ethereum: owner.eth});
-
- for(let i = 1n; i < 10n; i++) {
- const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth});
- expect(ownerCross.eth).to.be.eq(owner.eth);
- expect(ownerCross.sub).to.be.eq(owner.sub);
-
- const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- await collectionEvm.methods.transferCross(newOwner, tokenId).send({from: owner.eth});
- owner = newOwner;
- }
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner.eth, true);
- const newOwner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- await tokenContract.methods.transferCross(newOwner, 50).send({from: owner.eth});
- const ownerCross = await collectionEvm.methods.ownerOfCross(tokenId).call({from: owner.eth});
- expect(ownerCross.eth.toUpperCase()).to.be.eq('0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
- expect(ownerCross.sub).to.be.eq('0');
- });
-});
-
-describe('RFT: Fees', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- expect(cost > 0n);
- });
-
- itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- expect(cost > 0n);
- });
-});
-
-describe('Common metadata', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([1000n], donor);
- });
- });
-
- itEth('Returns collection name', async ({helper}) => {
- const caller = helper.eth.createAccount();
- const tokenPropertyPermissions = [{
- key: 'URI',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: false,
- },
- }];
- const collection = await helper.rft.mintCollection(
- alice,
- {
- name: 'Leviathan',
- tokenPrefix: '11',
- properties: [{key: 'ERC721Metadata', value: '1'}],
- tokenPropertyPermissions,
- },
- );
-
- const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
- const name = await contract.methods.name().call();
- expect(name).to.equal('Leviathan');
- });
-
- itEth('Returns symbol name', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const tokenPropertyPermissions = [{
- key: 'URI',
- permission: {
- mutable: true,
- collectionAdmin: true,
- tokenOwner: false,
- },
- }];
- const {collectionId} = await helper.rft.mintCollection(
- alice,
- {
- name: 'Leviathan',
- tokenPrefix: '12',
- properties: [{key: 'ERC721Metadata', value: '1'}],
- tokenPropertyPermissions,
- },
- );
-
- const contract = await helper.ethNativeContract.collectionById(collectionId, 'rft', caller);
- const symbol = await contract.methods.symbol().call();
- expect(symbol).to.equal('12');
- });
-});
-
-describe('Negative tests', () => {
- let donor: IKeyringPair;
- let minter: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itEth('[negative] Cant perform burn without approval', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
-
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
-
- await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
-
- await contract.methods.setApprovalForAll(spender, true).send({from: owner});
- await contract.methods.setApprovalForAll(spender, false).send({from: owner});
-
- await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
- });
-
- itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
- const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = alice;
-
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'rft');
-
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
-
- await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
-
- await contract.methods.setApprovalForAll(spender, true).send({from: owner});
- await contract.methods.setApprovalForAll(spender, false).send({from: owner});
-
- await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
- });
-
- itEth('[negative] Can perform mintBulkCross() with multiple owners and multiple tokens', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const callerCross = helper.ethCrossAccount.fromAddress(caller);
- const receiver = helper.eth.createAccount();
- const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
- const receiver2 = helper.eth.createAccount();
- const receiver2Cross = helper.ethCrossAccount.fromAddress(receiver2);
-
- const permissions = [
- {code: TokenPermissionField.Mutable, value: true},
- {code: TokenPermissionField.TokenOwner, value: true},
- {code: TokenPermissionField.CollectionAdmin, value: true},
- ];
- const {collectionAddress} = await helper.eth.createCollection(
- caller,
- {
- ...CREATE_COLLECTION_DATA_DEFAULTS,
- name: 'A',
- description: 'B',
- tokenPrefix: 'C',
- collectionMode: 'rft',
- adminList: [callerCross],
- tokenPropertyPermissions: [
- {key: 'key_0_0', permissions},
- {key: 'key_2_0', permissions},
- {key: 'key_2_1', permissions},
- {key: 'key_2_2', permissions},
- ],
- },
- ).send();
-
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- const createData = [
- {
- owners: [{
- owner: receiverCross,
- pieces: 1,
- }],
- properties: [
- {key: 'key_0_0', value: Buffer.from('value_0_0')},
- ],
- },
- {
- owners: [
- {
- owner: receiverCross,
- pieces: 1,
- },
- {
- owner: receiver2Cross,
- pieces: 2,
- },
- ],
- properties: [
- {key: 'key_2_0', value: Buffer.from('value_2_0')},
- {key: 'key_2_1', value: Buffer.from('value_2_1')},
- {key: 'key_2_2', value: Buffer.from('value_2_2')},
- ],
- },
- ];
-
- await expect(contract.methods.mintBulkCross(createData).call({from: caller})).to.be.rejectedWith('creation of multiple tokens supported only if they have single owner each');
- });
-});
js-packages/tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/reFungibleToken.test.ts
+++ /dev/null
@@ -1,677 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Contract} from 'web3-eth-contract';
-
-// FIXME: Need erc721 for ReFubgible.
-describe('Check ERC721 token URI for ReFungible', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- async function setup(helper: EthUniqueHelper, baseUri: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- const result = await contract.methods.mint(receiver).send();
-
- const event = result.events.Transfer;
- const tokenId = event.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(receiver);
-
- if(propertyKey && propertyValue) {
- // Set URL or suffix
-
- await contract.methods.setProperties(tokenId, [{key: propertyKey, value: Buffer.from(propertyValue)}]).send();
- }
-
- return {contract, nextTokenId: tokenId};
- }
-
- itEth('Empty tokenURI', async ({helper}) => {
- const {contract, nextTokenId} = await setup(helper, '');
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
- });
-
- itEth('TokenURI from url', async ({helper}) => {
- const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URI', 'Token URI');
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
- });
-
- itEth('TokenURI from baseURI', async ({helper}) => {
- const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_');
- });
-
- itEth('TokenURI from baseURI + suffix', async ({helper}) => {
- const suffix = '/some/suffix';
- const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URISuffix', suffix);
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
- });
-});
-
-describe('Refungible: Plain calls', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([50n], donor);
- });
- });
-
- itEth('Can perform approve()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- {
- const result = await contract.methods.approve(spender, 100).send({from: owner});
- const event = result.events.Approval;
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(spender);
- expect(event.returnValues.value).to.be.equal('100');
- }
-
- {
- const allowance = await contract.methods.allowance(owner, spender).call();
- expect(+allowance).to.equal(100);
- }
- });
-
- itEth('Can perform approveCross()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0];
- const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);
- const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub);
-
-
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- {
- const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});
- const event = result.events.Approval;
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(spender);
- expect(event.returnValues.value).to.be.equal('100');
- }
-
- {
- const allowance = await contract.methods.allowance(owner, spender).call();
- expect(+allowance).to.equal(100);
- }
-
-
- {
- const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner});
- const event = result.events.Approval;
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.owner).to.be.equal(owner);
- expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address));
- expect(event.returnValues.value).to.be.equal('100');
- }
-
- {
- const allowance = await collection.getTokenApprovedPieces(tokenId, {Ethereum: owner}, {Substrate: spenderSub.address});
- expect(allowance).to.equal(100n);
- }
-
- {
- //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call()
- }
- });
-
- itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {
- const nonOwner = await helper.eth.createAccountWithBalance(donor);
- const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});
- const token = await collection.mintToken(alice, 100n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
- const tokenEvm = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- await expect(tokenEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');
- });
-
- [
- 'transferFrom',
- 'transferFromCross',
- ].map(testCase =>
- itEth(`Can perform ${testCase}`, async ({helper}) => {
- const isCross = testCase === 'transferFromCross';
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const spender = await helper.eth.createAccountWithBalance(donor);
- const receiverEth = helper.eth.createAccount();
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const [receiverSub] = await helper.arrange.createAccounts([1n], donor);
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
-
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- await contract.methods.approve(spender, 100).send({from: owner});
-
- // 1. Can transfer from
- // 1.1 Plain ethereum or cross address:
- {
- const result = await contract.methods[testCase](
- isCross ? ownerCross : owner,
- isCross ? receiverCrossEth : receiverEth,
- 49,
- ).send({from: spender});
-
- // Check events:
- const transferEvent = result.events.Transfer;
- expect(transferEvent.address).to.be.equal(tokenAddress);
- expect(transferEvent.returnValues.from).to.be.equal(owner);
- expect(transferEvent.returnValues.to).to.be.equal(receiverEth);
- expect(transferEvent.returnValues.value).to.be.equal('49');
-
- const approvalEvent = result.events.Approval;
- expect(approvalEvent.address).to.be.equal(tokenAddress);
- expect(approvalEvent.returnValues.owner).to.be.equal(owner);
- expect(approvalEvent.returnValues.spender).to.be.equal(spender);
- expect(approvalEvent.returnValues.value).to.be.equal('51');
-
- // Check balances:
- const receiverBalance = await contract.methods.balanceOf(receiverEth).call();
- const ownerBalance = await contract.methods.balanceOf(owner).call();
-
- expect(+receiverBalance).to.equal(49);
- expect(+ownerBalance).to.equal(151);
- }
-
- // 1.2 Cross substrate address:
- if(testCase === 'transferFromCross') {
- const result = await contract.methods.transferFromCross(ownerCross, receiverCrossSub, 51).send({from: spender});
- // Check events:
- const transferEvent = result.events.Transfer;
- expect(transferEvent.address).to.be.equal(tokenAddress);
- expect(transferEvent.returnValues.from).to.be.equal(owner);
- expect(transferEvent.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));
- expect(transferEvent.returnValues.value).to.be.equal('51');
-
- const approvalEvent = result.events.Approval;
- expect(approvalEvent.address).to.be.equal(tokenAddress);
- expect(approvalEvent.returnValues.owner).to.be.equal(owner);
- expect(approvalEvent.returnValues.spender).to.be.equal(spender);
- expect(approvalEvent.returnValues.value).to.be.equal('0');
-
- // Check balances:
- const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});
- const ownerBalance = await contract.methods.balanceOf(owner).call();
- expect(receiverBalance).to.equal(51n);
- expect(+ownerBalance).to.equal(100);
- }
- }));
-
- [
- 'transfer',
- 'transferCross',
- ].map(testCase =>
- itEth(`Can perform ${testCase}()`, async ({helper}) => {
- const isCross = testCase === 'transferCross';
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiverEth = helper.eth.createAccount();
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const [receiverSub] = await helper.arrange.createAccounts([1n], donor);
- const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- // 1. Can transfer to plain ethereum or cross-ethereum account:
- {
- const result = await contract.methods[testCase](isCross ? receiverCrossEth : receiverEth, 50).send({from: owner});
- // Check events
- const transferEvent = result.events.Transfer;
- expect(transferEvent.address).to.be.equal(tokenAddress);
- expect(transferEvent.returnValues.from).to.be.equal(owner);
- expect(transferEvent.returnValues.to).to.be.equal(receiverEth);
- expect(transferEvent.returnValues.value).to.be.equal('50');
- // Check balances:
- const ownerBalance = await contract.methods.balanceOf(owner).call();
- const receiverBalance = await contract.methods.balanceOf(receiverEth).call();
- expect(+ownerBalance).to.equal(150);
- expect(+receiverBalance).to.equal(50);
- }
-
- // 2. Can transfer to cross-substrate account:
- if(isCross) {
- const result = await contract.methods.transferCross(receiverCrossSub, 50).send({from: owner});
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));
- expect(event.returnValues.value).to.be.equal('50');
- // Check balances:
- const ownerBalance = await contract.methods.balanceOf(owner).call();
- const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});
- expect(+ownerBalance).to.equal(100);
- expect(receiverBalance).to.equal(50n);
- }
- }));
-
- [
- 'transfer',
- 'transferCross',
- ].map(testCase =>
- itEth(`Cannot ${testCase}() non-owned token`, async ({helper}) => {
- const isCross = testCase === 'transferCross';
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const receiverEth = await helper.eth.createAccountWithBalance(donor);
- const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
- const collection = await helper.rft.mintCollection(alice);
- const rftOwner = await collection.mintToken(alice, 10n, {Ethereum: owner});
- const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiverEth});
- const tokenIdNonExist = 9999999;
-
- const tokenAddress1 = helper.ethAddress.fromTokenId(collection.collectionId, rftOwner.tokenId);
- const tokenAddress2 = helper.ethAddress.fromTokenId(collection.collectionId, rftReceiver.tokenId);
- const tokenAddressNonExist = helper.ethAddress.fromTokenId(collection.collectionId, tokenIdNonExist);
- const tokenEvmOwner = await helper.ethNativeContract.rftToken(tokenAddress1, owner);
- const tokenEvmReceiver = await helper.ethNativeContract.rftToken(tokenAddress2, owner);
- const tokenEvmNonExist = await helper.ethNativeContract.rftToken(tokenAddressNonExist, owner);
-
- // 1. Can transfer zero amount (EIP-20):
- await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 0).send({from: owner});
- // 2. Cannot transfer non-owned token:
- await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected;
- await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected;
- // 3. Cannot transfer non-existing token:
- await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected;
- await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected;
-
- // 4. Storage is not corrupted:
- expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);
- expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]);
- expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]);
-
- // 4.1 Tokens can be transferred:
- await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 10).send({from: owner});
- await tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 10).send({from: receiverEth});
- expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]);
- expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);
- }));
-
- itEth('Can perform repartition()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- await contract.methods.repartition(200).send({from: owner});
- expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);
- await contract.methods.transfer(receiver, 110).send({from: owner});
- expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);
- expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);
-
- await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected; // Transaction is reverted
-
- await contract.methods.transfer(receiver, 90).send({from: owner});
- expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);
- expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);
-
- await contract.methods.repartition(150).send({from: receiver});
- await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected; // Transaction is reverted
- expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);
- });
-
- itEth('Can repartition with increased amount', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- const result = await contract.methods.repartition(200).send();
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(owner);
- expect(event.returnValues.value).to.be.equal('100');
- });
-
- itEth('Can repartition with decreased amount', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- const result = await contract.methods.repartition(50).send();
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.from).to.be.equal(owner);
- expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.value).to.be.equal('50');
- });
-
- itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = await helper.eth.createAccountWithBalance(donor);
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
- const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller, true);
-
- await tokenContract.methods.repartition(2).send();
- await tokenContract.methods.transfer(receiver, 1).send();
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
- await tokenContract.methods.burnFrom(caller, 1).send();
-
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.tokenId).to.be.equal(tokenId);
- });
-
- itEth('Can perform burnFromCross()', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const ownerSub = (await helper.arrange.createAccounts([10n], donor))[0];
- const ownerCross = helper.ethCrossAccount.fromAddress(owner);
- const spender = await helper.eth.createAccountWithBalance(donor);
-
- const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);
- const ownerSubCross = helper.ethCrossAccount.fromKeyringPair(ownerSub);
-
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- {
- await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});
-
- await expect(contract.methods.burnFromCross(ownerCross, 50).send({from: spender})).to.be.fulfilled;
- await expect(contract.methods.burnFromCross(ownerCross, 100).send({from: spender})).to.be.rejected;
- expect(await contract.methods.balanceOf(owner).call({from: owner})).to.be.equal('150');
- }
- {
- const {tokenId} = await collection.mintToken(alice, 200n, {Substrate: ownerSub.address});
- await collection.approveToken(ownerSub, tokenId, {Ethereum: spender}, 100n);
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- await expect(contract.methods.burnFromCross(ownerSubCross, 50).send({from: spender})).to.be.fulfilled;
- await expect(contract.methods.burnFromCross(ownerSubCross, 100).send({from: spender})).to.be.rejected;
- expect(await collection.getTokenBalance(tokenId, {Substrate: ownerSub.address})).to.be.equal(150n);
- }
- });
-
- itEth('Check balanceOfCross()', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- const owner = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const other = await helper.ethCrossAccount.createAccountWithBalance(donor);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner.eth});
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner.eth);
-
- expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('200');
- expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
-
- await tokenContract.methods.repartition(100n).send({from: owner.eth});
- expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('100');
- expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('0');
-
- await tokenContract.methods.transferCross(other, 50n).send({from: owner.eth});
- expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('50');
- expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('50');
-
- await tokenContract.methods.transferCross(other, 50n).send({from: owner.eth});
- expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('0');
- expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('100');
-
- await tokenContract.methods.repartition(1000n).send({from: other.eth});
- await tokenContract.methods.transferCross(owner, 500n).send({from: other.eth});
- expect(await tokenContract.methods.balanceOfCross(owner).call({from: owner.eth})).to.be.eq('500');
- expect(await tokenContract.methods.balanceOfCross(other).call({from: owner.eth})).to.be.eq('500');
- });
-});
-
-describe('Refungible: Fees', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([50n], donor);
- });
- });
-
- itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-
- itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const spender = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- await contract.methods.approve(spender, 100).send({from: owner});
-
- const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-
- itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice);
- const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
- expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
- });
-});
-
-describe('Refungible: Substrate calls', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([50n], donor);
- });
- });
-
- itEth('Events emitted for approve()', async ({helper}) => {
- const receiver = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice);
- const token = await collection.mintToken(alice, 200n);
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress);
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- expect(await token.approve(alice, {Ethereum: receiver}, 100n)).to.be.true;
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Approval');
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.spender).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('100');
- });
-
- itEth('Events emitted for transferFrom()', async ({helper}) => {
- const [bob] = await helper.arrange.createAccounts([10n], donor);
- const receiver = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice);
- const token = await collection.mintToken(alice, 200n);
- await token.approve(alice, {Substrate: bob.address}, 100n);
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress);
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- expect(await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n)).to.be.true;
- if(events.length == 0) await helper.wait.newBlocks(1);
-
- let event = events[0];
- expect(event.event).to.be.equal('Transfer');
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('51');
-
- event = events[1];
- expect(event.event).to.be.equal('Approval');
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
- expect(event.returnValues.value).to.be.equal('49');
- });
-
- itEth('Events emitted for transfer()', async ({helper}) => {
- const receiver = helper.eth.createAccount();
- const collection = await helper.rft.mintCollection(alice);
- const token = await collection.mintToken(alice, 200n);
-
- const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
- const contract = await helper.ethNativeContract.rftToken(tokenAddress);
-
- const events: any = [];
- contract.events.allEvents((_: any, event: any) => {
- events.push(event);
- });
-
- expect(await token.transfer(alice, {Ethereum: receiver}, 51n)).to.be.true;
- if(events.length == 0) await helper.wait.newBlocks(1);
- const event = events[0];
-
- expect(event.event).to.be.equal('Transfer');
- expect(event.address).to.be.equal(tokenAddress);
- expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
- expect(event.returnValues.to).to.be.equal(receiver);
- expect(event.returnValues.value).to.be.equal('51');
- });
-});
-
-describe('ERC 1633 implementation', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Default parent token address and id', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN');
- const collectionContract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
- const result = await collectionContract.methods.mint(owner).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
- const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner);
-
- expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress);
- expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId);
- });
-});
js-packages/tests/src/eth/scheduling.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/scheduling.test.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect} from 'chai';
-import {itSchedEth} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import {Pallets, usingPlaygrounds} from '../util/index.js';
-
-describe('Scheduing EVM smart contracts', () => {
-
- before(async () => {
- await usingPlaygrounds(async (helper) => {
- await helper.testUtils.enable(Pallets.TestUtils);
- });
- });
-
- itSchedEth.ifWithPallets('Successfully schedules and periodically executes an EVM contract', [Pallets.UniqueScheduler], async (scheduleKind, {helper, privateKey}) => {
- const donor = await privateKey({url: import.meta.url});
- const [alice] = await helper.arrange.createAccounts([1000n], donor);
-
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
-
- const deployer = await helper.eth.createAccountWithBalance(alice);
- const flipper = await helper.eth.deployFlipper(deployer);
-
- const initialValue = await flipper.methods.getValue().call();
- await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address));
-
- const waitForBlocks = 4;
- const periodic = {
- period: 2,
- repetitions: 2,
- };
-
- await helper.scheduler.scheduleAfter<EthUniqueHelper>(waitForBlocks, {scheduledId, periodic})
- .eth.sendEVM(
- alice,
- flipper.options.address,
- flipper.methods.flip().encodeABI(),
- '0',
- );
-
- expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
-
- await helper.wait.newBlocks(waitForBlocks + 1);
- expect(await flipper.methods.getValue().call()).to.be.not.equal(initialValue);
-
- await helper.wait.newBlocks(periodic.period);
- expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
- });
-});
js-packages/tests/src/eth/sponsoring.test.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import type {IKeyringPair} from '@polkadot/types/types';18import {itEth, expect, SponsoringMode} from './util/index.js';19import {usingPlaygrounds} from '../util/index.js';2021describe('EVM sponsoring', () => {22 let donor: IKeyringPair;2324 before(async () => {25 await usingPlaygrounds(async (_helper, privateKey) => {26 donor = await privateKey({url: import.meta.url});27 });28 });2930 itEth('Fee is deducted from contract if sponsoring is enabled', async ({helper}) => {31 const owner = await helper.eth.createAccountWithBalance(donor);32 const sponsor = await helper.eth.createAccountWithBalance(donor);33 const caller = helper.eth.createAccount();34 const originalCallerBalance = await helper.balance.getEthereum(caller);3536 expect(originalCallerBalance).to.be.equal(0n);3738 const flipper = await helper.eth.deployFlipper(owner);3940 const helpers = await helper.ethNativeContract.contractHelpers(owner);4142 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});43 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});4445 await helpers.methods.setSponsor(flipper.options.address, sponsor).send({from: owner});46 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});4748 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;49 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});50 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});51 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;5253 const originalSponsorBalance = await helper.balance.getEthereum(sponsor);54 expect(originalSponsorBalance).to.be.not.equal(0n);5556 await flipper.methods.flip().send({from: caller});57 expect(await flipper.methods.getValue().call()).to.be.true;5859 // Balance should be taken from flipper instead of caller60 expect(await helper.balance.getEthereum(caller)).to.be.equal(originalCallerBalance);61 expect(await helper.balance.getEthereum(sponsor)).to.be.not.equal(originalSponsorBalance);62 });6364 itEth('...but this doesn\'t applies to payable value', async ({helper}) => {65 const owner = await helper.eth.createAccountWithBalance(donor);66 const sponsor = await helper.eth.createAccountWithBalance(donor);67 const caller = await helper.eth.createAccountWithBalance(donor);68 const originalCallerBalance = await helper.balance.getEthereum(caller);6970 expect(originalCallerBalance).to.be.not.equal(0n);7172 const collector = await helper.eth.deployCollectorContract(owner);7374 const helpers = await helper.ethNativeContract.contractHelpers(owner);7576 await helpers.methods.toggleAllowlist(collector.options.address, true).send({from: owner});77 await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner});7879 expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.false;80 await helpers.methods.setSponsoringMode(collector.options.address, SponsoringMode.Allowlisted).send({from: owner});81 await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});82 expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;8384 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});85 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});8687 const originalSponsorBalance = await helper.balance.getEthereum(sponsor);88 expect(originalSponsorBalance).to.be.not.equal(0n);8990 await collector.methods.giveMoney().send({from: caller, value: '10000'});9192 // Balance will be taken from both caller (value) and from collector (fee)93 expect(await helper.balance.getEthereum(caller)).to.be.equals((originalCallerBalance - 10000n));94 expect(await helper.balance.getEthereum(sponsor)).to.be.not.equals(originalSponsorBalance);95 expect(await collector.methods.getCollected().call()).to.be.equal('10000');96 });97});js-packages/tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/tokenProperties.test.ts
+++ /dev/null
@@ -1,625 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Contract} from 'web3-eth-contract';
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import type {ITokenPropertyPermission} from '@unique/playgrounds/src/types.js';
-import {Pallets} from '../util/index.js';
-import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '@unique/playgrounds/src/unique.js';
-import {CreateCollectionData, TokenPermissionField} from './util/playgrounds/types.js';
-
-describe('EVM token properties', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([1000n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can set all possible token property permissions`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);
- for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {
- const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
- await collection.methods.addCollectionAdminCross(caller).send({from: owner});
-
- await collection.methods.setTokenPropertyPermissions([
- ['testKey', [
- [TokenPermissionField.Mutable, mutable],
- [TokenPermissionField.TokenOwner, tokenOwner],
- [TokenPermissionField.CollectionAdmin, collectionAdmin]],
- ],
- ]).send({from: caller.eth});
-
- expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{
- key: 'testKey',
- permission: {mutable, collectionAdmin, tokenOwner},
- }]);
-
- expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([
- ['testKey', [
- [TokenPermissionField.Mutable.toString(), mutable],
- [TokenPermissionField.TokenOwner.toString(), tokenOwner],
- [TokenPermissionField.CollectionAdmin.toString(), collectionAdmin]],
- ],
- ]);
- }
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- await collection.methods.setTokenPropertyPermissions([
- ['testKey_0', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ['testKey_1', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, false],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ['testKey_2', [
- [TokenPermissionField.Mutable, false],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, false]],
- ],
- ]).send({from: owner});
-
- expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([
- {
- key: 'testKey_0',
- permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
- },
- {
- key: 'testKey_1',
- permission: {mutable: true, tokenOwner: false, collectionAdmin: true},
- },
- {
- key: 'testKey_2',
- permission: {mutable: false, tokenOwner: true, collectionAdmin: false},
- },
- ]);
-
- expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([
- ['testKey_0', [
- [TokenPermissionField.Mutable.toString(), true],
- [TokenPermissionField.TokenOwner.toString(), true],
- [TokenPermissionField.CollectionAdmin.toString(), true]],
- ],
- ['testKey_1', [
- [TokenPermissionField.Mutable.toString(), true],
- [TokenPermissionField.TokenOwner.toString(), false],
- [TokenPermissionField.CollectionAdmin.toString(), true]],
- ],
- ['testKey_2', [
- [TokenPermissionField.Mutable.toString(), false],
- [TokenPermissionField.TokenOwner.toString(), true],
- [TokenPermissionField.CollectionAdmin.toString(), false]],
- ],
- ]);
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);
-
- const {collectionId, collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
- await collection.methods.addCollectionAdminCross(caller).send({from: owner});
-
- await collection.methods.setTokenPropertyPermissions([
- ['testKey_0', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ['testKey_1', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, false],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ['testKey_2', [
- [TokenPermissionField.Mutable, false],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, false]],
- ],
- ]).send({from: caller.eth});
-
- expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([
- {
- key: 'testKey_0',
- permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
- },
- {
- key: 'testKey_1',
- permission: {mutable: true, tokenOwner: false, collectionAdmin: true},
- },
- {
- key: 'testKey_2',
- permission: {mutable: false, tokenOwner: true, collectionAdmin: false},
- },
- ]);
-
- expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([
- ['testKey_0', [
- [TokenPermissionField.Mutable.toString(), true],
- [TokenPermissionField.TokenOwner.toString(), true],
- [TokenPermissionField.CollectionAdmin.toString(), true]],
- ],
- ['testKey_1', [
- [TokenPermissionField.Mutable.toString(), true],
- [TokenPermissionField.TokenOwner.toString(), false],
- [TokenPermissionField.CollectionAdmin.toString(), true]],
- ],
- ['testKey_2', [
- [TokenPermissionField.Mutable.toString(), false],
- [TokenPermissionField.TokenOwner.toString(), true],
- [TokenPermissionField.CollectionAdmin.toString(), false]],
- ],
- ]);
-
- }));
-
- [
- {
- method: 'setProperties',
- methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]],
- expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}],
- },
- {
- method: 'setProperty' /*Soft-deprecated*/,
- methodParams: ['testKey1', Buffer.from('testValue1')],
- expectedProps: [{key: 'testKey1', value: 'testValue1'}],
- },
- ].map(testCase =>
- itEth(`[${testCase.method}] Can be set`, async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.nft.mintCollection(alice, {
- tokenPropertyPermissions: [{
- key: 'testKey1',
- permission: {
- collectionAdmin: true,
- },
- }, {
- key: 'testKey2',
- permission: {
- collectionAdmin: true,
- },
- }],
- });
-
- await collection.addAdmin(alice, {Ethereum: caller});
- const token = await collection.mintToken(alice);
-
- const collectionEvm = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller, testCase.method === 'setProperty');
-
- await collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller});
-
- const properties = await token.getProperties();
- expect(properties).to.deep.equal(testCase.expectedProps);
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`Can be multiple set/read for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
- const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {tokenOwner: true,
- collectionAdmin: true,
- mutable: true}}));
-
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPrefix: 'ethp',
- tokenPropertyPermissions: permissions,
- }) as UniqueNFTCollection | UniqueRFTCollection;
-
- const token = await collection.mintToken(alice);
-
- const valuesBefore = await token.getProperties(properties.map(p => p.key));
- expect(valuesBefore).to.be.deep.equal([]);
-
-
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
-
- expect(await contract.methods.properties(token.tokenId, []).call()).to.be.deep.equal([]);
-
- await contract.methods.setProperties(token.tokenId, properties).send({from: caller});
-
- const values = await token.getProperties(properties.map(p => p.key));
- expect(values).to.be.deep.equal(properties.map(p => ({key: p.key, value: p.value.toString()})));
-
- expect(await contract.methods.properties(token.tokenId, []).call()).to.be.like(properties
- .map(p => helper.ethProperty.property(p.key, p.value.toString())));
-
- expect(await contract.methods.properties(token.tokenId, [properties[0].key]).call())
- .to.be.like([helper.ethProperty.property(properties[0].key, properties[0].value.toString())]);
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`Can be deleted for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: [{
- key: 'testKey',
- permission: {
- mutable: true,
- collectionAdmin: true,
- },
- },
- {
- key: 'testKey_1',
- permission: {
- mutable: true,
- collectionAdmin: true,
- },
- }],
- });
-
- const token = await collection.mintToken(alice);
- await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}, {key: 'testKey_1', value: 'testValue_1'}]);
- expect(await token.getProperties()).to.has.length(2);
-
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
-
- await contract.methods.deleteProperties(token.tokenId, ['testKey', 'testKey_1']).send({from: caller});
-
- const result = await token.getProperties(['testKey', 'testKey_1']);
- expect(result.length).to.equal(0);
- }));
-
- itEth('Can be read', async({helper}) => {
- const caller = helper.eth.createAccount();
- const collection = await helper.nft.mintCollection(alice, {
- tokenPropertyPermissions: [{
- key: 'testKey',
- permission: {
- collectionAdmin: true,
- },
- }],
- });
-
- const token = await collection.mintToken(alice);
- await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, 'nft', caller);
-
- const value = await contract.methods.property(token.tokenId, 'testKey').call();
- expect(value).to.equal(helper.getWeb3().utils.toHex('testValue'));
- });
-});
-
-describe('EVM token properties negative', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let caller: string;
- let aliceCollection: UniqueNFTCollection;
- let token: UniqueNFToken;
- const tokenProps = [{key: 'testKey_1', value: 'testValue_1'}, {key: 'testKey_2', value: 'testValue_2'}];
- let collectionEvm: Contract;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- beforeEach(async () => {
- // 1. create collection with props: testKey_1, testKey_2
- // 2. create token and set props testKey_1, testKey_2
- await usingEthPlaygrounds(async (helper) => {
- aliceCollection = await helper.nft.mintCollection(alice, {
- tokenPropertyPermissions: [{
- key: 'testKey_1',
- permission: {
- mutable: true,
- collectionAdmin: true,
- },
- },
- {
- key: 'testKey_2',
- permission: {
- mutable: true,
- collectionAdmin: true,
- },
- }],
- });
- token = await aliceCollection.mintToken(alice);
- await token.setProperties(alice, tokenProps);
- collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true);
- });
- });
-
- [
- {method: 'setProperty', methodParams: [tokenProps[1].key, Buffer.from('newValue')]},
- {method: 'setProperties', methodParams: [[{key: tokenProps[1].key, value: Buffer.from('newValue')}]]},
- ].map(testCase =>
- itEth(`[${testCase.method}] Cannot set properties of non-owned collection`, async ({helper}) => {
- caller = await helper.eth.createAccountWithBalance(donor);
- collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true);
- // Caller not an owner and not an admin, so he cannot set properties:
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
-
- // Props have not changed:
- const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
- const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
- expect(actualProps).to.deep.eq(expectedProps);
- }));
-
- [
- {method: 'setProperty', methodParams: ['testKey_3', Buffer.from('testValue3')]},
- {method: 'setProperties', methodParams: [[{key: 'testKey_3', value: Buffer.from('testValue3')}]]},
- ].map(testCase =>
- itEth(`[${testCase.method}] Cannot set non-existing properties`, async ({helper}) => {
- caller = await helper.eth.createAccountWithBalance(donor);
- collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true);
- await helper.collection.addAdmin(alice, aliceCollection.collectionId, {Ethereum: caller});
-
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
-
- // Props have not changed:
- const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
- const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
- expect(actualProps).to.deep.eq(expectedProps);
- }));
-
- [
- {method: 'deleteProperty', methodParams: ['testKey_2']},
- {method: 'deleteProperties', methodParams: [['testKey_2']]},
- ].map(testCase =>
- itEth(`[${testCase.method}] Cannot delete properties of non-owned collection`, async ({helper}) => {
- caller = await helper.eth.createAccountWithBalance(donor);
- collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, testCase.method == 'deleteProperty');
- // Caller not an owner and not an admin, so he cannot set properties:
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
-
- // Props have not changed:
- const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
- const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
- expect(actualProps).to.deep.eq(expectedProps);
- }));
-
- [
- {method: 'deleteProperty', methodParams: ['testKey_3']},
- {method: 'deleteProperties', methodParams: [['testKey_3']]},
- ].map(testCase =>
- itEth(`[${testCase.method}] Cannot delete non-existing properties`, async ({helper}) => {
- caller = await helper.eth.createAccountWithBalance(donor);
- collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, testCase.method == 'deleteProperty');
- await helper.collection.addAdmin(alice, aliceCollection.collectionId, {Ethereum: caller});
- // Caller cannot delete non-existing properties:
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission');
- await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected;
- // Props have not changed:
- const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString()));
- const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call();
- expect(actualProps).to.deep.eq(expectedProps);
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- await expect(collection.methods.setTokenPropertyPermissions([
- ['testKey_0', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).call({from: caller})).to.be.rejectedWith('NoPermission');
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- await expect(collection.methods.setTokenPropertyPermissions([
- // "Space" is invalid character
- ['testKey 0', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey');
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can reconfigure token property permissions to stricter ones`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- // 1. Owner sets strict property-permissions:
- await collection.methods.setTokenPropertyPermissions([
- ['testKey', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).send({from: owner});
-
- // 2. Owner can set stricter property-permissions:
- for(const values of [[true, true, false], [true, false, false], [false, false, false]]) {
- await collection.methods.setTokenPropertyPermissions([
- ['testKey', [
- [TokenPermissionField.Mutable, values[0]],
- [TokenPermissionField.TokenOwner, values[1]],
- [TokenPermissionField.CollectionAdmin, values[2]]],
- ],
- ]).send({from: owner});
- }
-
- expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{
- key: 'testKey',
- permission: {mutable: false, collectionAdmin: false, tokenOwner: false},
- }]);
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Cannot reconfigure token property permissions to less strict ones`, testCase.requiredPallets, async({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
-
- const {collectionAddress} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();
- const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- // 1. Owner sets strict property-permissions:
- await collection.methods.setTokenPropertyPermissions([
- ['testKey', [
- [TokenPermissionField.Mutable, false],
- [TokenPermissionField.TokenOwner, false],
- [TokenPermissionField.CollectionAdmin, false]],
- ],
- ]).send({from: owner});
-
- // 2. Owner cannot set less strict property-permissions:
- for(const values of [[true, false, false], [false, true, false], [false, false, true]]) {
- await expect(collection.methods.setTokenPropertyPermissions([
- ['testKey', [
- [TokenPermissionField.Mutable, values[0]],
- [TokenPermissionField.TokenOwner, values[1]],
- [TokenPermissionField.CollectionAdmin, values[2]]],
- ],
- ]).call({from: owner})).to.be.rejectedWith('NoPermission');
- }
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can't be multiple set/read for non-existent token`, testCase.requiredPallets, async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)}));
- const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {tokenOwner: true,
- collectionAdmin: true,
- mutable: true}}));
-
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPrefix: 'ethp',
- tokenPropertyPermissions: permissions,
- }) as UniqueNFTCollection | UniqueRFTCollection;
-
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
-
- await expect(contract.methods.setProperties(1, properties).call({from: caller})).to.be.rejectedWith('TokenNotFound');
- }));
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itEth.ifWithPallets(`[${testCase.mode}] Can't be deleted for non-existent token`, testCase.requiredPallets, async({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: [{
- key: 'testKey',
- permission: {
- mutable: true,
- collectionAdmin: true,
- },
- },
- {
- key: 'testKey_1',
- permission: {
- mutable: true,
- collectionAdmin: true,
- },
- }],
- });
-
-
- await collection.addAdmin(alice, {Ethereum: caller});
-
- const address = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller);
-
- await expect(contract.methods.deleteProperties(1, ['testKey', 'testKey_1']).call({from: caller})).to.be.rejectedWith('TokenNotFound');
- }));
-});
-
-
-type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
-function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
- if(args.length === 0) {
- yield internalRest as any;
- return;
- }
- for(const value of args[0]) {
- yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
- }
-}
js-packages/tests/src/eth/tokens/callMethodsERC20.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/tokens/callMethodsERC20.test.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {Pallets, requirePalletsOrSkip} from '../../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {CreateCollectionData} from '../util/playgrounds/types.js';
-
-[
- {mode: 'ft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
-].map(testCase => {
- describe(`${testCase.mode.toUpperCase()}: ERC-20 call methods`, () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, testCase.requiredPallets);
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('totalSupply', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const mintingParams = testCase.mode === 'ft' ? [caller, 200n] : [caller];
-
- const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('TotalSupply', '6', '6', testCase.mode)).send();
- if(testCase.mode === 'rft') await collection.methods.mint(caller).send({from: caller});
-
- // Use collection contract for FT or token contract for RFT:
- const contract = testCase.mode === 'ft'
- ? collection
- : await helper.ethNativeContract.rftTokenById(collectionId, 1, caller);
-
- // Mint tokens:
- testCase.mode === 'ft'
- ? await contract.methods.mint(...mintingParams).send({from: caller})
- : await contract.methods.repartition(200).send({from: caller});
-
- const totalSupply = await contract.methods.totalSupply().call();
- expect(totalSupply).to.equal('200');
- });
-
- itEth('balanceOf', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const mintingParams = testCase.mode === 'ft' ? [caller, 200n] : [caller];
-
- const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('BalanceOf', 'Descroption', 'Prefix', testCase.mode)).send();
- if(testCase.mode === 'rft') await collection.methods.mint(caller).send({from: caller});
-
- // Use collection contract for FT or token contract for RFT:
- const contract = testCase.mode === 'ft'
- ? collection
- : await helper.ethNativeContract.rftTokenById(collectionId, 1, caller);
-
- // Mint tokens:
- testCase.mode === 'ft'
- ? await contract.methods.mint(...mintingParams).send({from: caller})
- : await contract.methods.repartition(200).send({from: caller});
-
- const balance = await contract.methods.balanceOf(caller).call();
- expect(balance).to.equal('200');
- });
-
- itEth('decimals', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('BalanceOf', 'Descroption', 'Prefix', testCase.mode)).send();
- if(testCase.mode === 'rft') await collection.methods.mint(caller).send({from: caller});
-
- // Use collection contract for FT or token contract for RFT:
- const contract = testCase.mode === 'ft'
- ? collection
- : await helper.ethNativeContract.rftTokenById(collectionId, 1, caller);
-
- const decimals = await contract.methods.decimals().call();
- expect(decimals).to.equal(testCase.mode === 'rft' ? '0' : '18');
- });
- });
-});
js-packages/tests/src/eth/tokens/callMethodsERC721.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/tokens/callMethodsERC721.test.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {Pallets} from '../../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {CreateCollectionData} from '../util/playgrounds/types.js';
-
-
-describe('ERC-721 call methods', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- [
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'nft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: name/symbol/description`, testCase.requiredPallets, async ({helper}) => {
- const callerEth = await helper.eth.createAccountWithBalance(donor);
- const [callerSub] = await helper.arrange.createAccounts([100n], donor);
- const [name, description, tokenPrefix] = ['Name', 'Description', 'Symbol'];
-
- const {collection: collectionEth} = await helper.eth.createCollection(callerEth, new CreateCollectionData(name, description, tokenPrefix, testCase.mode)).send();
- await collectionEth.methods.mint(callerEth).send({from: callerEth});
- const {collectionId} = await helper[testCase.mode].mintCollection(callerSub, {name, description, tokenPrefix});
- const collectionSub = await helper.ethNativeContract.collectionById(collectionId, testCase.mode, callerEth);
-
- // Can get name/symbol/description for Eth collection
- expect(await collectionEth.methods.name().call()).to.eq(name);
- expect(await collectionEth.methods.symbol().call()).to.eq(tokenPrefix);
- expect(await collectionEth.methods.description().call()).to.eq(description);
- // Can get name/symbol/description for Sub collection
- expect(await collectionSub.methods.name().call()).to.eq(name);
- expect(await collectionSub.methods.symbol().call()).to.eq(tokenPrefix);
- expect(await collectionSub.methods.description().call()).to.eq(description);
- });
- });
-
- [
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'nft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: totalSupply`, testCase.requiredPallets, async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const {collection} = await helper.eth.createCollection(caller, new CreateCollectionData('TotalSupply', '6', '6', testCase.mode)).send();
- await collection.methods.mint(caller).send({from: caller});
-
- const totalSupply = await collection.methods.totalSupply().call();
- expect(totalSupply).to.equal('1');
- });
- });
-
- [
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'nft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: balanceOf`, testCase.requiredPallets, async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
-
- const {collection} = await helper.eth.createCollection(caller, new CreateCollectionData('BalanceOf', 'Descroption', 'Prefix', testCase.mode)).send();
- await collection.methods.mint(caller).send({from: caller});
- await collection.methods.mint(caller).send({from: caller});
- await collection.methods.mint(caller).send({from: caller});
-
- const balance = await collection.methods.balanceOf(caller).call();
- expect(balance).to.equal('3');
- });
- });
-
- [
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'nft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: ownerOf`, testCase.requiredPallets, async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const {collection} = await helper.eth.createCollection(caller, new CreateCollectionData('OwnerOf', '6', '6', testCase.mode)).send();
-
- const result = await collection.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
-
- const owner = await collection.methods.ownerOf(tokenId).call();
- expect(owner).to.equal(caller);
- });
- });
-
- [
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- // TODO {mode: 'nft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: ownerOf after burn`, testCase.requiredPallets, async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collection, collectionId} = await helper.eth.createCollection(caller, new CreateCollectionData('OwnerOf-AfterBurn', '6', '6', testCase.mode)).send();
-
- const result = await collection.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller, true);
-
- await tokenContract.methods.repartition(2).send();
- await tokenContract.methods.transfer(receiver, 1).send();
-
- await tokenContract.methods.burnFrom(caller, 1).send();
-
- const owner = await collection.methods.ownerOf(tokenId).call();
- expect(owner).to.equal(receiver);
- });
- });
-
- itEth.ifWithPallets('RFT: ownerOf for partial ownership', [Pallets.ReFungible], async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6');
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
-
- const result = await contract.methods.mint(caller).send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
-
- await tokenContract.methods.repartition(2).send();
- await tokenContract.methods.transfer(receiver, 1).send();
-
- const owner = await contract.methods.ownerOf(tokenId).call();
- expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
- });
-});
js-packages/tests/src/eth/tokens/minting.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/tokens/minting.test.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {Pallets} from '../../util/index.js';
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
-import {CreateCollectionData} from '../util/playgrounds/types.js';
-
-
-describe('Minting tokens', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([30n, 20n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mint() for Substrate collection`, testCase.requiredPallets, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const mintingParams = testCase.mode === 'ft' ? [receiver, 100] : [receiver];
-
- const collection = await helper[testCase.mode].mintCollection(alice);
- await collection.addAdmin(alice, {Ethereum: owner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- const result = await contract.methods.mint(...mintingParams).send({from: owner});
-
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- if(testCase.mode === 'ft')
- expect(event.returnValues.value).to.equal('100');
-
- // Check token exist:
- if(testCase.mode === 'ft') {
- expect(await helper.ft.getBalance(collection.collectionId, {Ethereum: receiver})).to.eq(100n);
- } else {
- const tokenId = event.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
- expect(await helper.collection.getLastTokenId(collection.collectionId)).to.eq(1);
- expect(await contract.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
- }
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mint() for Ethereum collection`, testCase.requiredPallets, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const mintingParams = testCase.mode === 'ft' ? [receiver, 100] : [receiver];
-
- const {collection, collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Name', 'Desc', 'Prefix', testCase.mode)).send();
-
- const result = await collection.methods.mint(...mintingParams).send({from: owner});
-
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- if(testCase.mode === 'ft')
- expect(event.returnValues.value).to.equal('100');
-
- // Check token exist:
- if(testCase.mode === 'ft') {
- expect(await helper.ft.getBalance(collectionId, {Ethereum: receiver})).to.eq(100n);
- } else {
- const tokenId = event.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
- expect(await helper.collection.getLastTokenId(collectionId)).to.eq(1);
- expect(await collection.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
- }
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- {mode: 'ft' as const, requiredPallets: []},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mint() for Ethereum collection`, testCase.requiredPallets, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
- const mintingParams = testCase.mode === 'ft' ? [receiver, 100] : [receiver];
-
- const {collection, collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('Name', 'Desc', 'Prefix', testCase.mode)).send();
-
- const result = await collection.methods.mint(...mintingParams).send({from: owner});
-
- // Check events:
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(receiver);
- if(testCase.mode === 'ft')
- expect(event.returnValues.value).to.equal('100');
-
- // Check token exist:
- if(testCase.mode === 'ft') {
- expect(await helper.ft.getBalance(collectionId, {Ethereum: receiver})).to.eq(100n);
- } else {
- const tokenId = event.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
- expect(await helper.collection.getLastTokenId(collectionId)).to.eq(1);
- expect(await collection.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
- }
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase => {
- itEth.ifWithPallets(`${testCase.mode.toUpperCase()}: Can mintWithTokenURI() for Ethereum collection`, testCase.requiredPallets, async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', '6', '6', '');
- const contract = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);
-
- const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send();
- const tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal('1');
-
- const event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(receiver);
-
- expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
- expect(await contract.methods.ownerOfCross(tokenId).call()).to.be.like([receiver, '0']);
- // TODO: this wont work right now, need release 919000 first
- // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();
- // const tokenUri = await contract.methods.tokenURI(nextTokenId).call();
- // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);
- });
- });
-});
js-packages/tests/src/eth/transferValue.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/transferValue.test.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from './util/index.js';
-import {expect} from 'chai';
-
-describe('Send value to contract', () => {
- let donor: IKeyringPair;
-
- before(async () => {
- await usingEthPlaygrounds(async (_helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Send to and from contract', async ({helper}) => {
- const contractOwner = await helper.eth.createAccountWithBalance(donor, 600n);
- const [buyer, receiver] = await helper.arrange.createAccounts([600n, 600n], donor);
- const receiverMirror = helper.address.substrateToEth(receiver.address);
- const contract = await helper.ethContract.deployByCode(
- contractOwner,
- 'Test',
- `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.18;
-
- contract Test {
- function send() public payable {
- if (msg.value < 1000000000000000000)
- revert("Not enough gold");
- }
-
- function withdraw(address to) public {
- payable(to).transfer(1000000000000000000);
- }
- }
- `,
- );
-
- const balanceBefore = await helper.balance.getSubstrate(buyer.address);
- await helper.eth.sendEVM(buyer, contract.options.address, contract.methods.send().encodeABI(), '2000000000000000000');
- const balanceAfter = await helper.balance.getSubstrate(buyer.address);
- expect(balanceBefore - balanceAfter > 2000000000000000000n).to.be.true;
- expect(await helper.balance.getEthereum(contract.options.address)).to.be.equal(2000000000000000000n);
-
- await helper.eth.sendEVM(buyer, contract.options.address, contract.methods.withdraw(receiverMirror).encodeABI(), '0');
- expect(await helper.balance.getEthereum(receiverMirror)).to.be.equal(1000000000000000000n);
- expect(await helper.balance.getEthereum(contract.options.address)).to.be.equal(1000000000000000000n);
- });
-});
js-packages/tests/src/eth/util/index.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/util/index.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-import * as path from 'path';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import config from '../../config.js';
-
-import {EthUniqueHelper} from './playgrounds/unique.dev.js';
-import {SilentLogger, SilentConsole} from '@unique/playgrounds/src/unique.dev.js';
-import {makeNames} from '../../util/index.js';
-import type {SchedKind} from '../../util/index.js';
-
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import chaiLike from 'chai-like';
-import {getTestSeed, MINIMUM_DONOR_FUND, requirePalletsOrSkip} from '../../util/index.js';
-
-chai.use(chaiAsPromised);
-chai.use(chaiLike);
-export const expect = chai.expect;
-
-export enum SponsoringMode {
- Disabled = 0,
- Allowlisted = 1,
- Generous = 2,
-}
-
-type PrivateKeyFn = (seed: string | {filename?: string, url?: string}) => Promise<IKeyringPair>;
-
-export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: PrivateKeyFn) => Promise<void>) => {
- const silentConsole = new SilentConsole();
- silentConsole.enable();
-
- const helper = new EthUniqueHelper(new SilentLogger());
-
- try {
- await helper.connect(config.substrateUrl);
- await helper.connectWeb3(config.substrateUrl);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const privateKey: PrivateKeyFn = async (seed) => {
- if(typeof seed === 'string') {
- return helper.util.fromSeed(seed, ss58Format);
- }
- if(seed.url) {
- const {filename} = makeNames(seed.url);
- seed.filename = filename;
- } else if(seed.filename) {
- // Pass
- } else {
- throw new Error('no url nor filename set');
- }
- const actualSeed = getTestSeed(seed.filename);
- let account = helper.util.fromSeed(actualSeed, ss58Format);
- if(await helper.balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND) {
- console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
- account = helper.util.fromSeed('//Alice', ss58Format);
- }
- return account;
- };
- await code(helper, privateKey);
- }
- finally {
- await helper.disconnect();
- silentConsole.disable();
- }
-};
-
-export function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
- (opts.only ? it.only :
- opts.skip ? it.skip : it)(name, async function() {
- await usingEthPlaygrounds(async (helper, privateKey) => {
- if(opts.requiredPallets) {
- requirePalletsOrSkip(this, helper, opts.requiredPallets);
- }
-
- await cb({helper, privateKey});
- });
- });
-}
-
-export function itEthIfWithPallet(name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
- return itEth(name, cb, {requiredPallets: required, ...opts});
-}
-
-itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEth(name, cb, {only: true});
-itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEth(name, cb, {skip: true});
-
-itEthIfWithPallet.only = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {only: true});
-itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});
-itEth.ifWithPallets = itEthIfWithPallet;
-
-export function itSchedEth(
- name: string,
- cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any,
- opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},
-) {
- itEth(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);
- itEth(name + ' (named scheduling)', (apis) => cb('named', apis), opts);
-}
-itSchedEth.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {only: true});
-itSchedEth.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {skip: true});
-itSchedEth.ifWithPallets = itSchedIfWithPallets;
-
-function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
- return itSchedEth(name, cb, {requiredPallets: required, ...opts});
-}
js-packages/tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/util/playgrounds/types.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import {CollectionFlag} from '@unique/playgrounds/src/types.js';
-import type {TCollectionMode} from '@unique/playgrounds/src/types.js';
-
-export interface ContractImports {
- solPath: string;
- fsPath: string;
-}
-
-export interface CompiledContract {
- abi: any;
- object: string;
-}
-
-export type NormalizedEvent = {
- address: string,
- event: string,
- args: { [key: string]: string }
-};
-
-export interface OptionUint {
- status: boolean,
- value: bigint,
-}
-
-export type EthAddress = string;
-
-export interface CrossAddress {
- readonly eth: EthAddress,
- readonly sub: string | Uint8Array,
-}
-
-export type EthProperty = string[];
-
-export enum TokenPermissionField {
- Mutable,
- TokenOwner,
- CollectionAdmin
-}
-
-export enum CollectionLimitField {
- AccountTokenOwnership,
- SponsoredDataSize,
- SponsoredDataRateLimit,
- TokenLimit,
- SponsorTransferTimeout,
- SponsorApproveTimeout,
- OwnerCanTransfer,
- OwnerCanDestroy,
- TransferEnabled
-}
-
-export interface CollectionLimit {
- field: CollectionLimitField,
- value: OptionUint,
-}
-
-export interface CollectionLimitValue {
- field: CollectionLimitField,
- value: bigint,
-}
-
-export enum CollectionMode {
- Nonfungible,
- Fungible,
- Refungible,
-}
-
-export interface PropertyPermission {
- code: TokenPermissionField,
- value: boolean,
-}
-export interface TokenPropertyPermission {
- key: string,
- permissions: PropertyPermission[],
-}
-export interface CollectionNestingAndPermission {
- token_owner: boolean,
- collection_admin: boolean,
- restricted: string[],
-}
-
-export const emptyAddress: [string, string] = [
- '0x0000000000000000000000000000000000000000',
- '0',
-];
-
-export const CREATE_COLLECTION_DATA_DEFAULTS = {
- decimals: 0,
- properties: [],
- tokenPropertyPermissions: [],
- adminList: [],
- nestingSettings: {token_owner: false, collection_admin: false, restricted: []},
- limits: [],
- pendingSponsor: emptyAddress,
- flags: 0,
-};
-
-export interface Property {
- key: string;
- value: Buffer;
-}
-
-export class CreateCollectionData {
- name: string;
- description: string;
- tokenPrefix: string;
- collectionMode: TCollectionMode;
- decimals? = 0;
- properties?: Property[] = [];
- tokenPropertyPermissions?: TokenPropertyPermission[] = [];
- adminList?: CrossAddress[] = [];
- nestingSettings?: CollectionNestingAndPermission = {token_owner: false, collection_admin: false, restricted: []};
- limits?: CollectionLimitValue[] = [];
- pendingSponsor?: [string, string] = emptyAddress;
- flags?: number | CollectionFlag[] = [0];
-
- constructor(
- name: string,
- description: string,
- tokenPrefix: string,
- collectionMode: TCollectionMode,
- decimals = 18,
- ) {
- this.name = name;
- this.description = description;
- this.tokenPrefix = tokenPrefix;
- this.collectionMode = collectionMode;
- if(collectionMode == 'ft')
- this.decimals = decimals;
- else
- this.decimals = 0;
- }
-}
js-packages/tests/src/eth/util/playgrounds/unique.dev.d.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/util/playgrounds/unique.dev.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-declare module 'solc';
\ No newline at end of file
js-packages/tests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- a/js-packages/tests/src/eth/util/playgrounds/unique.dev.ts
+++ /dev/null
@@ -1,617 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-/* eslint-disable function-call-argument-newline */
-// eslint-disable-next-line @typescript-eslint/triple-slash-reference
-/// <reference path="unique.dev.d.ts" />
-
-import {readFile} from 'fs/promises';
-
-import Web3 from 'web3';
-import {WebsocketProvider} from 'web3-core';
-import {Contract} from 'web3-eth-contract';
-
-import solc from 'solc';
-
-import {evmToAddress} from '@polkadot/util-crypto';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import {ArrangeGroup, DevUniqueHelper} from '@unique/playgrounds/src/unique.dev.js';
-
-import type {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types.js';
-import {CollectionMode, CreateCollectionData} from './types.js';
-
-// Native contracts ABI
-import collectionHelpersAbi from '../../abi/collectionHelpers.json' assert {type: 'json'};
-import nativeFungibleAbi from '../../abi/nativeFungible.json' assert {type: 'json'};
-import fungibleAbi from '../../abi/fungible.json' assert {type: 'json'};
-import fungibleDeprecatedAbi from '../../abi/fungibleDeprecated.json' assert {type: 'json'};
-import nonFungibleAbi from '../../abi/nonFungible.json' assert {type: 'json'};
-import nonFungibleDeprecatedAbi from '../../abi/nonFungibleDeprecated.json' assert {type: 'json'};
-import refungibleAbi from '../../abi/reFungible.json' assert {type: 'json'};
-import refungibleDeprecatedAbi from '../../abi/reFungibleDeprecated.json' assert {type: 'json'};
-import refungibleTokenAbi from '../../abi/reFungibleToken.json' assert {type: 'json'};
-import refungibleTokenDeprecatedAbi from '../../abi/reFungibleTokenDeprecated.json' assert {type: 'json'};
-import contractHelpersAbi from '../../abi/contractHelpers.json' assert {type: 'json'};
-import type {ICrossAccountId, TEthereumAccount, TCollectionMode} from '@unique/playgrounds/src/types.js';
-
-class EthGroupBase {
- helper: EthUniqueHelper;
- gasPrice?: string;
-
- constructor(helper: EthUniqueHelper) {
- this.helper = helper;
- }
- async getGasPrice() {
- if(this.gasPrice)
- return this.gasPrice;
- this.gasPrice = await this.helper.getWeb3().eth.getGasPrice();
- return this.gasPrice;
- }
-}
-
-class ContractGroup extends EthGroupBase {
- async findImports(imports?: ContractImports[]) {
- if(!imports) return function(path: string) {
- return {error: `File not found: ${path}`};
- };
-
- const knownImports = {} as { [key: string]: string };
- for(const imp of imports) {
- knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
- }
-
- return function(path: string) {
- if(path in knownImports) return {contents: knownImports[path]};
- return {error: `File not found: ${path}`};
- };
- }
-
- async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {
- const compiled = JSON.parse(solc.compile(JSON.stringify({
- language: 'Solidity',
- sources: {
- [`${name}.sol`]: {
- content: src,
- },
- },
- settings: {
- outputSelection: {
- '*': {
- '*': ['*'],
- },
- },
- },
- }), {import: await this.findImports(imports)}));
-
- const hasErrors = compiled['errors']
- && compiled['errors'].length > 0
- && compiled.errors.some(function(err: any) {
- return err.severity == 'error';
- });
-
- if(hasErrors) {
- throw compiled.errors;
- }
- const out = compiled.contracts[`${name}.sol`][name];
-
- return {
- abi: out.abi,
- object: '0x' + out.evm.bytecode.object,
- };
- }
-
- async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[], gas?: number, args?: any[]): Promise<Contract> {
- const compiledContract = await this.compile(name, src, imports);
- return this.deployByAbi(signer, compiledContract.abi, compiledContract.object, gas, args);
- }
-
- async deployByAbi(signer: string, abi: any, object: string, gas?: number, args?: any[]): Promise<Contract> {
- const web3 = this.helper.getWeb3();
- const contract = new web3.eth.Contract(abi, undefined, {
- data: object,
- from: signer,
- gas: gas ?? this.helper.eth.DEFAULT_GAS,
- });
- return await contract.deploy({data: object, arguments: args}).send({from: signer});
- }
-
-}
-
-class NativeContractGroup extends EthGroupBase {
-
- contractHelpers(caller: string) {
- const web3 = this.helper.getWeb3();
- return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {
- from: caller,
- gas: this.helper.eth.DEFAULT_GAS,
- });
- }
-
- collectionHelpers(caller: string) {
- const web3 = this.helper.getWeb3();
- return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {
- from: caller,
- gas: this.helper.eth.DEFAULT_GAS,
- });
- }
-
- collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) {
- let abi;
- if(address === this.helper.ethAddress.fromCollectionId(0)) {
- abi = nativeFungibleAbi;
- } else {
- abi ={
- 'nft': nonFungibleAbi,
- 'rft': refungibleAbi,
- 'ft': fungibleAbi,
- }[mode];
- }
- if(mergeDeprecated) {
- const deprecated = {
- 'nft': nonFungibleDeprecatedAbi,
- 'rft': refungibleDeprecatedAbi,
- 'ft': fungibleDeprecatedAbi,
- }[mode];
- abi = [...abi, ...deprecated];
- }
- const web3 = this.helper.getWeb3();
- return new web3.eth.Contract(abi as any, address, {
- gas: this.helper.eth.DEFAULT_GAS,
- ...(caller ? {from: caller} : {}),
- });
- }
-
- collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string, mergeDeprecated = false) {
- return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated);
- }
-
- rftToken(address: string, caller?: string, mergeDeprecated = false) {
- const web3 = this.helper.getWeb3();
- const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi;
- return new web3.eth.Contract(abi as any, address, {
- gas: this.helper.eth.DEFAULT_GAS,
- ...(caller ? {from: caller} : {}),
- });
- }
-
- rftTokenById(collectionId: number, tokenId: number, caller?: string, mergeDeprecated = false) {
- return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller, mergeDeprecated);
- }
-}
-
-class CreateCollectionTransaction {
- signer: string;
- data: CreateCollectionData;
- mergeDeprecated: boolean;
- helper: EthUniqueHelper;
-
- constructor(helper: EthUniqueHelper, signer: string, data: CreateCollectionData, mergeDeprecated = false) {
- this.helper = helper;
- this.signer = signer;
-
- let flags = 0;
- // convert CollectionFlags to number and join them in one number
- if(!data.flags) {
- flags = 0;
- } else if(typeof data.flags == 'number') {
- flags = data.flags;
- } else {
- for(let i = 0; i < data.flags.length; i++){
- const flag = data.flags[i];
- flags = flags | flag;
- }
- }
- data.flags = flags;
-
- this.data = data;
- this.mergeDeprecated = mergeDeprecated;
- }
-
- // eslint-disable-next-line require-await
- private async createTransaction() {
- const collectionHelper = this.helper.ethNativeContract.collectionHelpers(this.signer);
- let collectionMode;
- switch (this.data.collectionMode) {
- case 'nft': collectionMode = CollectionMode.Nonfungible; break;
- case 'rft': collectionMode = CollectionMode.Refungible; break;
- case 'ft': collectionMode = CollectionMode.Fungible; break;
- }
-
- const tx = collectionHelper.methods.createCollection([
- this.data.name,
- this.data.description,
- this.data.tokenPrefix,
- collectionMode,
- this.data.decimals,
- this.data.properties,
- this.data.tokenPropertyPermissions,
- this.data.adminList,
- this.data.nestingSettings,
- this.data.limits,
- this.data.pendingSponsor,
- this.data.flags,
- ]);
- return tx;
- }
-
- async send(options?: any): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[], collection: Contract }> {
- const collectionCreationPrice = {
- value: Number(this.helper.balance.getCollectionCreationPrice()),
- };
- const tx = await this.createTransaction();
- const result = await tx.send({...options, ...collectionCreationPrice});
-
- const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
- const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
- const events = this.helper.eth.normalizeEvents(result.events);
- const collection = await this.helper.ethNativeContract.collectionById(collectionId, this.data.collectionMode, this.signer, this.mergeDeprecated);
-
- return {collectionId, collectionAddress, events, collection};
- }
-
- async call(options?: any) {
- const collectionCreationPrice = {
- value: Number(this.helper.balance.getCollectionCreationPrice()),
- };
- const tx = await this.createTransaction();
-
- return await tx.call({...options, ...collectionCreationPrice});
- }
-}
-
-
-class EthGroup extends EthGroupBase {
- DEFAULT_GAS = 2_500_000;
-
- createAccount() {
- const web3 = this.helper.getWeb3();
- const account = web3.eth.accounts.create();
- web3.eth.accounts.wallet.add(account.privateKey);
- return account.address;
- }
-
- async createAccountWithBalance(donor: IKeyringPair, amount = 600n) {
- const account = this.createAccount();
- await this.transferBalanceFromSubstrate(donor, account, amount);
-
- return account;
- }
-
- async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount = 100n, inTokens = true) {
- return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
- }
-
- async getCollectionCreationFee(signer: string) {
- const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
- return await collectionHelper.methods.collectionCreationFee().call();
- }
-
- async sendEVM(signer: IKeyringPair, contractAddress: string, abi: string, value: string, gasLimit?: number) {
- if(!gasLimit) gasLimit = this.DEFAULT_GAS;
- const web3 = this.helper.getWeb3();
- // FIXME: can't send legacy transaction using tx.evm.call
- const gasPrice = await web3.eth.getGasPrice();
- // TODO: check execution status
- await this.helper.executeExtrinsic(
- signer,
- 'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []],
- true,
- );
- }
-
- async callEVM(signer: TEthereumAccount, contractAddress: string, abi: string) {
- return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);
- }
-
- createCollectionMethodName(mode: TCollectionMode) {
- switch (mode) {
- case 'ft':
- return 'createFTCollection';
- case 'nft':
- return 'createNFTCollection';
- case 'rft':
- return 'createRFTCollection';
- }
- }
-
- createCollection(signer: string, data: CreateCollectionData, mergeDeprecated = false): CreateCollectionTransaction {
- return new CreateCollectionTransaction(this.helper, signer, data, mergeDeprecated);
- }
-
- createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
- return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
- }
-
- async createERC721MetadataCompatibleCollection(signer: string, data: CreateCollectionData, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
- const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-
- const {collectionId, collectionAddress, events} = await this.createCollection(signer, data).send();
-
- await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
-
- return {collectionId, collectionAddress, events};
- }
-
- async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
- const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-
- const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
-
- await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
-
- return {collectionId, collectionAddress, events};
- }
-
- createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
- return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
- }
-
- createFungibleCollection(signer: string, name: string, _decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
- return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'ft')).send();
- }
-
- async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
- const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-
- const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
-
- await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
-
- return {collectionId, collectionAddress, events};
- }
-
- async deployCollectorContract(signer: string): Promise<Contract> {
- return await this.helper.ethContract.deployByCode(signer, 'Collector', `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- contract Collector {
- uint256 collected;
- fallback() external payable {
- giveMoney();
- }
- function giveMoney() public payable {
- collected += msg.value;
- }
- function getCollected() public view returns (uint256) {
- return collected;
- }
- function getUnaccounted() public view returns (uint256) {
- return address(this).balance - collected;
- }
-
- function withdraw(address payable target) public {
- target.transfer(collected);
- collected = 0;
- }
- }
- `);
- }
-
- async deployFlipper(signer: string): Promise<Contract> {
- return await this.helper.ethContract.deployByCode(signer, 'Flipper', `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- contract Flipper {
- bool value = false;
- function flip() public {
- value = !value;
- }
- function getValue() public view returns (bool) {
- return value;
- }
- }
- `);
- }
-
- async recordCallFee(user: string, call: () => Promise<any>): Promise<bigint> {
- const before = await this.helper.balance.getEthereum(user);
- await call();
- // In dev mode, the transaction might not finish processing in time
- await this.helper.wait.newBlocks(1);
- const after = await this.helper.balance.getEthereum(user);
-
- return before - after;
- }
-
- normalizeEvents(events: any): NormalizedEvent[] {
- const output = [];
- for(const key of Object.keys(events)) {
- if(key.match(/^[0-9]+$/)) {
- output.push(events[key]);
- } else if(Array.isArray(events[key])) {
- output.push(...events[key]);
- } else {
- output.push(events[key]);
- }
- }
- output.sort((a, b) => a.logIndex - b.logIndex);
- return output.map(({address, event, returnValues}) => {
- const args: { [key: string]: string } = {};
- for(const key of Object.keys(returnValues)) {
- if(!key.match(/^[0-9]+$/)) {
- args[key] = returnValues[key];
- }
- }
- return {
- address,
- event,
- args,
- };
- });
- }
-
- async calculateFee(address: ICrossAccountId, code: () => Promise<any>): Promise<bigint> {
- const wrappedCode = async () => {
- await code();
- // In dev mode, the transaction might not finish processing in time
- await this.helper.wait.newBlocks(1);
- };
- return await this.helper.arrange.calculcateFee(address, wrappedCode);
- }
-}
-
-class EthAddressGroup extends EthGroupBase {
- extractCollectionId(address: string): number {
- if(!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
- return parseInt(address.slice(address.length - 8), 16);
- }
-
- fromCollectionId(collectionId: number): string {
- if(collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow');
- return (Web3 as any).utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`);
- }
-
- extractTokenId(address: string): { collectionId: number, tokenId: number } {
- if(!address.startsWith('0x'))
- throw 'address not starts with "0x"';
- if(address.length > 42)
- throw 'address length is more than 20 bytes';
- return {
- collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
- tokenId: Number('0x' + address.substring(address.length - 8)),
- };
- }
-
- fromTokenId(collectionId: number, tokenId: number): string {
- return this.helper.util.getTokenAddress({collectionId, tokenId});
- }
-
- normalizeAddress(address: string): string {
- return '0x' + address.substring(address.length - 40);
- }
-}
-export class EthPropertyGroup extends EthGroupBase {
- property(key: string, value: string): EthProperty {
- return [
- key,
- '0x' + Buffer.from(value).toString('hex'),
- ];
- }
-}
-export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;
-
-export class EthCrossAccountGroup extends EthGroupBase {
- createAccount(): CrossAddress {
- return this.fromAddress(this.helper.eth.createAccount());
- }
-
- async createAccountWithBalance(donor: IKeyringPair, amount = 100n) {
- return this.fromAddress(await this.helper.eth.createAccountWithBalance(donor, amount));
- }
-
- fromAddress(address: TEthereumAccount): CrossAddress {
- return {
- eth: address,
- sub: '0',
- };
- }
-
- fromAddr(address: TEthereumAccount): [string, string] {
- return [
- address,
- '0',
- ];
- }
-
- fromKeyringPair(keyring: IKeyringPair): CrossAddress {
- return {
- eth: '0x0000000000000000000000000000000000000000',
- sub: keyring.addressRaw,
- };
- }
-}
-
-export class FeeGas {
- fee: number | bigint = 0n;
-
- gas: number | bigint = 0n;
-
- public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
- const instance = new FeeGas();
- instance.fee = instance.convertToTokens(fee);
- instance.gas = await instance.convertToGas(fee, helper);
- return instance;
- }
-
- private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
- const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
- return fee / gasPrice;
- }
-
- private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
- return Number((value * 1000n) / nominal) / 1000;
- }
-}
-
-class EthArrangeGroup extends ArrangeGroup {
- declare helper: EthUniqueHelper;
-
- constructor(helper: EthUniqueHelper) {
- super(helper);
- this.helper = helper;
- }
-
- async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
- const fee = await this.calculcateFee(payer, promise);
- return await FeeGas.build(this.helper, fee);
- }
-}
-export class EthUniqueHelper extends DevUniqueHelper {
- web3: Web3.default | null = null;
- web3Provider: WebsocketProvider | null = null;
-
- eth: EthGroup;
- ethAddress: EthAddressGroup;
- ethCrossAccount: EthCrossAccountGroup;
- ethNativeContract: NativeContractGroup;
- ethContract: ContractGroup;
- ethProperty: EthPropertyGroup;
- declare arrange: EthArrangeGroup;
- constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: { [key: string]: any } = {}) {
- options.helperBase = options.helperBase ?? EthUniqueHelper;
-
- super(logger, options);
- this.eth = new EthGroup(this);
- this.ethAddress = new EthAddressGroup(this);
- this.ethCrossAccount = new EthCrossAccountGroup(this);
- this.ethNativeContract = new NativeContractGroup(this);
- this.ethContract = new ContractGroup(this);
- this.ethProperty = new EthPropertyGroup(this);
- this.arrange = new EthArrangeGroup(this);
- super.arrange = this.arrange;
- }
-
- getWeb3(): Web3.default {
- if(this.web3 === null) throw Error('Web3 not connected');
- return this.web3;
- }
-
- connectWeb3(wsEndpoint: string) {
- if(this.web3 !== null) return;
- this.web3Provider = new (Web3 as any).providers.WebsocketProvider(wsEndpoint);
- this.web3 = new (Web3 as any)(this.web3Provider);
- }
-
- override async disconnect() {
- if(this.web3 === null) return;
- this.web3Provider?.connection.close();
-
- await super.disconnect();
- }
-
- override clearApi() {
- super.clearApi();
- this.web3 = null;
- }
-
- override clone(helperCls: EthUniqueHelperConstructor, options?: { [key: string]: any; }): EthUniqueHelper {
- const newHelper = super.clone(helperCls, options) as EthUniqueHelper;
- newHelper.web3 = this.web3;
- newHelper.web3Provider = this.web3Provider;
-
- return newHelper;
- }
-}
js-packages/tests/src/fungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/fungible.test.ts
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect, requirePalletsOrSkip, Pallets} from './util/index.js';
-
-const U128_MAX = (1n << 128n) - 1n;
-
-describe('integration test: Fungible functionality:', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
- });
- });
-
- itSub('Create fungible collection and token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'trest'});
- const defaultTokenId = await collection.getLastTokenId();
- expect(defaultTokenId).to.be.equal(0);
-
- await collection.mint(alice, U128_MAX);
- const aliceBalance = await collection.getBalance({Substrate: alice.address});
- const itemCountAfter = await collection.getLastTokenId();
-
- expect(itemCountAfter).to.be.equal(defaultTokenId);
- expect(aliceBalance).to.be.equal(U128_MAX);
- });
-
- itSub('RPC method tokenOnewrs for fungible collection and token', async ({helper}) => {
- const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
- const facelessCrowd = (await helper.arrange.createAccounts(Array(7).fill(0n), donor)).map(keyring => ({Substrate: keyring.address}));
-
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- await collection.mint(alice, U128_MAX);
-
- await collection.transfer(alice, {Substrate: bob.address}, 1000n);
- await collection.transfer(alice, ethAcc, 900n);
-
- for(let i = 0; i < 7; i++) {
- await collection.transfer(alice, facelessCrowd[i], 1n);
- }
-
- const owners = await collection.getTop10Owners();
-
- // What to expect
- expect(owners).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]);
- expect(owners.length).to.be.equal(10);
-
- const [eleven] = await helper.arrange.createAccounts([0n], donor);
- expect(await collection.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true;
- expect((await collection.getTop10Owners()).length).to.be.equal(10);
- });
-
- itSub('Transfer token', async ({helper}) => {
- const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- await collection.mint(alice, 500n);
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(500n);
- expect(await collection.transfer(alice, {Substrate: bob.address}, 60n)).to.be.true;
- expect(await collection.transfer(alice, ethAcc, 140n)).to.be.true;
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(300n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(60n);
- expect(await collection.getBalance(ethAcc)).to.be.equal(140n);
-
- await expect(collection.transfer(alice, {Substrate: bob.address}, 350n)).to.eventually.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub('Tokens multiple creation', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- await collection.mintWithOneOwner(alice, [
- {value: 500n},
- {value: 400n},
- {value: 300n},
- ]);
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1200n);
- });
-
- itSub('Burn some tokens ', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- await collection.mint(alice, 500n);
-
- expect(await collection.doesTokenExist(0)).to.be.true;
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(500n);
- expect(await collection.burnTokens(alice, 499n)).to.be.true;
- expect(await collection.doesTokenExist(0)).to.be.true;
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);
- });
-
- itSub('Burn all tokens ', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- await collection.mint(alice, 500n);
-
- expect(await collection.doesTokenExist(0)).to.be.true;
- expect(await collection.burnTokens(alice, 500n)).to.be.true;
- expect(await collection.doesTokenExist(0)).to.be.true;
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(0n);
- expect(await collection.getTotalPieces()).to.be.equal(0n);
- });
-
- itSub('Set allowance for token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
- await collection.mint(alice, 100n);
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(100n);
-
- expect(await collection.approveTokens(alice, {Substrate: bob.address}, 60n)).to.be.true;
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(60n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);
-
- expect(await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: bob.address}, 20n)).to.be.true;
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(80n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(20n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(40n);
-
- await collection.burnTokensFrom(bob, {Substrate: alice.address}, 10n);
-
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(70n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(30n);
- expect(await collection.transferFrom(bob, {Substrate: alice.address}, ethAcc, 10n)).to.be.true;
- expect(await collection.getBalance(ethAcc)).to.be.equal(10n);
- });
-});
-
-describe('Fungible negative tests', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('Cannot transfer incorrect amount of tokens', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const nonExistingCollection = helper.ft.getCollectionObject(99999);
- await collection.mint(alice, 10n, {Substrate: bob.address});
-
- // 1. Alice cannot transfer more than 0 tokens if balance low:
- await expect(collection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
- await expect(collection.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow');
-
- // 2. Alice cannot transfer non-existing token:
- await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.CollectionNotFound');
- await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.CollectionNotFound');
-
- // 3. Zero transfer allowed (EIP-20):
- await collection.transfer(bob, {Substrate: charlie.address}, 0n);
- // 3.1 even if the balance = 0
- await collection.transfer(alice, {Substrate: charlie.address}, 0n);
-
- expect(await collection.getBalance({Substrate: alice.address})).to.eq(0n);
- expect(await collection.getBalance({Substrate: bob.address})).to.eq(10n);
- expect(await collection.getBalance({Substrate: charlie.address})).to.eq(0n);
- });
-});
js-packages/tests/src/getPropertiesRpc.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/getPropertiesRpc.test.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-import {UniqueHelper, UniqueNFTCollection} from '@unique/playgrounds/src/unique.js';
-
-const collectionProps = [
- {key: 'col-0', value: 'col-0-value'},
- {key: 'col-1', value: 'col-1-value'},
-];
-
-const tokenProps = [
- {key: 'tok-0', value: 'tok-0-value'},
- {key: 'tok-1', value: 'tok-1-value'},
-];
-
-const tokPropPermission = {
- mutable: false,
- tokenOwner: true,
- collectionAdmin: false,
-};
-
-const tokenPropPermissions = [
- {
- key: 'tok-0',
- permission: tokPropPermission,
- },
- {
- key: 'tok-1',
- permission: tokPropPermission,
- },
-];
-
-describe('query properties RPC', () => {
- let alice: IKeyringPair;
-
- const mintCollection = async (helper: UniqueHelper) => await helper.nft.mintCollection(alice, {
- tokenPrefix: 'prps',
- properties: collectionProps,
- tokenPropertyPermissions: tokenPropPermissions,
- });
-
- const mintToken = async (collection: UniqueNFTCollection) => await collection.mintToken(alice, {Substrate: alice.address}, tokenProps);
-
-
- before(async () => {
- await usingPlaygrounds(async (_, privateKey) => {
- alice = await privateKey({url: import.meta.url});
- });
- });
-
- itSub('query empty collection key set', async ({helper}) => {
- const collection = await mintCollection(helper);
- const props = await collection.getProperties([]);
- expect(props).to.be.empty;
- });
-
- itSub('query empty token key set', async ({helper}) => {
- const collection = await mintCollection(helper);
- const token = await mintToken(collection);
- const props = await token.getProperties([]);
- expect(props).to.be.empty;
- });
-
- itSub('query empty token key permissions set', async ({helper}) => {
- const collection = await mintCollection(helper);
- const propPermissions = await collection.getPropertyPermissions([]);
- expect(propPermissions).to.be.empty;
- });
-
- itSub('query all collection props by null arg', async ({helper}) => {
- const collection = await mintCollection(helper);
- const props = await collection.getProperties(null);
- expect(props).to.be.deep.equal(collectionProps);
- });
-
- itSub('query all token props by null arg', async ({helper}) => {
- const collection = await mintCollection(helper);
- const token = await mintToken(collection);
- const props = await token.getProperties(null);
- expect(props).to.be.deep.equal(tokenProps);
- });
-
- itSub('query empty token key permissions by null arg', async ({helper}) => {
- const collection = await mintCollection(helper);
- const propPermissions = await collection.getPropertyPermissions(null);
- expect(propPermissions).to.be.deep.equal(tokenPropPermissions);
- });
-
- itSub('query all collection props by undefined arg', async ({helper}) => {
- const collection = await mintCollection(helper);
- const props = await collection.getProperties();
- expect(props).to.be.deep.equal(collectionProps);
- });
-
- itSub('query all token props by undefined arg', async ({helper}) => {
- const collection = await mintCollection(helper);
- const token = await mintToken(collection);
- const props = await token.getProperties();
- expect(props).to.be.deep.equal(tokenProps);
- });
-
- itSub('query empty token key permissions by undefined arg', async ({helper}) => {
- const collection = await mintCollection(helper);
- const propPermissions = await collection.getPropertyPermissions();
- expect(propPermissions).to.be.deep.equal(tokenPropPermissions);
- });
-});
-
-[
- {mode: 'nft' as const},
- {mode: 'rft' as const},
-].map(testCase =>
- describe('negative properties', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (_, privateKey) => {
- alice = await privateKey({url: import.meta.url});
- });
- });
-
- itSub(`[${testCase.mode}] set token property for non-existent token`, async ({helper}) => {
- const collection = await helper[testCase.mode].mintCollection(alice);
- await collection.setTokenPropertyPermissions(alice, [{key: 'key', permission: {mutable: true, tokenOwner: true, collectionAdmin: true}}]);
- await expect(collection.setTokenProperties(alice, 1, [{key: 'key', value: 'value'}])).to.be.rejectedWith('common.TokenNotFound');
- expect(await collection.getTokenProperties(1, ['key'])).to.be.empty;
- });
-
- itSub(`[${testCase.mode}] delete token property for non-existent token`, async ({helper}) => {
- const collection = await helper[testCase.mode].mintCollection(alice);
- await collection.setTokenPropertyPermissions(alice, [{key: 'key', permission: {mutable: true, tokenOwner: true, collectionAdmin: true}}]);
- await expect(collection.deleteTokenProperties(alice, 1, ['key'])).to.be.rejectedWith('common.TokenNotFound');
- expect(await collection.getTokenProperties(1, ['key'])).to.be.empty;
- });
- }));
\ No newline at end of file
js-packages/tests/src/governance/council.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/governance/council.test.ts
+++ /dev/null
@@ -1,457 +0,0 @@
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {Event} from '@unique/playgrounds/src/unique.dev.js';
-import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';
-import type {ICounselors} from './util.js';
-
-describeGov('Governance: Council tests', () => {
- let donor: IKeyringPair;
- let counselors: ICounselors;
- let sudoer: IKeyringPair;
-
- const moreThanHalfCouncilThreshold = 3;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Council]);
-
- donor = await privateKey({url: import.meta.url});
- sudoer = await privateKey('//Alice');
- });
- });
-
- beforeEach(async () => {
- counselors = await initCouncil(donor, sudoer);
- });
-
- afterEach(async () => {
- await clearCouncil(sudoer);
- await clearTechComm(sudoer);
- });
-
- async function proposalFromMoreThanHalfCouncil(proposal: any) {
- return await usingPlaygrounds(async (helper) => {
- expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
- const proposeResult = await helper.council.collective.propose(
- counselors.filip,
- proposal,
- moreThanHalfCouncilThreshold,
- );
-
- const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
- const proposalIndex = councilProposedEvent.proposalIndex;
- const proposalHash = councilProposedEvent.proposalHash;
-
-
- await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
-
- return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
- });
- }
-
- async function proposalFromAllCouncil(proposal: any) {
- return await usingPlaygrounds(async (helper) => {
- expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
- const proposeResult = await helper.council.collective.propose(
- counselors.filip,
- proposal,
- moreThanHalfCouncilThreshold,
- );
-
- const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
- const proposalIndex = councilProposedEvent.proposalIndex;
- const proposalHash = councilProposedEvent.proposalHash;
-
-
- await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.ildar, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.irina, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
-
- return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
- });
- }
-
- itSub('>50% of Council can externally propose SuperMajorityAgainst', async ({helper}) => {
- const forceSetBalanceReceiver = helper.arrange.createEmptyAccount();
- const forceSetBalanceTestValue = 20n * 10n ** 25n;
-
- const democracyProposal = await helper.constructApiCall('api.tx.balances.forceSetBalance', [
- forceSetBalanceReceiver.address, forceSetBalanceTestValue,
- ]);
-
- const councilProposal = await helper.democracy.externalProposeDefaultCall(democracyProposal);
-
- const proposeResult = await helper.council.collective.propose(
- counselors.filip,
- councilProposal,
- moreThanHalfCouncilThreshold,
- );
-
- const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
- const proposalIndex = councilProposedEvent.proposalIndex;
- const proposalHash = councilProposedEvent.proposalHash;
-
- await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
- await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
-
- await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
-
- const democracyStartedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const democracyReferendumIndex = democracyStartedEvent.referendumIndex;
- const democracyThreshold = democracyStartedEvent.threshold;
-
- expect(democracyThreshold).to.be.equal('SuperMajorityAgainst');
-
- await helper.democracy.vote(counselors.filip, democracyReferendumIndex, {
- Standard: {
- vote: {
- aye: true,
- conviction: 1,
- },
- balance: 10_000n,
- },
- });
-
- await helper.democracy.vote(counselors.charu, democracyReferendumIndex, {
- Standard: {
- vote: {
- aye: false,
- conviction: 1,
- },
- balance: 50_000n,
- },
- });
-
- const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
- expect(passedReferendumEvent.referendumIndex).to.be.equal(democracyReferendumIndex);
-
- await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
- const receiverBalance = await helper.balance.getSubstrate(forceSetBalanceReceiver.address);
- expect(receiverBalance).to.be.equal(forceSetBalanceTestValue);
- });
-
- itSub('Council prime member vote is the default', async ({helper}) => {
- const newTechCommMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
- const proposeResult = await helper.council.collective.propose(
- counselors.filip,
- addMemberProposal,
- moreThanHalfCouncilThreshold,
- );
-
- const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
- const proposalIndex = councilProposedEvent.proposalIndex;
- const proposalHash = councilProposedEvent.proposalHash;
-
- await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
-
- await helper.wait.newBlocks(councilMotionDuration);
- const closeResult = await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
- const closeEvent = Event.Council.Closed.expect(closeResult);
- const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as string[];
- expect(closeEvent.yes).to.be.equal(members.length);
- });
-
- itSub('Superuser can add a member', async ({helper}) => {
- const newMember = helper.arrange.createEmptyAccount();
- await expect(helper.getSudo().council.membership.addMember(sudoer, newMember.address)).to.be.fulfilled;
-
- const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
- expect(members).to.contains(newMember.address);
- });
-
- itSub('Superuser can remove a member', async ({helper}) => {
- await expect(helper.getSudo().council.membership.removeMember(sudoer, counselors.alex.address)).to.be.fulfilled;
-
- const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
- expect(members).to.not.contains(counselors.alex.address);
- });
-
- itSub('>50% Council can add TechComm member', async ({helper}) => {
- const newTechCommMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
-
- await proposalFromMoreThanHalfCouncil(addMemberProposal);
-
- const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
- expect(techCommMembers).to.contains(newTechCommMember.address);
- });
-
- itSub('Council can remove TechComm member', async ({helper}) => {
- const techComm = await initTechComm(donor, sudoer);
- const removeMemberPrpoposal = helper.technicalCommittee.membership.removeMemberCall(techComm.andy.address);
- await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
-
- const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
- expect(techCommMembers).to.not.contains(techComm.andy.address);
- });
-
- itSub.skip('Council member can add Fellowship member', async ({helper}) => {
- const newFellowshipMember = helper.arrange.createEmptyAccount();
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
- )).to.be.fulfilled;
- const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
- expect(fellowshipMembers).to.contains(newFellowshipMember.address);
- });
-
- itSub('>50% Council can promote Fellowship member', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const memberWithZeroRank = fellowship[0][0];
-
- const proposal = helper.fellowship.collective.promoteCall(memberWithZeroRank.address);
- await proposalFromMoreThanHalfCouncil(proposal);
- const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithZeroRank.address])).toJSON();
- expect(record).to.be.deep.equal({rank: 1});
-
- await clearFellowship(sudoer);
- });
-
- itSub('>50% Council can demote Fellowship member', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const memberWithRankOne = fellowship[1][0];
-
- const proposal = helper.fellowship.collective.demoteCall(memberWithRankOne.address);
- await proposalFromMoreThanHalfCouncil(proposal);
-
- const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithRankOne.address])).toJSON();
- expect(record).to.be.deep.equal({rank: 0});
-
- await clearFellowship(sudoer);
- });
-
- itSub('>50% Council can add\remove Fellowship member', async ({helper}) => {
- try {
- const newMember = helper.arrange.createEmptyAccount();
-
- const proposalAdd = helper.fellowship.collective.addMemberCall(newMember.address);
- const proposalRemove = helper.fellowship.collective.removeMemberCall(newMember.address, fellowshipRankLimit);
- await expect(proposalFromMoreThanHalfCouncil(proposalAdd)).to.be.fulfilled;
- expect(await helper.fellowship.collective.getMembers()).to.be.deep.contain(newMember.address);
- await expect(proposalFromMoreThanHalfCouncil(proposalRemove)).to.be.fulfilled;
- expect(await helper.fellowship.collective.getMembers()).to.be.not.deep.contain(newMember.address);
- }
- finally {
- await clearFellowship(sudoer);
- }
- });
-
- itSub('Council can blacklist Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash, null))).to.be.fulfilled;
- });
-
- itSub('Sudo can blacklist Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await expect(helper.getSudo().democracy.blacklist(sudoer, preimageHash)).to.be.fulfilled;
- });
-
- itSub('[Negative] Council cannot add Council member', async ({helper}) => {
- const newCouncilMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
-
- await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejected;
- });
-
- itSub('[Negative] Council cannot remove Council member', async ({helper}) => {
- const removeMemberProposal = helper.council.membership.removeMemberCall(counselors.alex.address);
-
- await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejected;
- });
-
- itSub('[Negative] Council cannot submit regular democracy proposal', async ({helper}) => {
- const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
-
- await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council cannot externally propose SimpleMajority', async ({helper}) => {
- const councilProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
-
- await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council cannot externally propose SuperMajorityApprove', async ({helper}) => {
- const councilProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
-
- await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council member cannot add/remove a Council member', async ({helper}) => {
- const newCouncilMember = helper.arrange.createEmptyAccount();
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.council.membership.addMemberCall(newCouncilMember.address),
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.council.membership.removeMemberCall(counselors.charu.address),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council cannot set/clear Council prime member', async ({helper}) => {
- const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
- const proposalForClear = await helper.council.membership.clearPrimeCall();
-
- await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith(/BadOrigin/);
- await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith(/BadOrigin/);
-
- });
-
- itSub('[Negative] Council member cannot set/clear Council prime member', async ({helper}) => {
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.council.membership.setPrimeCall(counselors.charu.address),
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.council.membership.clearPrimeCall(),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council member cannot add/remove a TechComm member', async ({helper}) => {
- const newTechCommMember = helper.arrange.createEmptyAccount();
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address),
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.technicalCommittee.membership.removeMemberCall(newTechCommMember.address),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const memberWithRankOne = fellowship[1][0];
-
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.fellowship.collective.promoteCall(memberWithRankOne.address),
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.fellowship.collective.demoteCall(memberWithRankOne.address),
- )).to.be.rejectedWith('BadOrigin');
- await clearFellowship(sudoer);
- });
-
- itSub('[Negative] Council cannot fast-track Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))
- .to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council member cannot fast-track Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council cannot cancel Democracy proposals', async ({helper}) => {
- const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
- const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
- await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))
- .to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council member cannot cancel Democracy proposals', async ({helper}) => {
-
- const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
- const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.democracy.cancelProposalCall(proposalIndex),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council cannot cancel ongoing Democracy referendums', async ({helper}) => {
- await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const referendumIndex = startedEvent.referendumIndex;
-
- await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))
- .to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council member cannot cancel ongoing Democracy referendums', async ({helper}) => {
- await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const referendumIndex = startedEvent.referendumIndex;
-
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.democracy.emergencyCancelCall(referendumIndex),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council cannot cancel Fellowship referendums', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const fellowshipProposer = fellowship[5][0];
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- fellowshipProposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
- await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))
- .to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Council member cannot cancel Fellowship referendums', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const fellowshipProposer = fellowship[5][0];
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- fellowshipProposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
- await expect(helper.council.collective.execute(
- counselors.alex,
- helper.fellowship.referenda.cancelCall(referendumIndex),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] Council referendum cannot be closed until the voting threshold is met', async ({helper}) => {
- const councilSize = (await helper.callRpc('api.query.councilMembership.members')).toJSON().length as any as number;
- expect(councilSize).is.greaterThan(1);
- const proposeResult = await helper.council.collective.propose(
- counselors.filip,
- dummyProposalCall(helper),
- councilSize,
- );
-
- const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
- const proposalIndex = councilProposedEvent.proposalIndex;
- const proposalHash = councilProposedEvent.proposalHash;
-
-
- await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
- await expect(helper.council.collective.close(counselors.filip, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
- });
-
-});
js-packages/tests/src/governance/democracy.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/governance/democracy.test.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {clearFellowship, democracyLaunchPeriod, democracyTrackMinRank, dummyProposalCall, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, fellowshipPreparePeriod, fellowshipPropositionOrigin, initFellowship, voteUnanimouslyInFellowship} from './util.js';
-import {Event} from '@unique/playgrounds/src/unique.dev.js';
-
-describeGov('Governance: Democracy tests', () => {
- let regularUser: IKeyringPair;
- let donor: IKeyringPair;
- let sudoer: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Democracy]);
-
- donor = await privateKey({url: import.meta.url});
- sudoer = await privateKey('//Alice');
-
- [regularUser] = await helper.arrange.createAccounts([1000n], donor);
- });
- });
-
- itSub('Regular user can vote', async ({helper}) => {
- const fellows = await initFellowship(donor, sudoer);
- const rank1Proposer = fellows[1][0];
-
- const democracyProposalCall = dummyProposalCall(helper);
- const fellowshipProposal = {
- Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
- };
-
- const submitResult = await helper.fellowship.referenda.submit(
- rank1Proposer,
- fellowshipPropositionOrigin,
- fellowshipProposal,
- {After: 0},
- );
-
- const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
- await voteUnanimouslyInFellowship(helper, fellows, democracyTrackMinRank, fellowshipReferendumIndex);
- await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
-
- await helper.wait.expectEvent(
- fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
- Event.Democracy.Proposed,
- );
-
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const referendumIndex = startedEvent.referendumIndex;
-
- const ayeBalance = 10_000n;
-
- await helper.democracy.vote(regularUser, referendumIndex, {
- Standard: {
- vote: {
- aye: true,
- conviction: 1,
- },
- balance: ayeBalance,
- },
- });
-
- const referendumInfo = await helper.democracy.referendumInfo(referendumIndex);
- const tally = referendumInfo.ongoing.tally;
-
- expect(BigInt(tally.ayes)).to.be.equal(ayeBalance);
-
- await clearFellowship(sudoer);
- });
-
- itSub('[Negative] Regular user cannot submit a regular proposal', async ({helper}) => {
- const submitResult = helper.democracy.propose(regularUser, dummyProposalCall(helper), 0n);
- await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Regular user cannot externally propose SuperMajorityAgainst', async ({helper}) => {
- const submitResult = helper.democracy.externalProposeDefault(regularUser, dummyProposalCall(helper));
- await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Regular user cannot externally propose SimpleMajority', async ({helper}) => {
- const submitResult = helper.democracy.externalProposeMajority(regularUser, dummyProposalCall(helper));
- await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Regular user cannot externally propose SuperMajorityApprove', async ({helper}) => {
- const submitResult = helper.democracy.externalPropose(regularUser, dummyProposalCall(helper));
- await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
- });
-});
js-packages/tests/src/governance/fellowship.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/governance/fellowship.test.ts
+++ /dev/null
@@ -1,335 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {DevUniqueHelper, Event} from '@unique/playgrounds/src/unique.dev.js';
-import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, voteUnanimouslyInFellowship, democracyTrackMinRank, fellowshipPreparePeriod, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, democracyTrackId, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
-import type {ICounselors, ITechComms} from './util.js';
-
-describeGov('Governance: Fellowship tests', () => {
- let members: IKeyringPair[][];
-
- let rank1Proposer: IKeyringPair;
-
- let sudoer: any;
- let donor: any;
- let counselors: ICounselors;
- let techcomms: ITechComms;
-
- const submissionDeposit = 1000n;
-
- async function testBadFellowshipProposal(
- helper: DevUniqueHelper,
- proposalCall: any,
- ) {
- const badProposal = {
- Inline: proposalCall.method.toHex(),
- };
- const submitResult = await helper.fellowship.referenda.submit(
- rank1Proposer,
- fellowshipPropositionOrigin,
- badProposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
- await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, referendumIndex);
- await helper.fellowship.referenda.placeDecisionDeposit(donor, referendumIndex);
-
- const enactmentId = await helper.fellowship.referenda.enactmentEventId(referendumIndex);
- const dispatchedEvent = await helper.wait.expectEvent(
- fellowshipPreparePeriod + fellowshipConfirmPeriod + defaultEnactmentMoment.After,
- Event.Scheduler.Dispatched,
- (event: any) => event.id == enactmentId,
- );
-
- expect(dispatchedEvent.result.isErr, 'Bad Fellowship must fail')
- .to.be.true;
-
- expect(dispatchedEvent.result.asErr.isBadOrigin, 'Bad Fellowship must fail with BadOrigin')
- .to.be.true;
- }
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Fellowship, Pallets.TechnicalCommittee, Pallets.Council]);
-
- sudoer = await privateKey('//Alice');
- donor = await privateKey({url: import.meta.url});
- });
-
- counselors = await initCouncil(donor, sudoer);
- techcomms = await initTechComm(donor, sudoer);
- members = await initFellowship(donor, sudoer);
-
- rank1Proposer = members[1][0];
- });
-
- after(async () => {
- await clearFellowship(sudoer);
- await clearTechComm(sudoer);
- await clearCouncil(sudoer);
- await hardResetFellowshipReferenda(sudoer);
- await hardResetDemocracy(sudoer);
- await hardResetGovScheduler(sudoer);
- });
-
- itSub('FellowshipProposition can submit regular Democracy proposals', async ({helper}) => {
- const democracyProposalCall = dummyProposalCall(helper);
- const fellowshipProposal = {
- Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
- };
-
- const submitResult = await helper.fellowship.referenda.submit(
- rank1Proposer,
- fellowshipPropositionOrigin,
- fellowshipProposal,
- defaultEnactmentMoment,
- );
-
- const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
- await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, fellowshipReferendumIndex);
- await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
-
- const democracyProposed = await helper.wait.expectEvent(
- fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
- Event.Democracy.Proposed,
- );
-
- const democracyEnqueuedProposal = await helper.democracy.expectPublicProposal(democracyProposed.proposalIndex);
- expect(democracyEnqueuedProposal.inline, 'Fellowship proposal expected to be in the Democracy')
- .to.be.equal(democracyProposalCall.method.toHex());
-
- await helper.wait.newBlocks(democracyVotingPeriod);
- });
-
- itSub('Fellowship (rank-1 or greater) member can submit Fellowship proposals on the Democracy track', async ({helper}) => {
- for(let rank = 1; rank < fellowshipRankLimit; rank++) {
- const rankMembers = members[rank];
-
- for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
- const member = rankMembers[memberIdx];
- const newDummyProposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- member,
- fellowshipPropositionOrigin,
- newDummyProposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
- const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
- expect(referendumInfo.ongoing.track, `${memberIdx}-th member of rank #${rank}: proposal #${referendumIndex} is on invalid track`)
- .to.be.equal(democracyTrackId);
- }
- }
- });
-
- itSub(`Fellowship (rank-${democracyTrackMinRank} or greater) members can vote on the Democracy track`, async ({helper}) => {
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- rank1Proposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
- let expectedAyes = 0;
- for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
- const rankMembers = members[rank];
-
- for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
- const member = rankMembers[memberIdx];
- await helper.fellowship.collective.vote(member, referendumIndex, true);
- expectedAyes += 1;
-
- const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
- expect(referendumInfo.ongoing.tally.bareAyes, `Vote from ${memberIdx}-th member of rank #${rank} isn't accounted`)
- .to.be.equal(expectedAyes);
- }
- }
- });
-
- itSub('Fellowship rank vote strength is correct', async ({helper}) => {
- const excessRankWeightTable = [
- 1,
- 3,
- 6,
- 10,
- 15,
- 21,
- ];
-
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- rank1Proposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
- for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
- const rankMembers = members[rank];
-
- for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
- const member = rankMembers[memberIdx];
-
- const referendumInfoBefore = await helper.fellowship.referenda.referendumInfo(referendumIndex);
- const ayesBefore = referendumInfoBefore.ongoing.tally.ayes;
-
- await helper.fellowship.collective.vote(member, referendumIndex, true);
-
- const referendumInfoAfter = await helper.fellowship.referenda.referendumInfo(referendumIndex);
- const ayesAfter = referendumInfoAfter.ongoing.tally.ayes;
-
- const expectedVoteWeight = excessRankWeightTable[rank - democracyTrackMinRank];
- const voteWeight = ayesAfter - ayesBefore;
-
- expect(voteWeight, `Vote weight of ${memberIdx}-th member of rank #${rank} is invalid`)
- .to.be.equal(expectedVoteWeight);
- }
- }
- });
-
- itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityAgainst', async ({helper}) => {
- await testBadFellowshipProposal(helper, helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper)));
- });
-
- itSub('[Negative] FellowshipProposition cannot externally propose SimpleMajority', async ({helper}) => {
- await testBadFellowshipProposal(helper, helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper)));
- });
-
- itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityApprove', async ({helper}) => {
- await testBadFellowshipProposal(helper, helper.democracy.externalProposeCall(dummyProposalCall(helper)));
- });
-
- itSub('[Negative] Fellowship (rank-0) member cannot submit Fellowship proposals on the Democracy track', async ({helper}) => {
- const rank0Proposer = members[0][0];
-
- const proposal = dummyProposal(helper);
-
- const submitResult = helper.fellowship.referenda.submit(
- rank0Proposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
- });
-
- itSub('[Negative] Fellowship (rank-1 or greater) member cannot submit if no deposit can be provided', async ({helper}) => {
- const poorMember = rank1Proposer;
-
- const balanceBefore = await helper.balance.getSubstrate(poorMember.address);
- await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, submissionDeposit - 1n);
-
- const proposal = dummyProposal(helper);
-
- const submitResult = helper.fellowship.referenda.submit(
- poorMember,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- await expect(submitResult).to.be.rejectedWith(/account balance too low/);
-
- await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, balanceBefore);
- });
-
- itSub(`[Negative] Fellowship (rank-${democracyTrackMinRank - 1} or less) members cannot vote on the Democracy track`, async ({helper}) => {
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- rank1Proposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
- for(let rank = 0; rank < democracyTrackMinRank; rank++) {
- for(const member of members[rank]) {
- const voteResult = helper.fellowship.collective.vote(member, referendumIndex, true);
- await expect(voteResult).to.be.rejectedWith(/RankTooLow/);
- }
- }
- });
-
- itSub('[Negative] FellowshipProposition cannot add/remove a Council member', async ({helper}) => {
- const [councilNonMember] = await helper.arrange.createAccounts([10n], donor);
-
- await testBadFellowshipProposal(helper, helper.council.membership.addMemberCall(councilNonMember.address));
- await testBadFellowshipProposal(helper, helper.council.membership.removeMemberCall(counselors.ildar.address));
- });
-
- itSub('[Negative] FellowshipProposition cannot set/clear Council prime member', async ({helper}) => {
- await testBadFellowshipProposal(helper, helper.council.membership.setPrimeCall(counselors.ildar.address));
- await testBadFellowshipProposal(helper, helper.council.membership.clearPrimeCall());
- });
-
- itSub('[Negative] FellowshipProposition cannot add/remove a TechComm member', async ({helper}) => {
- const [techCommNonMember] = await helper.arrange.createAccounts([10n], donor);
-
- await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.addMemberCall(techCommNonMember.address));
- await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.removeMemberCall(techcomms.constantine.address));
- });
-
- itSub('[Negative] FellowshipProposition cannot add/remove a Fellowship member', async ({helper}) => {
- const [fellowshipNonMember] = await helper.arrange.createAccounts([10n], donor);
-
- await testBadFellowshipProposal(helper, helper.fellowship.collective.addMemberCall(fellowshipNonMember.address));
- await testBadFellowshipProposal(helper, helper.fellowship.collective.removeMemberCall(rank1Proposer.address, 1));
- });
-
- itSub('[Negative] FellowshipProposition cannot promote/demote a Fellowship member', async ({helper}) => {
- await testBadFellowshipProposal(helper, helper.fellowship.collective.promoteCall(rank1Proposer.address));
- await testBadFellowshipProposal(helper, helper.fellowship.collective.demoteCall(rank1Proposer.address));
- });
-
- itSub('[Negative] FellowshipProposition cannot fast-track Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await testBadFellowshipProposal(helper, helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
- });
-
- itSub('[Negative] FellowshipProposition cannot cancel Democracy proposals', async ({helper}) => {
- const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
- const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
- await testBadFellowshipProposal(helper, helper.democracy.cancelProposalCall(proposalIndex));
- });
-
- itSub('[Negative] FellowshipProposition cannot cancel ongoing Democracy referendums', async ({helper}) => {
- await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const referendumIndex = startedEvent.referendumIndex;
-
- await testBadFellowshipProposal(helper, helper.democracy.emergencyCancelCall(referendumIndex));
- });
-
- itSub('[Negative] FellowshipProposition cannot blacklist Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await testBadFellowshipProposal(helper, helper.democracy.blacklistCall(preimageHash, null));
- });
-
- itSub('[Negative] FellowshipProposition cannot veto external proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await testBadFellowshipProposal(helper, helper.democracy.vetoExternalCall(preimageHash));
- });
-});
js-packages/tests/src/governance/init.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/governance/init.test.ts
+++ /dev/null
@@ -1,193 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {Event} from '@unique/playgrounds/src/unique.dev.js';
-import {democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, clearCouncil, clearTechComm, clearFellowship} from './util.js';
-import type {ICounselors, ITechComms} from './util.js';
-
-describeGov('Governance: Initialization', () => {
- let donor: IKeyringPair;
- let sudoer: IKeyringPair;
- let counselors: ICounselors;
- let techcomms: ITechComms;
- let coreDevs: any;
-
- const expectedAlexFellowRank = 7;
- const expectedFellowRank = 6;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Council, Pallets.TechnicalCommittee]);
-
- const councilMembers = await helper.council.membership.getMembers();
- const techcommMembers = await helper.technicalCommittee.membership.getMembers();
- expect(councilMembers.length == 0, 'The Council must be empty before the Gov Init');
- expect(techcommMembers.length == 0, 'The Technical Commettee must be empty before the Gov Init');
-
- donor = await privateKey({url: import.meta.url});
- sudoer = await privateKey('//Alice');
-
- const counselorsNum = 5;
- const techCommsNum = 3;
- const coreDevsNum = 2;
- const [
- alex,
- ildar,
- charu,
- filip,
- irina,
-
- greg,
- andy,
- constantine,
-
- yaroslav,
- daniel,
- ] = await helper.arrange.createAccounts(new Array(counselorsNum + techCommsNum + coreDevsNum).fill(10_000n), donor);
-
- counselors = {
- alex,
- ildar,
- charu,
- filip,
- irina,
- };
-
- techcomms = {
- greg,
- andy,
- constantine,
- };
-
- coreDevs = {
- yaroslav: yaroslav,
- daniel: daniel,
- };
- });
- });
-
- itSub('Initialize Governance', async ({helper}) => {
- const promoteFellow = (fellow: string, promotionsNum: number) => new Array(promotionsNum).fill(helper.fellowship.collective.promoteCall(fellow));
-
- const expectFellowRank = async (fellow: string, expectedRank: number) => {
- expect(await helper.fellowship.collective.getMemberRank(fellow)).to.be.equal(expectedRank);
- };
-
- console.log('\t- Setup the Prime of the Council via sudo');
- await helper.getSudo().utility.batchAll(sudoer, [
- helper.council.membership.addMemberCall(counselors.alex.address),
- helper.council.membership.setPrimeCall(counselors.alex.address),
-
- helper.fellowship.collective.addMemberCall(counselors.alex.address),
- ...promoteFellow(counselors.alex.address, expectedAlexFellowRank),
- ]);
-
- let councilMembers = await helper.council.membership.getMembers();
- const councilPrime = await helper.council.collective.getPrimeMember();
- const alexFellowRank = await helper.fellowship.collective.getMemberRank(counselors.alex.address);
- expect(councilMembers).to.be.deep.equal([counselors.alex.address]);
- expect(councilPrime).to.be.equal(counselors.alex.address);
- expect(alexFellowRank).to.be.equal(expectedAlexFellowRank);
-
- console.log('\t- The Council Prime initializes the Technical Commettee');
- const councilProposalThreshold = 1;
-
- await helper.council.collective.propose(
- counselors.alex,
- helper.utility.batchAllCall([
- helper.technicalCommittee.membership.addMemberCall(techcomms.greg.address),
- helper.technicalCommittee.membership.addMemberCall(techcomms.andy.address),
- helper.technicalCommittee.membership.addMemberCall(techcomms.constantine.address),
-
- helper.technicalCommittee.membership.setPrimeCall(techcomms.greg.address),
- ]),
- councilProposalThreshold,
- );
-
- const techCommMembers = await helper.technicalCommittee.membership.getMembers();
- const techCommPrime = await helper.technicalCommittee.membership.getPrimeMember();
- const expectedTechComms = [techcomms.greg.address, techcomms.andy.address, techcomms.constantine.address];
- expect(techCommMembers.length).to.be.equal(expectedTechComms.length);
- expect(techCommMembers).to.containSubset(expectedTechComms);
- expect(techCommPrime).to.be.equal(techcomms.greg.address);
-
- console.log('\t- The Council Prime initiates a referendum to add counselors');
- const returnPreimageHash = true;
- const preimageHash = await helper.preimage.notePreimageFromCall(counselors.alex, helper.utility.batchAllCall([
- helper.council.membership.addMemberCall(counselors.ildar.address),
- helper.council.membership.addMemberCall(counselors.charu.address),
- helper.council.membership.addMemberCall(counselors.filip.address),
- helper.council.membership.addMemberCall(counselors.irina.address),
-
- helper.fellowship.collective.addMemberCall(counselors.charu.address),
- helper.fellowship.collective.addMemberCall(counselors.ildar.address),
- helper.fellowship.collective.addMemberCall(counselors.irina.address),
- helper.fellowship.collective.addMemberCall(counselors.filip.address),
- helper.fellowship.collective.addMemberCall(techcomms.greg.address),
- helper.fellowship.collective.addMemberCall(techcomms.andy.address),
- helper.fellowship.collective.addMemberCall(techcomms.constantine.address),
- helper.fellowship.collective.addMemberCall(coreDevs.yaroslav.address),
- helper.fellowship.collective.addMemberCall(coreDevs.daniel.address),
-
- ...promoteFellow(counselors.charu.address, expectedFellowRank),
- ...promoteFellow(counselors.ildar.address, expectedFellowRank),
- ...promoteFellow(counselors.irina.address, expectedFellowRank),
- ...promoteFellow(counselors.filip.address, expectedFellowRank),
- ...promoteFellow(techcomms.greg.address, expectedFellowRank),
- ...promoteFellow(techcomms.andy.address, expectedFellowRank),
- ...promoteFellow(techcomms.constantine.address, expectedFellowRank),
- ...promoteFellow(coreDevs.yaroslav.address, expectedFellowRank),
- ...promoteFellow(coreDevs.daniel.address, expectedFellowRank),
- ]), returnPreimageHash);
-
- await helper.council.collective.propose(
- counselors.alex,
- helper.democracy.externalProposeDefaultWithPreimageCall(preimageHash),
- councilProposalThreshold,
- );
-
- console.log('\t- The referendum is being decided');
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-
- await helper.democracy.vote(counselors.filip, startedEvent.referendumIndex, {
- Standard: {
- vote: {
- aye: true,
- conviction: 1,
- },
- balance: 10_000n,
- },
- });
-
- const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
- expect(passedReferendumEvent.referendumIndex).to.be.equal(startedEvent.referendumIndex);
-
- await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
-
- councilMembers = await helper.council.membership.getMembers();
- const expectedCounselors = [
- counselors.alex.address,
- counselors.ildar.address,
- counselors.charu.address,
- counselors.filip.address,
- counselors.irina.address,
- ];
- expect(councilMembers.length).to.be.equal(expectedCounselors.length);
- expect(councilMembers).to.containSubset(expectedCounselors);
-
- await expectFellowRank(counselors.ildar.address, expectedFellowRank);
- await expectFellowRank(counselors.charu.address, expectedFellowRank);
- await expectFellowRank(counselors.filip.address, expectedFellowRank);
- await expectFellowRank(counselors.irina.address, expectedFellowRank);
- await expectFellowRank(techcomms.greg.address, expectedFellowRank);
- await expectFellowRank(techcomms.andy.address, expectedFellowRank);
- await expectFellowRank(techcomms.constantine.address, expectedFellowRank);
- await expectFellowRank(coreDevs.yaroslav.address, expectedFellowRank);
- await expectFellowRank(coreDevs.daniel.address, expectedFellowRank);
- });
-
- after(async function() {
- await clearFellowship(sudoer);
- await clearTechComm(sudoer);
- await clearCouncil(sudoer);
- });
-});
js-packages/tests/src/governance/technicalCommittee.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/governance/technicalCommittee.test.ts
+++ /dev/null
@@ -1,383 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {Event} from '@unique/playgrounds/src/unique.dev.js';
-import {initCouncil, democracyLaunchPeriod, democracyFastTrackVotingPeriod, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
-import type {ITechComms} from './util.js';
-
-describeGov('Governance: Technical Committee tests', () => {
- let sudoer: IKeyringPair;
- let techcomms: ITechComms;
- let donor: IKeyringPair;
- let preImageHash: string;
-
-
- const allTechCommitteeThreshold = 3;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.TechnicalCommittee]);
- sudoer = await privateKey('//Alice');
- donor = await privateKey({url: import.meta.url});
-
- techcomms = await initTechComm(donor, sudoer);
-
- const proposalCall = await helper.constructApiCall('api.tx.balances.forceSetBalance', [donor.address, 20n * 10n ** 25n]);
- preImageHash = await helper.preimage.notePreimageFromCall(sudoer, proposalCall, true);
- });
- });
-
- after(async () => {
- await usingPlaygrounds(async (helper) => {
- await clearTechComm(sudoer);
-
- await helper.preimage.unnotePreimage(sudoer, preImageHash);
- await hardResetFellowshipReferenda(sudoer);
- await hardResetDemocracy(sudoer);
- await hardResetGovScheduler(sudoer);
- });
- });
-
- function proposalFromAllCommittee(proposal: any) {
- return usingPlaygrounds(async (helper) => {
- expect((await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length).to.be.equal(allTechCommitteeThreshold);
- const proposeResult = await helper.technicalCommittee.collective.propose(
- techcomms.andy,
- proposal,
- allTechCommitteeThreshold,
- );
-
- const commiteeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
- const proposalIndex = commiteeProposedEvent.proposalIndex;
- const proposalHash = commiteeProposedEvent.proposalHash;
-
-
- await helper.technicalCommittee.collective.vote(techcomms.andy, proposalHash, proposalIndex, true);
- await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
- await helper.technicalCommittee.collective.vote(techcomms.greg, proposalHash, proposalIndex, true);
-
- const closeResult = await helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex);
- Event.TechnicalCommittee.Closed.expect(closeResult);
- Event.TechnicalCommittee.Approved.expect(closeResult);
- const {result} = Event.TechnicalCommittee.Executed.expect(closeResult);
- expect(result).to.eq('Ok');
-
- return closeResult;
- });
- }
-
- itSub('TechComm can fast-track Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.wait.parachainBlockMultiplesOf(35n);
-
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- const fastTrackProposal = await proposalFromAllCommittee(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
- Event.Democracy.Started.expect(fastTrackProposal);
- });
-
- itSub('TechComm can cancel Democracy proposals', async ({helper}) => {
- const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
- const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
- const cancelProposal = await proposalFromAllCommittee(helper.democracy.cancelProposalCall(proposalIndex));
- Event.Democracy.ProposalCanceled.expect(cancelProposal);
- });
-
- itSub('TechComm can cancel ongoing Democracy referendums', async ({helper}) => {
- await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const referendumIndex = startedEvent.referendumIndex;
-
- const emergencyCancelProposal = await proposalFromAllCommittee(helper.democracy.emergencyCancelCall(referendumIndex));
- Event.Democracy.Cancelled.expect(emergencyCancelProposal);
- });
-
- itSub('TechComm member can veto Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- const vetoExternalCall = await helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.democracy.vetoExternalCall(preimageHash),
- );
- Event.Democracy.Vetoed.expect(vetoExternalCall);
- });
-
- itSub('TechComm can cancel Fellowship referendums', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const fellowshipProposer = fellowship[5][0];
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- fellowshipProposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
- const cancelProposal = await proposalFromAllCommittee(helper.fellowship.referenda.cancelCall(referendumIndex));
- Event.FellowshipReferenda.Cancelled.expect(cancelProposal);
- });
-
- itSub.skip('TechComm member can add a Fellowship member', async ({helper}) => {
- const newFellowshipMember = helper.arrange.createEmptyAccount();
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
- )).to.be.fulfilled;
- const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
- expect(fellowshipMembers).to.contains(newFellowshipMember.address);
- await clearFellowship(sudoer);
- });
-
- itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
- const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
-
- await expect(proposalFromAllCommittee(councilProposal)).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm cannot externally propose SuperMajorityAgainst', async ({helper}) => {
- const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
-
- await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm cannot externally propose SimpleMajority', async ({helper}) => {
- const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
-
- await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm cannot externally propose SuperMajorityApprove', async ({helper}) => {
- const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
-
- await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot submit regular democracy proposal', async ({helper}) => {
- const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- memberProposal,
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot externally propose SuperMajorityAgainst', async ({helper}) => {
- const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- memberProposal,
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot externally propose SimpleMajority', async ({helper}) => {
- const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- memberProposal,
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot externally propose SuperMajorityApprove', async ({helper}) => {
- const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- memberProposal,
- )).to.be.rejectedWith('BadOrigin');
- });
-
-
- itSub.skip('[Negative] TechComm cannot promote/demote Fellowship member', async () => {
-
- });
-
- itSub.skip('[Negative] TechComm member cannot promote/demote Fellowship member', async () => {
-
- });
-
- itSub('[Negative] TechComm cannot add/remove a Council member', async ({helper}) => {
- const newCouncilMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
- const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
-
- await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
- await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot add/remove a Council member', async ({helper}) => {
- const newCouncilMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
- const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- addMemberProposal,
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- removeMemberProposal,
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm cannot set/clear Council prime member', async ({helper}) => {
- const counselors = await initCouncil(donor, sudoer);
- const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
- const proposalForClear = await helper.council.membership.clearPrimeCall();
-
- await expect(proposalFromAllCommittee(proposalForSet)).to.be.rejectedWith('BadOrigin');
- await expect(proposalFromAllCommittee(proposalForClear)).to.be.rejectedWith('BadOrigin');
- await clearCouncil(sudoer);
- });
-
- itSub('[Negative] TechComm member cannot set/clear Council prime member', async ({helper}) => {
- const counselors = await initCouncil(donor, sudoer);
- const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
- const proposalForClear = await helper.council.membership.clearPrimeCall();
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- proposalForSet,
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- proposalForClear,
- )).to.be.rejectedWith('BadOrigin');
- await clearCouncil(sudoer);
- });
-
- itSub('[Negative] TechComm cannot add/remove a TechComm member', async ({helper}) => {
- const newCommMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
- const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
-
- await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
- await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot add/remove a TechComm member', async ({helper}) => {
- const newCommMember = helper.arrange.createEmptyAccount();
- const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
- const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- addMemberProposal,
- )).to.be.rejectedWith('BadOrigin');
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- removeMemberProposal,
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm cannot remove a Fellowship member', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
-
- await expect(proposalFromAllCommittee(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');
- await clearFellowship(sudoer);
- });
-
- itSub('[Negative] TechComm member cannot remove a Fellowship member', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),
- )).to.be.rejectedWith('BadOrigin');
- await clearFellowship(sudoer);
- });
-
- itSub('[Negative] TechComm member cannot fast-track Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot cancel Democracy proposals', async ({helper}) => {
- const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
- const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.democracy.cancelProposalCall(proposalIndex),
- ))
- .to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot cancel ongoing Democracy referendums', async ({helper}) => {
- await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
- const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
- const referendumIndex = startedEvent.referendumIndex;
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.democracy.emergencyCancelCall(referendumIndex),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm cannot blacklist Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await expect(proposalFromAllCommittee(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm member cannot blacklist Democracy proposals', async ({helper}) => {
- const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
- await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.democracy.blacklistCall(preimageHash),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub.skip('[Negative] TechComm member cannot veto external Democracy proposals until the cool-off period pass', async () => {
-
- });
-
- itSub('[Negative] TechComm member cannot cancel Fellowship referendums', async ({helper}) => {
- const fellowship = await initFellowship(donor, sudoer);
- const fellowshipProposer = fellowship[5][0];
- const proposal = dummyProposal(helper);
-
- const submitResult = await helper.fellowship.referenda.submit(
- fellowshipProposer,
- fellowshipPropositionOrigin,
- proposal,
- defaultEnactmentMoment,
- );
-
- const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
- await expect(helper.technicalCommittee.collective.execute(
- techcomms.andy,
- helper.fellowship.referenda.cancelCall(referendumIndex),
- )).to.be.rejectedWith('BadOrigin');
- });
-
- itSub('[Negative] TechComm referendum cannot be closed until the voting threshold is met', async ({helper}) => {
- const committeeSize = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length as any as number;
- expect(committeeSize).is.greaterThan(1);
- const proposeResult = await helper.technicalCommittee.collective.propose(
- techcomms.andy,
- dummyProposalCall(helper),
- committeeSize,
- );
-
- const committeeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
- const proposalIndex = committeeProposedEvent.proposalIndex;
- const proposalHash = committeeProposedEvent.proposalHash;
-
- await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
-
- await expect(helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
- });
-});
js-packages/tests/src/governance/util.tsdiffbeforeafterboth--- a/js-packages/tests/src/governance/util.ts
+++ /dev/null
@@ -1,224 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {xxhashAsHex} from '@polkadot/util-crypto';
-import type {u32} from '@polkadot/types-codec';
-import {usingPlaygrounds, expect} from '../util/index.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-import {DevUniqueHelper} from '@unique/playgrounds/src/unique.dev.js';
-
-export const democracyLaunchPeriod = 35;
-export const democracyVotingPeriod = 35;
-export const councilMotionDuration = 35;
-export const democracyEnactmentPeriod = 40;
-export const democracyFastTrackVotingPeriod = 5;
-
-export const fellowshipRankLimit = 7;
-export const fellowshipPropositionOrigin = 'FellowshipProposition';
-export const fellowshipPreparePeriod = 3;
-export const fellowshipConfirmPeriod = 3;
-export const fellowshipMinEnactPeriod = 1;
-
-export const defaultEnactmentMoment = {After: 0};
-
-export const democracyTrackId = 10;
-export const democracyTrackMinRank = 3;
-const twox128 = (data: any) => xxhashAsHex(data, 128);
-export interface ICounselors {
- alex: IKeyringPair;
- ildar: IKeyringPair;
- charu: IKeyringPair;
- filip: IKeyringPair;
- irina: IKeyringPair;
-}
-export interface ITechComms {
- greg: IKeyringPair;
- andy: IKeyringPair;
- constantine: IKeyringPair;
-}
-
-export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
- let counselors: IKeyringPair[] = [];
-
- await usingPlaygrounds(async (helper) => {
- const [alex, ildar, charu, filip, irina] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n, 10_000n, 10_000n], donor);
- const sudo = helper.getSudo();
- {
- const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as [];
- if(members.length != 0) {
- await clearCouncil(superuser);
- }
- }
- const expectedMembers = [alex, ildar, charu, filip, irina];
- for(const member of expectedMembers) {
- await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.addMember', [member.address]);
- }
- await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.setPrime', [alex.address]);
- {
- const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
- expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
- expect(members.length).to.be.equal(expectedMembers.length);
- }
-
- counselors = [alex, ildar, charu, filip, irina];
- });
- return {
- alex: counselors[0],
- ildar: counselors[1],
- charu: counselors[2],
- filip: counselors[3],
- irina: counselors[4],
- };
-}
-
-export async function clearCouncil(superuser: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- let members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
- if(members.length) {
- const sudo = helper.getSudo();
- for(const address of members) {
- await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.removeMember', [address]);
- }
- members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
- }
- expect(members).to.be.deep.equal([]);
- });
-}
-
-
-export async function initTechComm(donor: IKeyringPair, superuser: IKeyringPair) {
- let techcomms: IKeyringPair[] = [];
-
- await usingPlaygrounds(async (helper) => {
- const [greg, andy, constantine] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
- const sudo = helper.getSudo();
- {
- const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON() as [];
- if(members.length != 0) {
- await clearTechComm(superuser);
- }
- }
- await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [greg.address]);
- await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [andy.address]);
- await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [constantine.address]);
- await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.setPrime', [greg.address]);
- {
- const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
- expect(members).to.containSubset([greg.address, andy.address, constantine.address]);
- expect(members.length).to.be.equal(3);
- }
-
- techcomms = [greg, andy, constantine];
- });
-
- return {
- greg: techcomms[0],
- andy: techcomms[1],
- constantine: techcomms[2],
- };
-}
-
-export async function clearTechComm(superuser: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- let members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
- if(members.length) {
- const sudo = helper.getSudo();
- for(const address of members) {
- await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.removeMember', [address]);
- }
- members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
- }
- expect(members).to.be.deep.equal([]);
- });
-}
-
-export async function initFellowship(donor: IKeyringPair, sudoer: IKeyringPair) {
- const numMembersInRank = 3;
- const memberBalance = 5000n;
- const members: IKeyringPair[][] = [];
-
- await usingPlaygrounds(async (helper) => {
- const currentFellows = await helper.getApi().query.fellowshipCollective.members.keys();
-
- if(currentFellows.length != 0) {
- await clearFellowship(sudoer);
- }
- for(let i = 0; i < fellowshipRankLimit; i++) {
- const rankMembers = await helper.arrange.createAccounts(
- Array(numMembersInRank).fill(memberBalance),
- donor,
- );
-
- for(const member of rankMembers) {
- await helper.getSudo().fellowship.collective.addMember(sudoer, member.address);
-
- for(let rank = 0; rank < i; rank++) {
- await helper.getSudo().fellowship.collective.promote(sudoer, member.address);
- }
- }
-
- members.push(rankMembers);
- }
- });
-
- return members;
-}
-
-export async function clearFellowship(sudoer: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- const fellowship = (await helper.getApi().query.fellowshipCollective.members.keys())
- .map((key) => key.args[0].toString());
- for(const member of fellowship) {
- await helper.getSudo().fellowship.collective.removeMember(sudoer, member, fellowshipRankLimit);
- }
- });
-}
-
-export async function clearFellowshipReferenda(sudoer: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- const proposalsCount = (await helper.getApi().query.fellowshipReferenda.referendumCount()) as u32;
- for(let i = 0; i < proposalsCount.toNumber(); i++) {
- await helper.getSudo().fellowship.referenda.cancel(sudoer, i);
- }
- });
-}
-
-export async function hardResetFellowshipReferenda(sudoer: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- const api = helper.getApi();
- const prefix = twox128('FellowshipReferenda');
- await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
- });
-}
-
-export async function hardResetDemocracy(sudoer: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- const api = helper.getApi();
- const prefix = twox128('Democracy');
- await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
- });
-}
-
-export async function hardResetGovScheduler(sudoer: IKeyringPair) {
- await usingPlaygrounds(async (helper) => {
- const api = helper.getApi();
- const prefix = twox128('GovScheduler');
- await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 500)));
- });
-}
-
-export async function voteUnanimouslyInFellowship(helper: DevUniqueHelper, fellows: IKeyringPair[][], minRank: number, referendumIndex: number) {
- for(let rank = minRank; rank < fellowshipRankLimit; rank++) {
- for(const member of fellows[rank]) {
- await helper.fellowship.collective.vote(member, referendumIndex, true);
- }
- }
-}
-
-export function dummyProposalCall(helper: UniqueHelper) {
- return helper.constructApiCall('api.tx.system.remark', ['dummy proposal' + (new Date()).getTime()]);
-}
-
-export function dummyProposal(helper: UniqueHelper) {
- return {
- Inline: dummyProposalCall(helper).method.toHex(),
- };
-}
js-packages/tests/src/inflation.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/inflation.seqtest.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from './util/index.js';
-
-// todo:playgrounds requires sudo, look into on the later stage
-describe('integration test: Inflation', () => {
- let superuser: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (_, privateKey) => {
- superuser = await privateKey('//Alice');
- });
- });
-
- itSub('First year inflation is 10%', async ({helper}) => {
- // Make sure non-sudo can't start inflation
- const [bob] = await helper.arrange.createAccounts([10n], superuser);
-
- await expect(helper.executeExtrinsic(bob, 'api.tx.inflation.startInflation', [1])).to.be.rejectedWith(/BadOrigin/);
-
- // Make sure superuser can't start inflation without explicit sudo
- await expect(helper.executeExtrinsic(superuser, 'api.tx.inflation.startInflation', [1])).to.be.rejectedWith(/BadOrigin/);
-
- // Start inflation on relay block 1 (Alice is sudo)
- const tx = helper.constructApiCall('api.tx.inflation.startInflation', [1]);
- await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [tx])).to.not.be.rejected;
-
- const blockInterval = (helper.getApi().consts.inflation.inflationBlockInterval as any).toBigInt();
- const totalIssuanceStart = ((await helper.callRpc('api.query.inflation.startingYearTotalIssuance', [])) as any).toBigInt();
- const blockInflation = (await helper.callRpc('api.query.inflation.blockInflation', []) as any).toBigInt();
-
- const YEAR = 5259600n; // 6-second block. Blocks in one year
- // const YEAR = 2629800n; // 12-second block. Blocks in one year
-
- const totalExpectedInflation = totalIssuanceStart / 10n;
- const totalActualInflation = blockInflation * YEAR / blockInterval;
-
- const tolerance = 0.00001; // Relative difference per year between theoretical and actual inflation
- const expectedInflation = totalExpectedInflation / totalActualInflation - 1n;
-
- expect(Math.abs(Number(expectedInflation))).to.be.lessThanOrEqual(tolerance);
- });
-});
js-packages/tests/src/limits.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/limits.test.ts
+++ /dev/null
@@ -1,474 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util/index.js';
-
-describe('Number of tokens per address (NFT)', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itSub.skip('Collection limits allow greater number than chain limits, chain limits are enforced', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 20});
-
- for(let i = 0; i < 10; i++){
- await expect(collection.mintToken(alice)).to.be.not.rejected;
- }
- await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
- for(let i = 1; i < 11; i++) {
- await expect(collection.burnToken(alice, i)).to.be.not.rejected;
- }
- await collection.burn(alice);
- });
-
- itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 1});
-
- await collection.mintToken(alice);
- await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
-
- await collection.burnToken(alice, 1);
- await expect(collection.burn(alice)).to.be.not.rejected;
- });
-});
-
-describe('Number of tokens per address (ReFungible)', () => {
- let alice: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itSub.skip('Collection limits allow greater number than chain limits, chain limits are enforced', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 20});
-
- for(let i = 0; i < 10; i++){
- await expect(collection.mintToken(alice, 10n)).to.be.not.rejected;
- }
- await expect(collection.mintToken(alice, 10n)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
- for(let i = 1; i < 11; i++) {
- await expect(collection.burnToken(alice, i, 10n)).to.be.not.rejected;
- }
- await collection.burn(alice);
- });
-
- itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 1});
-
- await collection.mintToken(alice);
- await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
-
- await collection.burnToken(alice, 1);
- await expect(collection.burn(alice)).to.be.not.rejected;
- });
-});
-
-// todo:playgrounds skipped ~ postponed
-describe.skip('Sponsor timeout (NFT) (only for special chain limits test)', () => {
- /*let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- alice = privateKeyWrapper('//Alice');
- bob = privateKeyWrapper('//Bob');
- charlie = privateKeyWrapper('//Charlie');
- });
- });
-
- itSub.skip('Collection limits have greater timeout value than chain limits, collection limits are enforced', async ({helper}) => {
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 7});
- const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
- await setCollectionSponsorExpectSuccess(collectionId, alice.address);
- await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
- await transferExpectSuccess(collectionId, tokenId, alice, bob);
- const aliceBalanceBefore = await getFreeBalance(alice);
-
- // check setting SponsorTimeout = 5, fail
- await waitNewBlocks(5);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie);
- const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
-
- // check setting SponsorTimeout = 7, success
- await waitNewBlocks(2); // 5 + 2
- await transferExpectSuccess(collectionId, tokenId, charlie, bob);
- const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
- //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
- await destroyCollectionExpectSuccess(collectionId);
- });
-
- itSub('Collection limits have lower timeout value than chain limits, chain limits are enforced', async ({helper}) => {
-
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 1});
- const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
- await setCollectionSponsorExpectSuccess(collectionId, alice.address);
- await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
- await transferExpectSuccess(collectionId, tokenId, alice, bob);
- const aliceBalanceBefore = await getFreeBalance(alice);
-
- // check setting SponsorTimeout = 1, fail
- await waitNewBlocks(1);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie);
- const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
-
- // check setting SponsorTimeout = 5, success
- await waitNewBlocks(4);
- await transferExpectSuccess(collectionId, tokenId, charlie, bob);
- const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
- //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
- await destroyCollectionExpectSuccess(collectionId);
- });
-});
-
-describe.skip('Sponsor timeout (Fungible) (only for special chain limits test)', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- alice = privateKeyWrapper('//Alice');
- bob = privateKeyWrapper('//Bob');
- charlie = privateKeyWrapper('//Charlie');
- });
- });
-
- itSub('Collection limits have greater timeout value than chain limits, collection limits are enforced', async ({helper}) => {
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 7});
- const tokenId = await createItemExpectSuccess(alice, collectionId, 'Fungible');
- await setCollectionSponsorExpectSuccess(collectionId, alice.address);
- await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
- await transferExpectSuccess(collectionId, tokenId, alice, bob, 10, 'Fungible');
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
- const aliceBalanceBefore = await getFreeBalance(alice);
-
- // check setting SponsorTimeout = 5, fail
- await waitNewBlocks(5);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
- const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
-
- // check setting SponsorTimeout = 7, success
- await waitNewBlocks(2); // 5 + 2
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
- const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
- //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
-
- await destroyCollectionExpectSuccess(collectionId);
- });
-
- itSub('Collection limits have lower timeout value than chain limits, chain limits are enforced', async ({helper}) => {
-
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 1});
- const tokenId = await createItemExpectSuccess(alice, collectionId, 'Fungible');
- await setCollectionSponsorExpectSuccess(collectionId, alice.address);
- await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
- await transferExpectSuccess(collectionId, tokenId, alice, bob, 10, 'Fungible');
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
- const aliceBalanceBefore = await getFreeBalance(alice);
-
- // check setting SponsorTimeout = 1, fail
- await waitNewBlocks(1);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
- const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
-
- // check setting SponsorTimeout = 5, success
- await waitNewBlocks(4);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 2, 'Fungible');
- const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
- //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
-
- await destroyCollectionExpectSuccess(collectionId);
- });
-});
-
-describe.skip('Sponsor timeout (ReFungible) (only for special chain limits test)', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- alice = privateKeyWrapper('//Alice');
- bob = privateKeyWrapper('//Bob');
- charlie = privateKeyWrapper('//Charlie');
- });
- });
-
- itSub('Collection limits have greater timeout value than chain limits, collection limits are enforced', async ({helper}) => {
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
- await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 7});
- const tokenId = await createItemExpectSuccess(alice, collectionId, 'ReFungible');
- await setCollectionSponsorExpectSuccess(collectionId, alice.address);
- await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
- await transferExpectSuccess(collectionId, tokenId, alice, bob, 100, 'ReFungible');
- const aliceBalanceBefore = await getFreeBalance(alice);
-
- // check setting SponsorTimeout = 5, fail
- await waitNewBlocks(5);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 20, 'ReFungible');
- const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
-
- // check setting SponsorTimeout = 7, success
- await waitNewBlocks(2); // 5 + 2
- await transferExpectSuccess(collectionId, tokenId, bob, charlie, 20, 'ReFungible');
- const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
- //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
- await destroyCollectionExpectSuccess(collectionId);
- });
-
- itSub('Collection limits have lower timeout value than chain limits, chain limits are enforced', async ({helper}) => {
-
- const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
- await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorTransferTimeout: 1});
- const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
- await setCollectionSponsorExpectSuccess(collectionId, alice.address);
- await confirmSponsorshipExpectSuccess(collectionId, '//Alice');
- await transferExpectSuccess(collectionId, tokenId, alice, bob);
- const aliceBalanceBefore = await getFreeBalance(alice);
-
- // check setting SponsorTimeout = 1, fail
- await waitNewBlocks(1);
- await transferExpectSuccess(collectionId, tokenId, bob, charlie);
- const aliceBalanceAfterUnsponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);
-
- // check setting SponsorTimeout = 5, success
- await waitNewBlocks(4);
- await transferExpectSuccess(collectionId, tokenId, charlie, bob);
- const aliceBalanceAfterSponsoredTransaction = await getFreeBalance(alice);
- expect(aliceBalanceAfterSponsoredTransaction < aliceBalanceBefore).to.be.true;
- //expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);
- await destroyCollectionExpectSuccess(collectionId);
- });*/
-});
-
-describe('Collection zero limits (NFT)', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itSub.skip('Limits have 0 in tokens per address field, the chain limits are applied', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 0});
-
- for(let i = 0; i < 10; i++){
- await collection.mintToken(alice);
- }
- await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
- });
-
- itSub('Limits have 0 in sponsor timeout, no limits are applied', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setLimits(alice, {sponsorTransferTimeout: 0});
- const token = await collection.mintToken(alice);
-
- await collection.setSponsor(alice, alice.address);
- await collection.confirmSponsorship(alice);
-
- await token.transfer(alice, {Substrate: bob.address});
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-
- // check setting SponsorTimeout = 0, success with next block
- await helper.wait.newBlocks(1);
- await token.transfer(bob, {Substrate: charlie.address});
- const aliceBalanceAfterSponsoredTransaction1 = await helper.balance.getSubstrate(alice.address);
- expect(aliceBalanceAfterSponsoredTransaction1 < aliceBalanceBefore).to.be.true;
- });
-});
-
-describe('Collection zero limits (Fungible)', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itSub('Limits have 0 in sponsor timeout, no limits are applied', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {});
- await collection.setLimits(alice, {sponsorTransferTimeout: 0});
- await collection.mint(alice, 3n);
-
- await collection.setSponsor(alice, alice.address);
- await collection.confirmSponsorship(alice);
-
- await collection.transfer(alice, {Substrate: bob.address}, 2n);
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-
- // check setting SponsorTimeout = 0, success with next block
- await helper.wait.newBlocks(1);
- await collection.transfer(bob, {Substrate: charlie.address});
- const aliceBalanceAfterSponsoredTransaction1 = await helper.balance.getSubstrate(alice.address);
- expect(aliceBalanceAfterSponsoredTransaction1 < aliceBalanceBefore).to.be.true;
- });
-});
-
-describe('Collection zero limits (ReFungible)', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- });
- });
-
- itSub.skip('Limits have 0 in tokens per address field, the chain limits are applied', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- await collection.setLimits(alice, {accountTokenOwnershipLimit: 0});
- for(let i = 0; i < 10; i++){
- await collection.mintToken(alice);
- }
- await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/);
- });
-
- itSub('Limits have 0 in sponsor timeout, no limits are applied', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- await collection.setLimits(alice, {sponsorTransferTimeout: 0});
- const token = await collection.mintToken(alice, 3n);
-
- await collection.setSponsor(alice, alice.address);
- await collection.confirmSponsorship(alice);
-
- await token.transfer(alice, {Substrate: bob.address}, 2n);
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-
- // check setting SponsorTimeout = 0, success with next block
- await helper.wait.newBlocks(1);
- await token.transfer(bob, {Substrate: charlie.address});
- const aliceBalanceAfterSponsoredTransaction1 = await helper.balance.getSubstrate(alice.address);
- expect(aliceBalanceAfterSponsoredTransaction1 < aliceBalanceBefore).to.be.true;
- });
-});
-
-describe('Effective collection limits (NFT)', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itSub('Effective collection limits', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {});
- await collection.setLimits(alice, {ownerCanTransfer: true});
-
- {
- // Check that limits are undefined
- const collectionInfo = await collection.getData();
- const limits = collectionInfo?.raw.limits;
- expect(limits).to.be.any;
-
- expect(limits.accountTokenOwnershipLimit).to.be.null;
- expect(limits.sponsoredDataSize).to.be.null;
- expect(limits.sponsoredDataRateLimit).to.be.null;
- expect(limits.tokenLimit).to.be.null;
- expect(limits.sponsorTransferTimeout).to.be.null;
- expect(limits.sponsorApproveTimeout).to.be.null;
- expect(limits.ownerCanTransfer).to.be.true;
- expect(limits.ownerCanDestroy).to.be.null;
- expect(limits.transfersEnabled).to.be.null;
- }
-
- { // Check that limits is undefined for non-existent collection
- const limits = await helper.collection.getEffectiveLimits(999999);
- expect(limits).to.be.null;
- }
-
- { // Check that default values defined for collection limits
- const limits = await collection.getEffectiveLimits();
-
- expect(limits.accountTokenOwnershipLimit).to.be.eq(100000);
- expect(limits.sponsoredDataSize).to.be.eq(2048);
- expect(limits.sponsoredDataRateLimit).to.be.deep.eq({sponsoringDisabled: null});
- expect(limits.tokenLimit).to.be.eq(4294967295);
- expect(limits.sponsorTransferTimeout).to.be.eq(5);
- expect(limits.sponsorApproveTimeout).to.be.eq(5);
- expect(limits.ownerCanTransfer).to.be.true;
- expect(limits.ownerCanDestroy).to.be.true;
- expect(limits.transfersEnabled).to.be.true;
- }
-
- {
- // Check the values for collection limits
- await collection.setLimits(alice, {
- accountTokenOwnershipLimit: 99_999,
- sponsoredDataSize: 1024,
- tokenLimit: 123,
- transfersEnabled: false,
- });
-
- const limits = await collection.getEffectiveLimits();
-
- expect(limits.accountTokenOwnershipLimit).to.be.eq(99999);
- expect(limits.sponsoredDataSize).to.be.eq(1024);
- expect(limits.sponsoredDataRateLimit).to.be.deep.eq({sponsoringDisabled: null});
- expect(limits.tokenLimit).to.be.eq(123);
- expect(limits.sponsorTransferTimeout).to.be.eq(5);
- expect(limits.sponsorApproveTimeout).to.be.eq(5);
- expect(limits.ownerCanTransfer).to.be.true;
- expect(limits.ownerCanDestroy).to.be.true;
- expect(limits.transfersEnabled).to.be.false;
- }
- });
-});
js-packages/tests/src/maintenance.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/maintenance.seqtest.ts
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {ApiPromise} from '@polkadot/api';
-import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util/index.js';
-import {itEth} from './eth/util/index.js';
-import {main as correctState} from './migrations/correctStateAfterMaintenance.js';
-import type {PalletBalancesIdAmount} from '@polkadot/types/lookup';
-import type {Vec} from '@polkadot/types-codec';
-
-async function maintenanceEnabled(api: ApiPromise): Promise<boolean> {
- return (await api.query.maintenance.enabled()).toJSON() as boolean;
-}
-
-describe('Integration Test: Maintenance Functionality', () => {
- let superuser: IKeyringPair;
- let donor: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Maintenance]);
- superuser = await privateKey('//Alice');
- donor = await privateKey({url: import.meta.url});
- [bob] = await helper.arrange.createAccounts([10000n], donor);
-
- });
- });
-
- describe('Maintenance Mode', () => {
- before(async function() {
- await usingPlaygrounds(async (helper) => {
- if(await maintenanceEnabled(helper.getApi())) {
- console.warn('\tMaintenance mode was left enabled BEFORE the test suite! Disabling it now.');
- await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', [])).to.be.fulfilled;
- }
- });
- });
-
- itSub('Allows superuser to enable and disable maintenance mode - and disallows anyone else', async ({helper}) => {
- // Make sure non-sudo can't enable maintenance mode
- await expect(helper.executeExtrinsic(superuser, 'api.tx.maintenance.enable', []), 'on commoner enabling MM')
- .to.be.rejectedWith(/BadOrigin/);
-
- // Set maintenance mode
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- // Make sure non-sudo can't disable maintenance mode
- await expect(helper.executeExtrinsic(bob, 'api.tx.maintenance.disable', []), 'on commoner disabling MM')
- .to.be.rejectedWith(/BadOrigin/);
-
- // Disable maintenance mode
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
- });
-
- itSub('MM blocks unique pallet calls', async ({helper}) => {
- // Can create an NFT collection before enabling the MM
- const nftCollection = await helper.nft.mintCollection(bob, {
- tokenPropertyPermissions: [{
- key: 'test', permission: {
- collectionAdmin: true,
- tokenOwner: true,
- mutable: true,
- },
- }],
- });
-
- // Can mint an NFT before enabling the MM
- const nft = await nftCollection.mintToken(bob);
-
- // Can create an FT collection before enabling the MM
- const ftCollection = await helper.ft.mintCollection(superuser);
-
- // Can mint an FT before enabling the MM
- await expect(ftCollection.mint(superuser)).to.be.fulfilled;
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- // Unable to create a collection when the MM is enabled
- await expect(helper.nft.mintCollection(superuser), 'cudo forbidden stuff')
- .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
-
- // Unable to set token properties when the MM is enabled
- await expect(nft.setProperties(
- bob,
- [{key: 'test', value: 'test-val'}],
- )).to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
-
- // Unable to mint an NFT when the MM is enabled
- await expect(nftCollection.mintToken(superuser))
- .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
-
- // Unable to mint an FT when the MM is enabled
- await expect(ftCollection.mint(superuser))
- .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
-
- // Can create a collection after disabling the MM
- await expect(helper.nft.mintCollection(bob), 'MM is disabled, the collection should be created').to.be.fulfilled;
-
- // Can set token properties after disabling the MM
- await nft.setProperties(bob, [{key: 'test', value: 'test-val'}]);
-
- // Can mint an NFT after disabling the MM
- await nftCollection.mintToken(bob);
-
- // Can mint an FT after disabling the MM
- await ftCollection.mint(superuser);
- });
-
- itSub.ifWithPallets('MM blocks unique pallet calls (Re-Fungible)', [Pallets.ReFungible], async ({helper}) => {
- // Can create an RFT collection before enabling the MM
- const rftCollection = await helper.rft.mintCollection(superuser);
-
- // Can mint an RFT before enabling the MM
- await expect(rftCollection.mintToken(superuser)).to.be.fulfilled;
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- // Unable to mint an RFT when the MM is enabled
- await expect(rftCollection.mintToken(superuser))
- .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
-
- // Can mint an RFT after disabling the MM
- await rftCollection.mintToken(superuser);
- });
-
- itSub('MM allows native token transfers and RPC calls', async ({helper}) => {
- // We can use RPC before the MM is enabled
- const totalCount = await helper.collection.getTotalCount();
-
- // We can transfer funds before the MM is enabled
- await expect(helper.balance.transferToSubstrate(superuser, bob.address, 2n)).to.be.fulfilled;
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- // RPCs work while in maintenance
- expect(await helper.collection.getTotalCount()).to.be.deep.equal(totalCount);
-
- // We still able to transfer funds
- await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled;
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
-
- // RPCs work after maintenance
- expect(await helper.collection.getTotalCount()).to.be.deep.equal(totalCount);
-
- // Transfers work after maintenance
- await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled;
- });
-
- itSched.ifWithPallets('MM blocks scheduled calls and the scheduler itself', [Pallets.UniqueScheduler], async (scheduleKind, {helper}) => {
- const collection = await helper.nft.mintCollection(bob);
-
- const nftBeforeMM = await collection.mintToken(bob);
- const nftDuringMM = await collection.mintToken(bob);
- const nftAfterMM = await collection.mintToken(bob);
-
- const [
- scheduledIdBeforeMM,
- scheduledIdDuringMM,
- scheduledIdBunkerThroughMM,
- scheduledIdAttemptDuringMM,
- scheduledIdAfterMM,
- ] = scheduleKind == 'named'
- ? helper.arrange.makeScheduledIds(5)
- : new Array(5);
-
- const blocksToWait = 6;
-
- // Scheduling works before the maintenance
- await helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdBeforeMM})
- .nft.transferToken(bob, collection.collectionId, nftBeforeMM.tokenId, {Substrate: superuser.address});
-
-
- await helper.wait.newBlocks(blocksToWait + 1);
- expect(await nftBeforeMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});
-
- // Schedule a transaction that should occur *during* the maintenance
- await helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdDuringMM})
- .nft.transferToken(bob, collection.collectionId, nftDuringMM.tokenId, {Substrate: superuser.address});
-
-
- // Schedule a transaction that should occur *after* the maintenance
- await helper.scheduler.scheduleAfter(blocksToWait * 2, {scheduledId: scheduledIdBunkerThroughMM})
- .nft.transferToken(bob, collection.collectionId, nftDuringMM.tokenId, {Substrate: superuser.address});
-
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- await helper.wait.newBlocks(blocksToWait + 1);
- // The owner should NOT change since the scheduled transaction should be rejected
- expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: bob.address});
-
- // Any attempts to schedule a tx during the MM should be rejected
- await expect(helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAttemptDuringMM})
- .nft.transferToken(bob, collection.collectionId, nftDuringMM.tokenId, {Substrate: superuser.address}))
- .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
-
- // Scheduling works after the maintenance
- await helper.scheduler.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAfterMM})
- .nft.transferToken(bob, collection.collectionId, nftAfterMM.tokenId, {Substrate: superuser.address});
-
- await helper.wait.newBlocks(blocksToWait + 1);
-
- expect(await nftAfterMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});
- // The owner of the token scheduled for transaction *before* maintenance should now change *after* maintenance
- expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});
- });
-
- itEth('Disallows Ethereum transactions to execute while in maintenance', async ({helper}) => {
- const owner = await helper.eth.createAccountWithBalance(donor);
- const receiver = helper.eth.createAccount();
-
- const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'B', 'C', '');
-
- // Set maintenance mode
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
- const tokenId = await contract.methods.nextTokenId().call();
- expect(tokenId).to.be.equal('1');
-
- await expect(contract.methods.mintWithTokenURI(receiver, 'Test URI').send())
- .to.be.rejectedWith(/Returned error: unknown error/);
-
- await expect(contract.methods.ownerOf(tokenId).call()).rejectedWith(/token not found/);
-
- // Disable maintenance mode
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
- });
-
- itSub('Allows to enable and disable MM repeatedly', async ({helper}) => {
- // Set maintenance mode
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true;
-
- // Disable maintenance mode
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;
- });
-
- afterEach(async () => {
- await usingPlaygrounds(async helper => {
- if(helper.fetchMissingPalletNames([Pallets.Maintenance]).length != 0) return;
- if(await maintenanceEnabled(helper.getApi())) {
- console.warn('\tMaintenance mode was left enabled AFTER a test has finished! Be careful. Disabling it now.');
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- }
- expect(await maintenanceEnabled(helper.getApi()), 'Disastrous! Exited the test suite with maintenance mode on.').to.be.false;
- });
- });
- });
-
- describe('Integration Test: Maintenance mode & App Promo', () => {
- let superuser: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.Maintenance]);
- superuser = await privateKey('//Alice');
- });
- });
-
- describe('Test AppPromo script for check state after Maintenance mode', () => {
- before(async function () {
- await usingPlaygrounds(async (helper) => {
- if(await maintenanceEnabled(helper.getApi())) {
- console.warn('\tMaintenance mode was left enabled BEFORE the test suite! Disabling it now.');
- await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', [])).to.be.fulfilled;
- }
- });
- });
- itSub('Can find and fix inconsistent state', async ({helper}) => {
- const api = helper.getApi();
-
- await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.system.setStorage([
- // pendingUnstake(1 -> [superuser.address, 100UNQ])
- ['0x42b67acb8bd223c60d0c8f621ffefc0ae280fa2db99bd3827aac976de75af95f5153cb1f00942ff401000000',
- '0x04d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d000010632d5ec76b0500000000000000'],
- // pendingUnstake(2 -> [superuser.address, 100UNQ])
- ['0x42b67acb8bd223c60d0c8f621ffefc0ae280fa2db99bd3827aac976de75af95f9eb2dcce60f37a2702000000',
- '0x04d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d000010632d5ec76b0500000000000000'],
- // Balances.freezes(superuser.address -> freeze with app promo id and 200 UNQ )
- ['0xc2261276cc9d1f8598ea4b6a74b15c2fb1c0eb12e038e5c7f91e120ed4b7ebf1de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d',
- '0x046170707374616b656170707374616b65000020c65abc8ed70a00000000000000'],
- ])]);
-
- expect((await api.query.appPromotion.pendingUnstake(1)).toJSON()).to.be.deep.equal([[superuser.address, '0x00000000000000056bc75e2d63100000']]);
- expect((await api.query.appPromotion.pendingUnstake(2)).toJSON()).to.be.deep.equal([[superuser.address, '0x00000000000000056bc75e2d63100000']]);
- expect((await api.query.balances.freezes(superuser.address) as Vec<PalletBalancesIdAmount>)
- .map(lock => ({id: lock.id.toUtf8(), amount: lock.amount.toBigInt()})))
- .to.be.deep.equal([{id: 'appstakeappstake', amount: 200000000000000000000n}]);
- await correctState();
-
- expect((await api.query.appPromotion.pendingUnstake(1)).toJSON()).to.be.deep.equal([]);
- expect((await api.query.appPromotion.pendingUnstake(2)).toJSON()).to.be.deep.equal([]);
- expect((await api.query.balances.freezes(superuser.address)).toJSON()).to.be.deep.equal([]);
-
- });
-
- itSub('(!negative test!) Only works when Maintenance mode is disabled', async({helper}) => {
- await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', [])).to.be.fulfilled;
- await expect(correctState()).to.be.rejectedWith('The network is still in maintenance mode');
- await expect(helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', [])).to.be.fulfilled;
- });
- });
- });
-
- after(async () => {
- await usingPlaygrounds(async(helper) => {
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);
- });
- });
-});
js-packages/tests/src/migrations/942057-appPromotion/README.mddiffbeforeafterboth--- a/js-packages/tests/src/migrations/942057-appPromotion/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Update Procedure
-
-- Enable maintenance mode
-- [Collect migration data using ChainQL](#stakers-data-loading)
-- ❗️❗️❗️ Initiate the runtime upgrade only at this point ❗️❗️❗️
-- Wait for the upgrade to complete
-- [Execute offchain migration](#execute-offchain-migration)
-- Disable maintenance mode
-
-## Stakers Data Loading
-
-Set the environment variable (WS_RPC). For example, ws://localhost:9944. Execute the following command:
-
-```sh
-chainql --tla-str=chainUrl=<WS_RPC> stakersParser.jsonnet > output.json
-```
-
-where `<WS_RPC>` - is the network address.
-
-Example for Opal:
-
-```sh
-chainql --tla-str=chainUrl=wss://eu-ws-opal.unique.network:443 stakersParser.jsonnet > output.json
-```
-
-To install chainql, execute the following command:
-
-```sh
-cargo install chainql
-```
-
-## Execute offchain migration
-
-To run, you need to set an environment variables:
-- `SUPERUSER_SEED` – the sudo key seed.
-- `WS_RPC` – the network address
-
-Run the migration by executing the following command:
-
-```sh
-npx ts-node --esm executeMigration.ts
-```
js-packages/tests/src/migrations/942057-appPromotion/collectData.tsdiffbeforeafterboth--- a/js-packages/tests/src/migrations/942057-appPromotion/collectData.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import {exec} from 'child_process';
-import path from 'path';
-import {dirname} from 'path';
-import {fileURLToPath} from 'url';
-
-export const collectData = () => {
- const dirName = dirname(fileURLToPath(import.meta.url));
-
- const pathToScript = path.resolve(dirName, './stakersParser.jsonnet');
- const outputPath = path.resolve(dirName, './output.json');
- exec(`chainql --tla-str=chainUrl=ws://127.0.0.1:9944 ${pathToScript} > ${outputPath}`);
-};
js-packages/tests/src/migrations/942057-appPromotion/executeMigration.tsdiffbeforeafterboth--- a/js-packages/tests/src/migrations/942057-appPromotion/executeMigration.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import {migrateLockedToFreeze} from './lockedToFreeze.js';
-
-
-const WS_RPC = process.env.WS_RPC || 'wss://ws-opal.unique.network:443';
-const SUPERUSER_SEED = process.env.SUPERUSER_SEED || '';
-
-migrateLockedToFreeze({
- wsEndpoint: WS_RPC,
- donorSeed: SUPERUSER_SEED,
-})
- .catch(console.error);
\ No newline at end of file
js-packages/tests/src/migrations/942057-appPromotion/index.tsdiffbeforeafterboth--- a/js-packages/tests/src/migrations/942057-appPromotion/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import type {Migration} from '../../util/frankensteinMigrate.js';
-import {collectData} from './collectData.js';
-import {migrateLockedToFreeze} from './lockedToFreeze.js';
-
-export const migration: Migration = {
- async before() {
- await collectData();
- },
- async after() {
- await migrateLockedToFreeze();
- },
-};
\ No newline at end of file
js-packages/tests/src/migrations/942057-appPromotion/lockedToFreeze.tsdiffbeforeafterboth--- a/js-packages/tests/src/migrations/942057-appPromotion/lockedToFreeze.ts
+++ /dev/null
@@ -1,259 +0,0 @@
-// import { usingApi, privateKey, onlySign } from "./../../load/lib";
-import * as fs from 'fs';
-import {usingPlaygrounds} from '../../util/index.js';
-import path, {dirname} from 'path';
-import {isInteger, parse} from 'lossless-json';
-import {fileURLToPath} from 'url';
-import config from '../../config.js';
-
-
-const WS_ENDPOINT = config.substrateUrl;
-const DONOR_SEED = '//Alice';
-const UPDATE_IF_VERSION = 942057;
-
-export function customNumberParser(value: any) {
- return isInteger(value) ? BigInt(value) : parseFloat(value);
-}
-
-export const migrateLockedToFreeze = async(options: { wsEndpoint: string; donorSeed: string } = {
- wsEndpoint: WS_ENDPOINT,
- donorSeed: DONOR_SEED,
-}) => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const api = helper.getApi();
- // 1. Check version equal 942057 or skip
- console.log((api.consts.system.version as any).specVersion.toNumber());
- if((api.consts.system.version as any).specVersion.toNumber() != UPDATE_IF_VERSION) {
- console.log("Version isn't 942057.");
- return;
- }
-
- // 2. Get sudo signer
- const signer = await privateKey(options.donorSeed);
- console.log('2. Getting sudo:', signer.address);
-
- // 3. Parse data to migrate
- console.log('3. Parsing chainql results...');
- const dirName = dirname(fileURLToPath(import.meta.url));
- const parsingResult = parse(fs.readFileSync(path.resolve(dirName, 'output.json'), 'utf-8'), undefined, customNumberParser);
-
- const chainqlImportData = parsingResult as {
- address: string;
- balance: string;
- account: {
- fee_frozen: string,
- free: string,
- misc_frozen: string,
- reserved: string,
- },
- locks: {
- amount: string,
- id: string,
- }[],
- stakes: object,
- unstakes: object,
- }[];
- testChainqlData(chainqlImportData);
-
- const stakers = chainqlImportData.map((i) => i.address);
-
- // 3.1 Split into chunks by 100
- console.log('3.1 Splitting into chunks...');
- const stakersChunks = chunk(stakers, 100);
- console.log('3.1 Done, total chunks:', stakersChunks.length);
-
- // 4. Get signer/sudo nonce
- console.log('4. Getting sudo nonce...');
- const signerAccount = (
- await api.query.system.account(signer.address)
- ).toJSON() as any;
-
- let nonce: number = signerAccount.nonce;
- console.log('4. Sudo nonce is:', nonce);
-
- // 5. Only sign upgradeAccounts-transactions for each chunk
- console.log('5. Signing transactions...');
- const signedTxs = [];
- for(const chunk of stakersChunks) {
- const tx = api.tx.sudo.sudo(api.tx.appPromotion.upgradeAccounts(chunk));
- const signed = tx.sign(signer, {
- blockHash: api.genesisHash,
- genesisHash: api.genesisHash,
- runtimeVersion: api.runtimeVersion,
- nonce: nonce++,
- });
- signedTxs.push(signed);
- }
-
- // 6. Send all signed transactions
- console.log('6. Sending transactions...');
- const promises = signedTxs.map((tx) => api.rpc.author.submitAndWatchExtrinsic(tx));
- // 6.1 Wait all transactions settled
- console.log('6.1 Waiting all transactions settled...');
- const res = await Promise.allSettled(promises);
-
- console.log('Wait 5 blocks for transactions to be included in a block...');
- await helper.wait.newBlocks(5);
- // 6.2 Filter failed transactions
- console.log('6.2 Getting failed transactions...');
- const failedTx = res.filter((r) => r.status == 'rejected') as PromiseRejectedResult[];
- console.log('6.2. total failedTxs:', failedTx.length);
-
- // 6.3 Log the reasons of failed tx
- for(const tx of failedTx) {
- console.log(tx.reason);
- }
-
- // 7. Check balances for 10 blocks:
- console.log('7. Check balances...');
- let blocksLeft = 10;
- let notMigrated = stakers;
- const suspiciousAccounts = [];
- do {
- console.log('blocks left:', blocksLeft);
- const _notMigrated: string[] = [];
- console.log('accounts to migrate...', notMigrated.length);
- for(const accountToMigrate of notMigrated) {
- let accountMigrated = true;
- // 7.0 get data from chainql:
- const oldAccount = chainqlImportData.find(acc => acc.address === accountToMigrate);
- if(!oldAccount) {
- console.log('Cannot find old account data for', accountMigrated);
- accountMigrated = false;
- _notMigrated.push(accountToMigrate);
- continue;
- }
-
- // 7.1 system.account
- const balance = await api.query.system.account(accountToMigrate) as any;
- // new balances
- const free = balance.data.free;
- const reserved = balance.data.reserved;
- const frozen = balance.data.frozen;
- // old balances
- const oldFree = oldAccount.account.free;
- const oldReserved = oldAccount.account.reserved;
- const oldFrozen = oldAccount.account.fee_frozen;
- // asserts new = old
- if(oldFree.toString() !== free.toString()) {
- console.log('Old free !== New free, which is probably not a problem', oldFree.toString(), free.toString());
- suspiciousAccounts.push(accountToMigrate);
- }
- if(oldFrozen.toString() !== frozen.toString()) {
- console.log('Old frozen !== New frozen, which is probably not a problem', oldFrozen.toString(), frozen.toString());
- suspiciousAccounts.push(accountToMigrate);
- }
- if(oldReserved.toString() !== reserved.toString()) {
- console.log('Old reserved !== New reserved, which is probably not a problem', oldReserved.toString(), reserved.toString());
- suspiciousAccounts.push(accountToMigrate);
- }
-
- // 7.2 balances.locks: no id appstake
- const locks = await helper.balance.getLocked(accountToMigrate);
- const appPromoLocks = locks.filter(lock => lock.id === 'appstake');
- if(appPromoLocks.length !== 0) {
- console.log('Account still has app-promo lock');
- accountMigrated = false;
- }
-
- // 7.3 balances.freezes set...
- let freezes = await api.query.balances.freezes(accountToMigrate) as any;
- freezes = freezes.map((freez: any) => ({id: freez.id.toString(), amount: freez.amount.toString()}));
- if(!freezes) {
- console.log('Account does not have freezes');
- accountMigrated = false;
- } else {
- const oldAppPromoLocks = oldAccount.locks.filter(l => l.id === '0x6170707374616b65'); // get app promo locks
- // should be only one freez for each account
- if(freezes.length !== 1) {
- console.log('freezes.length !== 1 and old appPromoLocks.length', freezes.length, oldAppPromoLocks.length);
- accountMigrated = false;
- } else {
- const appPromoFreez = freezes[0];
- // freez-amount should be equal to migrated lock amount
- if(appPromoFreez.amount.toString() !== oldAppPromoLocks[0].amount.toString()) {
- console.log('freezes amount !== old appPromoLocks amount', appPromoFreez.amount.toString(), oldAppPromoLocks[0].amount.toString());
- accountMigrated = false;
- }
- // freez id should be correct
- if(appPromoFreez.id !== '0x6170707374616b656170707374616b65') {
- console.log('Got freez with incorrect id:', appPromoFreez.id);
- accountMigrated = false;
- }
- }
- }
-
- // 7.4 Stakes number the same
- const stakesNumber = await helper.staking.getStakesNumber({Substrate: accountToMigrate});
- const oldStakesNumber = oldAccount.stakes ? Object.keys(oldAccount.stakes).length : 0;
- if(stakesNumber.toString() !== oldStakesNumber.toString()) {
- console.log('Old stakes number !== New stakes number', oldStakesNumber, stakesNumber);
- accountMigrated = false;
- }
-
- // 7.5 Total pendingUnstake + total staked = old locked
- const pendingUnstakes = await helper.staking.getPendingUnstake({Substrate: accountToMigrate});
- const totalStaked = await helper.staking.getTotalStaked({Substrate: accountToMigrate});
- const totalBalanceInAppPromo = pendingUnstakes + totalStaked;
- if(totalBalanceInAppPromo.toString() !== oldAccount.balance.toString()) {
- console.log('totalBalanceInAppPromo !== old locked in app promo', totalBalanceInAppPromo.toString(), oldAccount.balance.toString());
- accountMigrated = false;
- }
-
- // 8 Add to not-migrated
- if(!accountMigrated) {
- console.log('Add to not migrated:', accountToMigrate);
- _notMigrated.push(accountToMigrate);
- }
- }
-
- blocksLeft--;
- notMigrated = _notMigrated;
- await helper.wait.newBlocks(1);
- } while(blocksLeft > 0 && notMigrated.length !== 0);
-
- console.log('Not migrated accounts...', notMigrated.length);
- if(suspiciousAccounts.length > 0) {
- console.log('Saving suspicious accounts to suspicious.json:');
- fs.writeFileSync('./suspicious.json', JSON.stringify(suspiciousAccounts));
- }
- if(notMigrated.length > 0) {
- console.log('Saving not migrated list to failed.json:');
- notMigrated.forEach(console.log);
- fs.writeFileSync('./failed.json', JSON.stringify(notMigrated));
- process.exit(1);
- } else {
- console.log('Migration success');
- }
- }, options.wsEndpoint);
-};
-
-const chunk = <T>(arr: T[], size: number) =>
- Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
- arr.slice(i * size, i * size + size));
-
-const testChainqlData = (data: any) => {
- const wrongData = [];
- for(const account of data) {
- try {
- if(account.address == null) throw Error('no address in data');
- if(account.balance == null) throw Error('no balance in data');
- if(account.account == null) throw Error('no account in data');
- if(account.account.fee_frozen == null) throw Error('no account.fee_frozen in data');
- if(account.account.misc_frozen == null) throw Error('no account.misc_frozen in data');
- if(account.account.free == null) throw Error('no account.free in data');
- if(account.account.reserved == null) throw Error('no account.reserved in data');
- if(account.locks == null) throw Error('no locks in data');
- if(account.locks[0].amount == null) throw Error('no locks.amount in data');
- if(account.locks[0].id == null) throw Error('no locks.id in data');
- } catch (error) {
- wrongData.push(account.address);
- console.log((error as Error).message, account.address);
- }
- if(wrongData.length > 0) {
- console.log(data);
- throw Error('Chainql data not correct');
- }
- }
- console.log('Chainql data correct');
-};
js-packages/tests/src/migrations/942057-appPromotion/stakersParser.jsonnetdiffbeforeafterboth--- a/js-packages/tests/src/migrations/942057-appPromotion/stakersParser.jsonnet
+++ /dev/null
@@ -1,29 +0,0 @@
-function(chainUrl)
-
- local
- state = cql.chain(chainUrl).latest,
- locked_balances = state.Balances.Locks._preloadKeys,
- accountsRaw = state.System.Account._preloadKeys,
- stakers = state.AppPromotion.Staked._preloadKeys,
- unstakes = state.AppPromotion.PendingUnstake._preloadKeys,
- locks = [
- { [k]: std.filter(function(l) l.id == '0x6170707374616b65', locked_balances[k]) }
- for k in std.objectFields(locked_balances)
- ],
- unstakersData = [
- { [pair[0]]: { block: block, value: pair[1] } }
-
- for block in std.objectFields(unstakes)
- for pair in unstakes[block]
- ],
- non_empty_locks = std.prune(locks)
- ;
-
- std.map(function(a) {
- address: std.objectFields(a)[0],
- balance: a[std.objectFields(a)[0]][0].amount,
- account: accountsRaw[std.objectFields(a)[0]].data,
- locks: locked_balances[std.objectFields(a)[0]],
- stakes: if std.objectHas(stakers, std.objectFields(a)[0]) then stakers[std.objectFields(a)[0]] else null,
- unstakes: std.filterMap(function(b) std.objectHas(b, std.objectFields(a)[0]), function(c) std.objectValues(c)[0], unstakersData),
- }, non_empty_locks)
js-packages/tests/src/migrations/correctStateAfterMaintenance.tsdiffbeforeafterboth--- a/js-packages/tests/src/migrations/correctStateAfterMaintenance.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import config from '../config.js';
-import {usingPlaygrounds} from '../util/index.js';
-import type {u32} from '@polkadot/types-codec';
-
-const WS_ENDPOINT = config.substrateUrl;
-const DONOR_SEED = '//Alice';
-
-export const main = async(options: { wsEndpoint: string; donorSeed: string } = {
- wsEndpoint: WS_ENDPOINT,
- donorSeed: DONOR_SEED,
-}) => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const api = helper.getApi();
-
- if((await api.query.maintenance.enabled()).valueOf()) {
- throw Error('The network is still in maintenance mode');
- }
-
- const pendingBlocks = (
- await api.query.appPromotion.pendingUnstake.entries()
- ).map(([k, _v]) =>
- (k.args[0] as u32).toNumber());
-
- const currentBlock = (await api.query.system.number() as u32).toNumber();
-
- const filteredBlocks = pendingBlocks.filter(b => currentBlock > b);
-
- if(filteredBlocks.length != 0) {
- console.log(`During maintenance mode, ${filteredBlocks.length} block(s) were not processed. Number(s): ${filteredBlocks}`);
- } else {
- console.log('Nothing to change');
- return;
- }
-
- const skippedBlocks = chunk(filteredBlocks, 10);
-
- const signer = await privateKey(options.donorSeed);
-
- const txs = skippedBlocks.map((b) =>
- api.tx.sudo.sudo(api.tx.appPromotion.forceUnstake(b)));
-
-
- const promises = txs.map((tx) => () => helper.signTransaction(signer, tx));
-
- await Promise.allSettled(promises.map((p) => p()));
-
- const failedBlocks: number[] = [];
- let isSuccess = true;
-
- for(const b of filteredBlocks) {
- if(((await api.query.appPromotion.pendingUnstake(b)).toJSON() as any[]).length != 0) {
- failedBlocks.push(b);
- isSuccess = false;
- }
- }
-
- if(isSuccess) {
- console.log('Done. %d block(s) were processed.', filteredBlocks.length);
- } else {
- throw new Error(`Something went wrong. Block(s) have not been processed: ${failedBlocks}`);
- }
-
-
- }, options.wsEndpoint);
-};
-
-const chunk = <T>(arr: T[], size: number) =>
- Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
- arr.slice(i * size, i * size + size));
js-packages/tests/src/migrations/runCheckState.tsdiffbeforeafterboth--- a/js-packages/tests/src/migrations/runCheckState.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import {main} from './correctStateAfterMaintenance.js';
-
-main({
- wsEndpoint: process.env.WS_RPC!,
- donorSeed: process.env.SUPERUSER_SEED!,
-}).then(() => process.exit(0))
- .catch((e) => {
- console.error(e);
- process.exit(1);
- });
js-packages/tests/src/nativeFungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nativeFungible.test.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from './util/index.js';
-
-describe('Native fungible', () => {
- let root: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- root = await privateKey('//Alice');
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
- });
- });
-
- itSub('destroy_collection()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.burn(alice)).to.be.rejectedWith('common.UnsupportedOperation');
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.destroyCollection', [0])).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('add_to_allow_list()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.addToAllowList(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('remove_from_allow_list()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.removeFromAllowList(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('change_collection_owner()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.changeOwner(alice, bob.address)).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('add_collection_admin()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.addAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('remove_collection_admin()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.removeAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('set_collection_sponsor()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.setSponsor(alice, bob.address)).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('confirm_sponsorship()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.confirmSponsorship(alice)).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('remove_collection_sponsor()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.removeSponsor(alice)).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('create_item()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.mint(alice, 100n, {Substrate: bob.address})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('set_collection_properties()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.setProperties(alice, [{key: 'value'}])).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('delete_collection_properties()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.deleteProperties(alice, ['key'])).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('set_token_properties()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.setTokenProperties',
- [0, 0, [{key: 'value'}]],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('delete_token_properties()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.deleteTokenProperties',
- [0, 0, ['key']],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('set_transfers_enabled_flag()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.setTransfersEnabledFlag',
- [0, true],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('burn_item()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.burnItem',
- [0, 0, 100n],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('burn_from()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.burnTokens(alice, 100n)).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('transfer()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- const balanceAliceBefore = await helper.balance.getSubstrate(alice.address);
- const balanceBobBefore = await helper.balance.getSubstrate(bob.address);
- await collection.transfer(alice, {Substrate: bob.address}, 100n);
- const balanceAliceAfter = await helper.balance.getSubstrate(alice.address);
- const balanceBobAfter = await helper.balance.getSubstrate(bob.address);
- expect(balanceAliceBefore - balanceAliceAfter > 100n).to.be.true;
- expect(balanceBobAfter - balanceBobBefore === 100n).to.be.true;
- });
-
- itSub('transfer_from()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- const balanceAliceBefore = await helper.balance.getSubstrate(alice.address);
- const balanceBobBefore = await helper.balance.getSubstrate(bob.address);
-
- await collection.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address}, 100n);
-
- const balanceAliceAfter = await helper.balance.getSubstrate(alice.address);
- const balanceBobAfter = await helper.balance.getSubstrate(bob.address);
- expect(balanceAliceBefore - balanceAliceAfter > 100n).to.be.true;
- expect(balanceBobAfter - balanceBobBefore === 100n).to.be.true;
-
- await expect(collection.transferFrom(alice, {Substrate: bob.address}, {Substrate: alice.address}, 100n)).to.be.rejectedWith('common.ApprovedValueTooLow');
- });
-
- itSub('approve()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.approveTokens(alice, {Substrate: bob.address}, 100n)).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('approve_from()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.approveFrom',
- [{Substrate: alice.address}, {Substrate: bob.address}, 0, 0, 100n],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('set_collection_limits()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.setLimits(alice, {accountTokenOwnershipLimit: 1})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('set_collection_permissions()', async ({helper}) => {
- const collection = helper.ft.getCollectionObject(0);
- await expect(collection.setPermissions(alice, {access: 'AllowList'})).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('repartition()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.repartition',
- [0, 0, 100n],
- true,
- )).to.be.rejectedWith('unique.RepartitionCalledOnNonRefungibleCollection');
- });
-
- itSub('force_repair_collection()', async ({helper}) => {
- await expect(helper.executeExtrinsic(
- alice,
- 'api.tx.unique.forceRepairCollection',
- [0],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('force_repair_item()', async ({helper}) => {
- await expect(helper.getSudo().executeExtrinsic(
- root,
- 'api.tx.unique.forceRepairItem',
- [0, 0],
- true,
- )).to.be.rejectedWith('common.UnsupportedOperation');
- });
-
- itSub('Nest into NFT token()', async ({helper}) => {
- const nftCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await nftCollection.mintToken(alice);
-
- const collection = helper.ft.getCollectionObject(0);
- await collection.transfer(alice, targetToken.nestingAccount(), 100n);
-
- await collection.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 100n);
- });
-});
\ No newline at end of file
js-packages/tests/src/nesting/collectionProperties.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/collectionProperties.seqtest.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
-
-describe('Integration Test: Collection Properties with sudo', () => {
- let superuser: IKeyringPair;
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- superuser = await privateKey('//Alice');
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'ft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
- before(async function() {
- // eslint-disable-next-line require-await
- await usingPlaygrounds(async helper => {
- requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
- });
- });
-
- itSub('Repairing an unbroken collection\'s properties preserves the consumed space', async({helper}) => {
- const properties = [
- {key: 'sea-creatures', value: 'mermaids'},
- {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
- ];
- const collection = await helper[testSuite.mode].mintCollection(alice, {properties});
-
- const newProperty = {key: 'space', value: ' '.repeat(4096)};
- await collection.setProperties(alice, [newProperty]);
- const originalSpace = await collection.getPropertiesConsumedSpace();
- expect(originalSpace).to.be.equal(sizeOfProperty(properties[0]) + sizeOfProperty(properties[1]) + sizeOfProperty(newProperty));
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true);
- const recomputedSpace = await collection.getPropertiesConsumedSpace();
- expect(recomputedSpace).to.be.equal(originalSpace);
- });
- }));
-});
js-packages/tests/src/nesting/collectionProperties.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/collectionProperties.test.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
-
-describe('Integration Test: Collection Properties', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor);
- });
- });
-
- itSub('Properties are initially empty', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- expect(await collection.getProperties()).to.be.empty;
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'ft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
- before(async function() {
- // eslint-disable-next-line require-await
- await usingPlaygrounds(async helper => {
- requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
- });
- });
-
- itSub('Sets properties for a collection', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- // As owner
- await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;
-
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- // As administrator
- await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled;
-
- const properties = await collection.getProperties();
- expect(properties).to.include.deep.members([
- {key: 'electron', value: 'come bond'},
- {key: 'black_hole', value: ''},
- ]);
- });
-
- itSub('Check valid names for collection properties keys', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- // alpha symbols
- await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;
-
- // numeric symbols
- await expect(collection.setProperties(alice, [{key: '451'}])).to.be.fulfilled;
-
- // underscore symbol
- await expect(collection.setProperties(alice, [{key: 'black_hole'}])).to.be.fulfilled;
-
- // dash symbol
- await expect(collection.setProperties(alice, [{key: '-'}])).to.be.fulfilled;
-
- // dot symbol
- await expect(collection.setProperties(alice, [{key: 'once.in.a.long.long.while...', value: 'you get a little lost'}])).to.be.fulfilled;
-
- const properties = await collection.getProperties();
- expect(properties).to.include.deep.members([
- {key: 'answer', value: ''},
- {key: '451', value: ''},
- {key: 'black_hole', value: ''},
- {key: '-', value: ''},
- {key: 'once.in.a.long.long.while...', value: 'you get a little lost'},
- ]);
- });
-
- itSub('Changes properties of a collection', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;
-
- // Mutate the properties
- await expect(collection.setProperties(alice, [{key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
-
- const properties = await collection.getProperties();
- expect(properties).to.include.deep.members([
- {key: 'electron', value: 'come bond'},
- {key: 'black_hole', value: 'LIGO'},
- ]);
- });
-
- itSub('Deletes properties of a collection', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
-
- await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled;
-
- const properties = await collection.getProperties(['black_hole', 'electron']);
- expect(properties).to.be.deep.equal([
- {key: 'black_hole', value: 'LIGO'},
- ]);
- });
-
- itSub('Allows modifying a collection property multiple times with the same size', async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- const maxCollectionPropertiesSize = 40960;
-
- const propDataSize = 4096;
-
- let propDataChar = 'a';
- const makeNewPropData = () => {
- propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
- return `${propDataChar}`.repeat(propDataSize);
- };
-
- const property = {key: propKey, value: makeNewPropData()};
- await collection.setProperties(alice, [property]);
- const originalSpace = await collection.getPropertiesConsumedSpace();
- expect(originalSpace).to.be.equal(sizeOfProperty(property));
-
- const sameSizePropertiesPossibleNum = maxCollectionPropertiesSize / propDataSize;
-
- // It is possible to modify a property as many times as needed.
- // It will not consume any additional space.
- for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
- await collection.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
- const consumedSpace = await collection.getPropertiesConsumedSpace();
- expect(consumedSpace).to.be.equal(originalSpace);
- }
- });
-
- itSub('Adding then removing a collection property doesn\'t change the consumed space', async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testSuite.mode].mintCollection(alice);
- const originalSpace = await collection.getPropertiesConsumedSpace();
-
- const propDataSize = 4096;
- const propData = 'a'.repeat(propDataSize);
-
- const property = {key: propKey, value: propData};
- await collection.setProperties(alice, [property]);
- let consumedSpace = await collection.getPropertiesConsumedSpace();
- expect(consumedSpace).to.be.equal(sizeOfProperty(property));
-
- await collection.deleteProperties(alice, [propKey]);
- consumedSpace = await collection.getPropertiesConsumedSpace();
- expect(consumedSpace).to.be.equal(originalSpace);
- });
-
- itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testSuite.mode].mintCollection(alice);
- const originalSpace = await collection.getPropertiesConsumedSpace();
-
- const initProp = {key: propKey, value: 'a'.repeat(4096)};
- const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
- const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
-
- let consumedSpace;
- let expectedConsumedSpaceDiff;
-
- await collection.setProperties(alice, [initProp]);
- consumedSpace = await collection.getPropertiesConsumedSpace();
- expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
- expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
-
- await collection.setProperties(alice, [biggerProp]);
- consumedSpace = await collection.getPropertiesConsumedSpace();
- expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
- expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
-
- await collection.setProperties(alice, [smallerProp]);
- consumedSpace = await collection.getPropertiesConsumedSpace();
- expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
- expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
- });
- }));
-});
-
-describe('Negative Integration Test: Collection Properties', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([1000n, 100n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'ft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
- before(async function() {
- // eslint-disable-next-line require-await
- await usingPlaygrounds(async helper => {
- requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
- });
- });
-
- itSub('Fails to set properties in a collection if not its onwer/administrator', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))
- .to.be.rejectedWith(/common\.NoPermission/);
-
- expect(await collection.getProperties()).to.be.empty;
- });
-
- itSub('Fails to set properties that exceed the limits', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- const spaceLimit = (helper.getApi().consts.unique.maxCollectionPropertiesSize as any).toNumber();
-
- // Mute the general tx parsing error, too many bytes to process
- {
- console.error = () => {};
- await expect(collection.setProperties(alice, [
- {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))},
- ])).to.be.rejected;
- }
-
- expect(await collection.getProperties(['electron'])).to.be.empty;
-
- await expect(collection.setProperties(alice, [
- {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))},
- {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))},
- ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
- expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty;
- });
-
- itSub('Fails to set more properties than it is allowed', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- const propertiesToBeSet = [];
- for(let i = 0; i < 65; i++) {
- propertiesToBeSet.push({
- key: 'electron_' + i,
- value: Math.random() > 0.5 ? 'high' : 'low',
- });
- }
-
- await expect(collection.setProperties(alice, propertiesToBeSet)).
- to.be.rejectedWith(/common\.PropertyLimitReached/);
-
- expect(await collection.getProperties()).to.be.empty;
- });
-
- itSub('Fails to set properties with invalid names', async ({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice);
-
- const invalidProperties = [
- [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
- [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
- [{key: 'déjà vu', value: 'hmm...'}],
- ];
-
- for(let i = 0; i < invalidProperties.length; i++) {
- await expect(
- collection.setProperties(alice, invalidProperties[i]),
- `on rejecting the new badly-named property #${i}`,
- ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
- }
-
- await expect(
- collection.setProperties(alice, [{key: '', value: 'nothing must not exist'}]),
- 'on rejecting an unnamed property',
- ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
- await expect(
- collection.setProperties(alice, [{key: 'CRISPR-Cas9', value: 'rewriting nature!'}]),
- 'on setting the correctly-but-still-badly-named property',
- ).to.be.fulfilled;
-
- const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');
-
- const properties = await collection.getProperties(keys);
- expect(properties).to.be.deep.equal([
- {key: 'CRISPR-Cas9', value: 'rewriting nature!'},
- ]);
-
- for(let i = 0; i < invalidProperties.length; i++) {
- await expect(
- collection.deleteProperties(alice, invalidProperties[i].map(propertySet => propertySet.key)),
- `on trying to delete the non-existent badly-named property #${i}`,
- ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
- }
- });
-
- itSub('Forbids to repair a collection if called with non-sudo', async({helper}) => {
- const collection = await helper[testSuite.mode].mintCollection(alice, {properties: [
- {key: 'sea-creatures', value: 'mermaids'},
- {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
- ]});
-
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true))
- .to.be.rejectedWith(/BadOrigin/);
- });
- }));
-});
js-packages/tests/src/nesting/graphs.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/graphs.test.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from '../util/index.js';
-import {UniqueHelper, UniqueNFTCollection, UniqueNFToken} from '@unique/playgrounds/src/unique.js';
-
-/**
- * ```dot
- * 4 -> 3 -> 2 -> 1
- * 7 -> 6 -> 5 -> 2
- * 8 -> 5
- * ```
- */
-async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<[UniqueNFTCollection,UniqueNFToken[]]> {
- const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
- const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
-
- await tokens[7].nest(sender, tokens[4]);
- await tokens[6].nest(sender, tokens[5]);
- await tokens[5].nest(sender, tokens[4]);
- await tokens[4].nest(sender, tokens[1]);
- await tokens[3].nest(sender, tokens[2]);
- await tokens[2].nest(sender, tokens[1]);
- await tokens[1].nest(sender, tokens[0]);
-
- return [collection, tokens];
-}
-
-describe('Graphs', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([10n], donor);
- });
- });
-
- itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {
- const [collection, tokens] = await buildComplexObjectGraph(helper, alice);
-
- await collection.setPermissions(alice, {nesting: {collectionAdmin: false, tokenOwner: true}});
-
- // [token owner] to self
- await expect(
- tokens[0].nest(alice, tokens[0]),
- '[token owner] self-nesting is forbidden',
- ).to.be.rejectedWith(/structure\.OuroborosDetected/);
- // [token owner] to nested part of graph
- await expect(
- tokens[0].nest(alice, tokens[4]),
- '[token owner] cannot nest the root node into an internal node',
- ).to.be.rejectedWith(/structure\.OuroborosDetected/);
- await expect(
- tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),
- '[token owner] cannot nest higher internal node into lower internal node',
- ).to.be.rejectedWith(/structure\.OuroborosDetected/);
-
- await collection.setPermissions(alice, {nesting: {collectionAdmin: true, tokenOwner: false}});
-
- // [collection owner] to self
- await expect(
- tokens[0].nest(alice, tokens[0]),
- '[collection owner] self-nesting is forbidden',
- ).to.be.rejectedWith(/structure\.OuroborosDetected/);
- // [collection owner] to nested part of graph
- await expect(
- tokens[0].nest(alice, tokens[4]),
- '[collection owner] cannot nest the root node into an internal node',
- ).to.be.rejectedWith(/structure\.OuroborosDetected/);
- });
-});
js-packages/tests/src/nesting/propertyPermissions.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/propertyPermissions.test.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect} from '../util/index.js';
-import {UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/src/unique.js';
-
-describe('Integration Test: Access Rights to Token Properties', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
- });
- });
-
- itSub('Reads access rights to properties of a collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- const propertyRights = (await helper.callRpc('api.query.common.collectionPropertyPermissions', [collection.collectionId])).toJSON();
- expect(propertyRights).to.be.empty;
- });
-
- async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
- await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}]))
- .to.be.fulfilled;
-
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- await expect(collection.setTokenPropertyPermissions(bob, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]))
- .to.be.fulfilled;
-
- const propertyRights = await collection.getPropertyPermissions(['skullduggery', 'mindgame']);
- expect(propertyRights).to.include.deep.members([
- {key: 'skullduggery', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}},
- {key: 'mindgame', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
- ]);
- }
-
- itSub('Sets access rights to properties of a collection (NFT)', async ({helper}) => {
- await testSetsAccessRightsToProperties(await helper.nft.mintCollection(alice));
- });
-
- itSub.ifWithPallets('Sets access rights to properties of a collection (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice));
- });
-
- async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) {
- await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]))
- .to.be.fulfilled;
-
- await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
- .to.be.fulfilled;
-
- const propertyRights = await collection.getPropertyPermissions();
- expect(propertyRights).to.be.deep.equal([
- {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
- ]);
- }
-
- itSub('Changes access rights to properties of a NFT collection', async ({helper}) => {
- await testChangesAccessRightsToProperty(await helper.nft.mintCollection(alice));
- });
-
- itSub.ifWithPallets('Changes access rights to properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
- await testChangesAccessRightsToProperty(await helper.rft.mintCollection(alice));
- });
-});
-
-describe('Negative Integration Test: Access Rights to Token Properties', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
- });
- });
-
- async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) {
- await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]))
- .to.be.rejectedWith(/common\.NoPermission/);
-
- const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
- expect(propertyRights).to.be.empty;
- }
-
- itSub('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async ({helper}) => {
- await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.nft.mintCollection(alice));
- });
-
- itSub.ifWithPallets('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', [Pallets.ReFungible], async ({helper}) => {
- await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice));
- });
-
- async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
- const constitution = [];
- for(let i = 0; i < 65; i++) {
- constitution.push({
- key: 'property_' + i,
- permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
- });
- }
-
- await expect(collection.setTokenPropertyPermissions(alice, constitution))
- .to.be.rejectedWith(/common\.PropertyLimitReached/);
-
- const propertyRights = await collection.getPropertyPermissions();
- expect(propertyRights).to.be.empty;
- }
-
- itSub('Prevents from adding too many possible properties (NFT)', async ({helper}) => {
- await testPreventFromAddingTooManyPossibleProperties(await helper.nft.mintCollection(alice));
- });
-
- itSub.ifWithPallets('Prevents from adding too many possible properties (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice));
- });
-
- async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) {
- await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
- .to.be.fulfilled;
-
- await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {collectionAdmin: true}}]))
- .to.be.rejectedWith(/common\.NoPermission/);
-
- const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
- expect(propertyRights).to.deep.equal([
- {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
- ]);
- }
-
- itSub('Prevents access rights to be modified if constant (NFT)', async ({helper}) => {
- await testPreventAccessRightsModifiedIfConstant(await helper.nft.mintCollection(alice));
- });
-
- itSub.ifWithPallets('Prevents access rights to be modified if constant (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice));
- });
-
- async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) {
- const invalidProperties = [
- [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
- [{key: 'G#4', permission: {tokenOwner: true}}],
- [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],
- ];
-
- for(let i = 0; i < invalidProperties.length; i++) {
- await expect(
- collection.setTokenPropertyPermissions(alice, invalidProperties[i]),
- `on setting the new badly-named property #${i}`,
- ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
- }
-
- await expect(
- collection.setTokenPropertyPermissions(alice, [{key: '', permission: {}}]),
- 'on rejecting an unnamed property',
- ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
- const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string
- await expect(
- collection.setTokenPropertyPermissions(alice, [
- {key: correctKey, permission: {collectionAdmin: true}},
- ]),
- 'on setting the correctly-but-still-badly-named property',
- ).to.be.fulfilled;
-
- const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');
-
- const propertyRights = await collection.getPropertyPermissions(keys);
- expect(propertyRights).to.be.deep.equal([
- {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
- ]);
- }
-
- itSub('Prevents adding properties with invalid names (NFT)', async ({helper}) => {
- await testPreventsAddingPropertiesWithInvalidNames(await helper.nft.mintCollection(alice));
- });
-
- itSub.ifWithPallets('Prevents adding properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- await testPreventsAddingPropertiesWithInvalidNames(await helper.rft.mintCollection(alice));
- });
-});
js-packages/tests/src/nesting/tokenProperties.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/tokenProperties.seqtest.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
-
-describe('Integration Test: Token Properties with sudo', () => {
- let superuser: IKeyringPair;
- let alice: IKeyringPair; // collection owner
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- superuser = await privateKey('//Alice');
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, pieces: undefined, requiredPallets: []} as const,
- {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
- ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
- before(async function() {
- // eslint-disable-next-line require-await
- await usingPlaygrounds(async helper => {
- requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
- });
- });
-
- itSub('force_repair_item preserves valid consumed space', async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testSuite.mode].mintCollection(alice, {
- tokenPropertyPermissions: [
- {
- key: propKey,
- permission: {mutable: true, tokenOwner: true},
- },
- ],
- });
- const token = await (
- testSuite.pieces
- ? collection.mintToken(alice, testSuite.pieces as any)
- : collection.mintToken(alice)
- );
-
- const prop = {key: propKey, value: 'a'.repeat(4096)};
-
- await token.setProperties(alice, [prop]);
- const originalSpace = await token.getTokenPropertiesConsumedSpace();
- expect(originalSpace).to.be.equal(sizeOfProperty(prop));
-
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true);
- const recomputedSpace = await token.getTokenPropertiesConsumedSpace();
- expect(recomputedSpace).to.be.equal(originalSpace);
- });
- }));
-});
js-packages/tests/src/nesting/tokenProperties.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/tokenProperties.test.ts
+++ /dev/null
@@ -1,816 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect, sizeOfProperty} from '../util/index.js';
-import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/src/unique.js';
-
-describe('Integration Test: Token Properties', () => {
- let alice: IKeyringPair; // collection owner
- let bob: IKeyringPair; // collection admin
- let charlie: IKeyringPair; // token owner
-
- let permissions: {permission: any, signers: IKeyringPair[]}[];
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);
- });
-
- permissions = [
- {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},
- {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},
- {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},
- {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},
- {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
- {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
- ];
- });
-
- async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
- const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
- tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
- signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
- });
- return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
- }
-
- async function testReadsYetEmptyProperties(token: UniqueNFToken | UniqueRFToken) {
- const properties = await token.getProperties();
- expect(properties).to.be.empty;
-
- const tokenData = await token.getData();
- expect(tokenData!.properties).to.be.empty;
- }
-
- itSub('Reads yet empty properties of a token (NFT)', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- const token = await collection.mintToken(alice);
- await testReadsYetEmptyProperties(token);
- });
-
- itSub.ifWithPallets('Reads yet empty properties of a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice);
- const token = await collection.mintToken(alice);
- await testReadsYetEmptyProperties(token);
- });
-
- async function testAssignPropertiesAccordingToPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- await token.collection.addAdmin(alice, {Substrate: bob.address});
- await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
- const propertyKeys: string[] = [];
- let i = 0;
- for(const permission of permissions) {
- i++;
- let j = 0;
- for(const signer of permission.signers) {
- j++;
- const key = i + '_' + signer.address;
- propertyKeys.push(key);
-
- await expect(
- token.setProperties(signer, [{key: key, value: 'Serotonin increase'}]),
- `on adding property #${i} by signer #${j}`,
- ).to.be.fulfilled;
- }
- }
-
- const properties = await token.getProperties(propertyKeys);
- const tokenData = await token.getData();
- for(let i = 0; i < properties.length; i++) {
- expect(properties[i].value).to.be.equal('Serotonin increase');
- expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
- }
- }
-
- itSub('Assigns properties to a token according to permissions (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testAssignPropertiesAccordingToPermissions(token, amount);
- });
-
- itSub.ifWithPallets('Assigns properties to a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testAssignPropertiesAccordingToPermissions(token, amount);
- });
-
- async function testChangesPropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- await token.collection.addAdmin(alice, {Substrate: bob.address});
- await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
- const propertyKeys: string[] = [];
- let i = 0;
- for(const permission of permissions) {
- i++;
- if(!permission.permission.mutable) continue;
-
- let j = 0;
- for(const signer of permission.signers) {
- j++;
- const key = i + '_' + signer.address;
- propertyKeys.push(key);
-
- await expect(
- token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
- `on adding property #${i} by signer #${j}`,
- ).to.be.fulfilled;
-
- await expect(
- token.setProperties(signer, [{key, value: 'Serotonin stable'}]),
- `on changing property #${i} by signer #${j}`,
- ).to.be.fulfilled;
- }
- }
-
- const properties = await token.getProperties(propertyKeys);
- const tokenData = await token.getData();
- for(let i = 0; i < properties.length; i++) {
- expect(properties[i].value).to.be.equal('Serotonin stable');
- expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
- }
- }
-
- itSub('Changes properties of a token according to permissions (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testChangesPropertiesAccordingPermission(token, amount);
- });
-
- itSub.ifWithPallets('Changes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testChangesPropertiesAccordingPermission(token, amount);
- });
-
- async function testDeletePropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- await token.collection.addAdmin(alice, {Substrate: bob.address});
- await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
- const propertyKeys: string[] = [];
- let i = 0;
-
- for(const permission of permissions) {
- i++;
- if(!permission.permission.mutable) continue;
-
- let j = 0;
- for(const signer of permission.signers) {
- j++;
- const key = i + '_' + signer.address;
- propertyKeys.push(key);
-
- await expect(
- token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
- `on adding property #${i} by signer #${j}`,
- ).to.be.fulfilled;
-
- await expect(
- token.deleteProperties(signer, [key]),
- `on deleting property #${i} by signer #${j}`,
- ).to.be.fulfilled;
- }
- }
-
- expect(await token.getProperties(propertyKeys)).to.be.empty;
- expect((await token.getData())!.properties).to.be.empty;
- }
-
- itSub('Deletes properties of a token according to permissions (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testDeletePropertiesAccordingPermission(token, amount);
- });
-
- itSub.ifWithPallets('Deletes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testDeletePropertiesAccordingPermission(token, amount);
- });
-
- itSub('Assigns properties to a nested token according to permissions', async ({helper}) => {
- const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const collectionB = await helper.nft.mintCollection(alice, {
- tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
- signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
- });
- const targetToken = await collectionA.mintToken(alice);
- const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
-
- await collectionB.addAdmin(alice, {Substrate: bob.address});
- await targetToken.transfer(alice, {Substrate: charlie.address});
-
- const propertyKeys: string[] = [];
- let i = 0;
- for(const permission of permissions) {
- i++;
- let j = 0;
- for(const signer of permission.signers) {
- j++;
- const key = i + '_' + signer.address;
- propertyKeys.push(key);
-
- await expect(
- nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
- `on adding property #${i} by signer #${j}`,
- ).to.be.fulfilled;
- }
- }
-
- const properties = await nestedToken.getProperties(propertyKeys);
- const tokenData = await nestedToken.getData();
- for(let i = 0; i < properties.length; i++) {
- expect(properties[i].value).to.be.equal('Serotonin increase');
- expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
- }
- expect(await targetToken.getProperties()).to.be.empty;
- });
-
- itSub('Changes properties of a nested token according to permissions', async ({helper}) => {
- const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const collectionB = await helper.nft.mintCollection(alice, {
- tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
- signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
- });
- const targetToken = await collectionA.mintToken(alice);
- const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
-
- await collectionB.addAdmin(alice, {Substrate: bob.address});
- await targetToken.transfer(alice, {Substrate: charlie.address});
-
- const propertyKeys: string[] = [];
- let i = 0;
- for(const permission of permissions) {
- i++;
- if(!permission.permission.mutable) continue;
-
- let j = 0;
- for(const signer of permission.signers) {
- j++;
- const key = i + '_' + signer.address;
- propertyKeys.push(key);
-
- await expect(
- nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
- `on adding property #${i} by signer #${j}`,
- ).to.be.fulfilled;
-
- await expect(
- nestedToken.setProperties(signer, [{key, value: 'Serotonin stable'}]),
- `on changing property #${i} by signer #${j}`,
- ).to.be.fulfilled;
- }
- }
-
- const properties = await nestedToken.getProperties(propertyKeys);
- const tokenData = await nestedToken.getData();
- for(let i = 0; i < properties.length; i++) {
- expect(properties[i].value).to.be.equal('Serotonin stable');
- expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
- }
- expect(await targetToken.getProperties()).to.be.empty;
- });
-
- itSub('Deletes properties of a nested token according to permissions', async ({helper}) => {
- const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const collectionB = await helper.nft.mintCollection(alice, {
- tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
- signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
- });
- const targetToken = await collectionA.mintToken(alice);
- const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
-
- await collectionB.addAdmin(alice, {Substrate: bob.address});
- await targetToken.transfer(alice, {Substrate: charlie.address});
-
- const propertyKeys: string[] = [];
- let i = 0;
- for(const permission of permissions) {
- i++;
- if(!permission.permission.mutable) continue;
-
- let j = 0;
- for(const signer of permission.signers) {
- j++;
- const key = i + '_' + signer.address;
- propertyKeys.push(key);
-
- await expect(
- nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
- `on adding property #${i} by signer #${j}`,
- ).to.be.fulfilled;
-
- await expect(
- nestedToken.deleteProperties(signer, [key]),
- `on deleting property #${i} by signer #${j}`,
- ).to.be.fulfilled;
- }
- }
-
- expect(await nestedToken.getProperties(propertyKeys)).to.be.empty;
- expect((await nestedToken.getData())!.properties).to.be.empty;
- expect(await targetToken.getProperties()).to.be.empty;
- });
-
- [
- {mode: 'nft' as const, storage: 'nonfungible' as const, pieces: undefined, requiredPallets: []} as const,
- {mode: 'rft' as const, storage: 'refungible' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
- ].map(testCase =>
- itSub.ifWithPallets(`Allows modifying a token property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: [
- {
- key: propKey,
- permission: {mutable: true, tokenOwner: true},
- },
- ],
- });
-
- const maxTokenPropertiesSize = 32768;
-
- const propDataSize = 4096;
-
- let propDataChar = 'a';
- const makeNewPropData = () => {
- propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
- return `${propDataChar}`.repeat(propDataSize);
- };
-
- const token = await (
- testCase.pieces
- ? collection.mintToken(alice, testCase.pieces as any)
- : collection.mintToken(alice)
- );
-
- const property = {key: propKey, value: makeNewPropData()};
- await token.setProperties(alice, [property]);
- const originalSpace = await token.getTokenPropertiesConsumedSpace();
- expect(originalSpace).to.be.equal(sizeOfProperty(property));
-
- const sameSizePropertiesPossibleNum = maxTokenPropertiesSize / propDataSize;
-
- // It is possible to modify a property as many times as needed.
- // It will not consume any additional space.
- for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
- await token.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
- const consumedSpace = await token.getTokenPropertiesConsumedSpace();
- expect(consumedSpace).to.be.equal(originalSpace);
- }
- }));
-
- [
- {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
- {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itSub.ifWithPallets(`Adding then removing a token property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: [
- {
- key: propKey,
- permission: {mutable: true, tokenOwner: true},
- },
- ],
- });
- const token = await (
- testCase.pieces
- ? collection.mintToken(alice, testCase.pieces as any)
- : collection.mintToken(alice)
- );
- const originalSpace = await token.getTokenPropertiesConsumedSpace();
-
- const propDataSize = 4096;
- const propData = 'a'.repeat(propDataSize);
-
- const property = {key: propKey, value: propData};
- await token.setProperties(alice, [property]);
- let consumedSpace = await token.getTokenPropertiesConsumedSpace();
- expect(consumedSpace).to.be.equal(sizeOfProperty(property));
-
- await token.deleteProperties(alice, [propKey]);
- consumedSpace = await token.getTokenPropertiesConsumedSpace();
- expect(consumedSpace).to.be.equal(originalSpace);
- }));
-
- [
- {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
- {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itSub.ifWithPallets(`Modifying a token property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: [
- {
- key: propKey,
- permission: {mutable: true, tokenOwner: true},
- },
- ],
- });
- const token = await (
- testCase.pieces
- ? collection.mintToken(alice, testCase.pieces as any)
- : collection.mintToken(alice)
- );
- const originalSpace = await token.getTokenPropertiesConsumedSpace();
-
- const initProp = {key: propKey, value: 'a'.repeat(4096)};
- const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
- const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
-
- let consumedSpace;
- let expectedConsumedSpaceDiff;
-
- await token.setProperties(alice, [initProp]);
- consumedSpace = await token.getTokenPropertiesConsumedSpace();
- expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
- expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
-
- await token.setProperties(alice, [biggerProp]);
- consumedSpace = await token.getTokenPropertiesConsumedSpace();
- expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
- expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
-
- await token.setProperties(alice, [smallerProp]);
- consumedSpace = await token.getTokenPropertiesConsumedSpace();
- expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
- expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
- }));
-
- itSub('Set sponsored properties', async({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true}}]});
-
- await collection.setSponsor(alice, alice.address);
- await collection.confirmSponsorship(alice);
- await collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
- await collection.addToAllowList(alice, {Substrate: bob.address});
- await collection.setLimits(alice, {sponsoredDataRateLimit: {blocks: 30}});
-
- const token = await collection.mintToken(alice, {Substrate: bob.address});
-
- const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
- const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- await token.setProperties(bob, [{key: 'k', value: 'val'}]);
-
- const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
- const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(bobBalanceAfter).to.be.equal(bobBalanceBefore);
- expect(aliceBalanceBefore > aliceBalanceAfter).to.be.true;
- });
-});
-
-describe('Negative Integration Test: Token Properties', () => {
- let alice: IKeyringPair; // collection owner
- let bob: IKeyringPair; // collection admin
- let charlie: IKeyringPair; // token owner
-
- let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- let dave: IKeyringPair;
- [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
-
- // todo:playgrounds probably separate these tests later
- constitution = [
- {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
- {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
- {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},
- {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},
- {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
- {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
- ];
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: [Pallets.NFT]},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itSub.ifWithPallets(`Forbids adding/deleting properties of a token if token doesn't exist (${testCase.mode.toLocaleUpperCase})`, testCase.requiredPallets, async({helper}) => {
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: constitution.slice(0, 1).map(({permission}) => ({key: '1', permission})),
- });
- const nonExistentToken = collection.getTokenObject(1);
-
- await expect(
- nonExistentToken.setProperties(alice, [{key: '1', value: 'Serotonin increase'}]),
- 'on expecting failure whilst adding a property by alice',
- ).to.be.rejectedWith(/common\.TokenNotFound/);
-
- await expect(
- nonExistentToken.deleteProperties(alice, ['1']),
- 'on expecting failure whilst deleting a property by alice',
- ).to.be.rejectedWith(/common\.TokenNotFound/);
- }));
-
- async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
- const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
- tokenPropertyPermissions: constitution.map(({permission}, i) => ({key: `${i+1}`, permission})),
- });
- return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
- }
-
- async function getConsumedSpace(api: any, collectionId: number, tokenId: number, mode: 'NFT' | 'RFT'): Promise<number> {
- return (await (mode == 'NFT' ? api.query.nonfungible : api.query.refungible).tokenProperties(collectionId, tokenId)).toJSON().consumedSpace;
- }
-
- async function prepare(token: UniqueNFToken | UniqueRFToken, pieces: bigint): Promise<number> {
- await token.collection.addAdmin(alice, {Substrate: bob.address});
- await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
- let i = 0;
- for(const passage of constitution) {
- i++;
- const signer = passage.signers[0];
- await expect(
- token.setProperties(signer, [{key: `${i}`, value: 'Serotonin increase'}]),
- `on adding property ${i} by ${signer.address}`,
- ).to.be.fulfilled;
- }
-
- const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
- return originalSpace;
- }
-
- async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- const originalSpace = await prepare(token, pieces);
-
- let i = 0;
- for(const forbiddance of constitution) {
- i++;
- if(!forbiddance.permission.mutable) continue;
-
- await expect(
- token.setProperties(forbiddance.sinner, [{key: `${i}`, value: 'Serotonin down'}]),
- `on failing to change property ${i} by the malefactor`,
- ).to.be.rejectedWith(/common\.NoPermission/);
-
- await expect(
- token.deleteProperties(forbiddance.sinner, [`${i}`]),
- `on failing to delete property ${i} by the malefactor`,
- ).to.be.rejectedWith(/common\.NoPermission/);
- }
-
- const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
- expect(consumedSpace).to.be.equal(originalSpace);
- }
-
- itSub('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
- });
-
- itSub.ifWithPallets('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
- });
-
- async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- const originalSpace = await prepare(token, pieces);
-
- let i = 0;
- for(const permission of constitution) {
- i++;
- if(permission.permission.mutable) continue;
-
- await expect(
- token.setProperties(permission.signers[0], [{key: `${i}`, value: 'Serotonin down'}]),
- `on failing to change property ${i} by signer #0`,
- ).to.be.rejectedWith(/common\.NoPermission/);
-
- await expect(
- token.deleteProperties(permission.signers[0], [i.toString()]),
- `on failing to delete property ${i} by signer #0`,
- ).to.be.rejectedWith(/common\.NoPermission/);
- }
-
- const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
- expect(consumedSpace).to.be.equal(originalSpace);
- }
-
- itSub('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
- });
-
- itSub.ifWithPallets('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
- });
-
- async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- const originalSpace = await prepare(token, pieces);
-
- await expect(
- token.setProperties(alice, [{key: 'non-existent', value: 'I exist!'}]),
- 'on failing to add a previously non-existent property',
- ).to.be.rejectedWith(/common\.NoPermission/);
-
- await expect(
- token.collection.setTokenPropertyPermissions(alice, [{key: 'now-existent', permission: {}}]),
- 'on setting a new non-permitted property',
- ).to.be.fulfilled;
-
- await expect(
- token.setProperties(alice, [{key: 'now-existent', value: 'I exist!'}]),
- 'on failing to add a property forbidden by the \'None\' permission',
- ).to.be.rejectedWith(/common\.NoPermission/);
-
- expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty;
-
- const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
- expect(consumedSpace).to.be.equal(originalSpace);
- }
-
- itSub('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
- });
-
- itSub.ifWithPallets('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
- });
-
- async function testForbidsAddingTooLargeProperties(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
- const originalSpace = await prepare(token, pieces);
-
- await expect(
- token.collection.setTokenPropertyPermissions(alice, [
- {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}},
- {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},
- ]),
- 'on setting new permissions for properties',
- ).to.be.fulfilled;
-
- // Mute the general tx parsing error
- {
- console.error = () => {};
- await expect(token.setProperties(alice, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]))
- .to.be.rejected;
- }
-
- await expect(token.setProperties(alice, [
- {key: 'a_holy_book', value: 'word '.repeat(3277)},
- {key: 'young_years', value: 'neverending'.repeat(1490)},
- ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
- expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty;
- const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
- expect(consumedSpace).to.be.equal(originalSpace);
- }
-
- itSub('Forbids adding too large properties to a token (NFT)', async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
- await testForbidsAddingTooLargeProperties(token, amount);
- });
-
- itSub.ifWithPallets('Forbids adding too large properties to a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
- const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
- await testForbidsAddingTooLargeProperties(token, amount);
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itSub.ifWithPallets(`Forbids adding too many propeties to a token (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
- const collection = await helper[testCase.mode].mintCollection(alice);
- const maxPropertiesPerItem = 64;
-
- for(let i = 0; i < maxPropertiesPerItem; i++) {
- await collection.setTokenPropertyPermissions(alice, [{
- key: `${i+1}`,
- permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
- }]);
- }
-
- await expect(collection.setTokenPropertyPermissions(alice, [{
- key: `${maxPropertiesPerItem}-th`,
- permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
- }])).to.be.rejectedWith(/common\.PropertyLimitReached/);
- }));
-
- [
- {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
- {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase =>
- itSub.ifWithPallets(`Forbids force_repair_item from non-sudo (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
- const propKey = 'tok-prop';
-
- const collection = await helper[testCase.mode].mintCollection(alice, {
- tokenPropertyPermissions: [
- {
- key: propKey,
- permission: {mutable: true, tokenOwner: true},
- },
- ],
- });
- const token = await (
- testCase.pieces
- ? collection.mintToken(alice, testCase.pieces as any)
- : collection.mintToken(alice)
- );
-
- const propDataSize = 4096;
- const propData = 'a'.repeat(propDataSize);
- await token.setProperties(alice, [{key: propKey, value: propData}]);
-
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true))
- .to.be.rejectedWith(/BadOrigin/);
- }));
-});
-
-describe('ReFungible token properties permissions tests', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- async function prepare(helper: UniqueHelper): Promise<UniqueRFToken> {
- const collection = await helper.rft.mintCollection(alice);
- const token = await collection.mintToken(alice, 100n);
-
- await collection.addAdmin(alice, {Substrate: bob.address});
- await collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable: true, tokenOwner: true}}]);
-
- return token;
- }
-
- itSub('Forbids adding token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) => {
- const token = await prepare(helper);
-
- await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
- await expect(token.setProperties(alice, [
- {key: 'fractals', value: 'multiverse'},
- ])).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Forbids mutating token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) => {
- const token = await prepare(helper);
-
- await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, tokenOwner: true}}]))
- .to.be.fulfilled;
-
- await expect(token.setProperties(alice, [
- {key: 'fractals', value: 'multiverse'},
- ])).to.be.fulfilled;
-
- await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
- await expect(token.setProperties(alice, [
- {key: 'fractals', value: 'want to rule the world'},
- ])).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Forbids deleting token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) => {
- const token = await prepare(helper);
-
- await expect(token.setProperties(alice, [
- {key: 'fractals', value: 'one headline - why believe it'},
- ])).to.be.fulfilled;
-
- await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
- await expect(token.deleteProperties(alice, ['fractals'])).
- to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Allows token property mutation with collectionOwner==true when admin doesn\'t have all pieces', async ({helper}) => {
- const token = await prepare(helper);
-
- await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
- await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, collectionAdmin: true}}]))
- .to.be.fulfilled;
-
- await expect(token.setProperties(alice, [
- {key: 'fractals', value: 'multiverse'},
- ])).to.be.fulfilled;
- });
-});
js-packages/tests/src/nesting/unnest.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nesting/unnest.test.ts
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from '../util/index.js';
-import {CrossAccountId, UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/src/unique.js';
-
-describe('Integration Test: Unnesting', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);
- });
- });
-
- itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- // Create a nested token
- const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
-
- // Unnest
- await expect(nestedToken.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}), 'while unnesting').to.be.fulfilled;
- expect(await nestedToken.getOwner()).to.be.deep.equal({Substrate: alice.address});
-
- // Nest and burn
- await nestedToken.nest(alice, targetToken);
- await expect(nestedToken.burnFrom(alice, targetToken.nestingAccount()), 'while burning').to.be.fulfilled;
- await expect(nestedToken.getOwner()).to.be.rejected;
- });
-
- itSub('NativeFungible: allows the owner to successfully unnest a token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- const collectionFT = helper.ft.getCollectionObject(0);
-
- // Nest
- await collectionFT.transfer(alice, targetToken.nestingAccount(), 10n);
- // Unnest
- await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
-
- expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
- });
-
- itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- const collectionFT = await helper.ft.mintCollection(alice);
-
- // Nest and unnest
- await collectionFT.mint(alice, 10n, targetToken.nestingAccount());
- await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
- expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(9n);
- expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
-
- // Nest and burn
- await collectionFT.transfer(alice, targetToken.nestingAccount(), 5n);
- await expect(collectionFT.burnTokensFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
- expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(4n);
- expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
- expect(await targetToken.getChildren()).to.be.length(0);
- });
-
- itSub.ifWithPallets('ReFungible: allows the owner to successfully unnest a token', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- const collectionRFT = await helper.rft.mintCollection(alice);
-
- // Nest and unnest
- const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());
- await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);
- expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
-
- // Nest and burn
- await token.transfer(alice, targetToken.nestingAccount(), 5n);
- await expect(token.burnFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(4n);
- expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
- expect(await targetToken.getChildren()).to.be.length(0);
- });
-
- async function checkNestedAmountState({
- expectedBalance,
- childrenShouldPresent,
- nested,
- targetNft,
- }: {
- expectedBalance: bigint,
- childrenShouldPresent: boolean,
- nested: UniqueFTCollection | UniqueRFToken,
- targetNft: UniqueNFToken,
- }) {
- const balance = await nested.getBalance(targetNft.nestingAccount());
- expect(balance).to.be.equal(expectedBalance);
-
- const children = await targetNft.getChildren();
-
- if(childrenShouldPresent) {
- expect(children[0]).to.be.deep.equal({
- collectionId: nested.collectionId,
- tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,
- });
- } else {
- expect(children.length).to.be.equal(0);
- }
- }
-
- function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {
- mode: 'ft' | 'nft' | 'rft',
- sender: string,
- op: 'transfer' | 'burn',
- requiredPallets: Pallets[],
- }[] {
- const senders = ['owner', 'admin'];
- const ops = ['transfer', 'burn'];
-
- const cases = [];
- for(const mode of modes) {
- const requiredPallets = (mode === 'rft')
- ? [Pallets.ReFungible]
- : [];
-
- for(const sender of senders) {
- for(const op of ops) {
- cases.push({
- mode: mode as 'ft' | 'nft' | 'rft',
- sender,
- op: op as 'transfer' | 'burn',
- requiredPallets,
- });
- }
- }
- }
-
- return cases;
- }
-
- ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>
- itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {
- const owner = alice;
- const admin = bob;
-
- const unnester = (testCase.sender === 'owner')
- ? owner
- : admin;
-
- const collectionNFT = await helper.nft.mintCollection(owner);
- await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
-
- const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {
- limits: {
- ownerCanTransfer: true,
- },
- });
- await collectionNested.addAdmin(owner, {Substrate: admin.address});
-
- const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
-
- let nested: UniqueFTCollection | UniqueRFToken;
- const totalAmount = 5n;
- const firstUnnestAmount = 2n;
- const restUnnestAmount = totalAmount - firstUnnestAmount;
-
- if(collectionNested instanceof UniqueFTCollection) {
- await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});
- nested = collectionNested;
- } else {
- nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});
- }
-
- // transfer/burn `amount` of nested assets by `unnester`.
- const doOperationAndCheck = async ({
- amount,
- shouldBeNestedAfterOp,
- }: {
- amount: bigint,
- shouldBeNestedAfterOp: boolean,
- }) => {
- const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());
-
- if(testCase.op === 'transfer') {
- const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});
-
- await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);
- expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);
- } else {
- if(nested instanceof UniqueFTCollection) {
- await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);
- } else {
- await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);
- }
- }
-
- await checkNestedAmountState({
- expectedBalance: nestedBalanceBeforeOp - amount,
- childrenShouldPresent: shouldBeNestedAfterOp,
- nested,
- targetNft,
- });
- };
-
- // Initial setup: nest (fungibles/rft parts).
- // Check NFT's balance of nested assets and NFT's children.
- await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);
- await checkNestedAmountState({
- expectedBalance: totalAmount,
- childrenShouldPresent: true,
- nested,
- targetNft,
- });
-
- // Transfer/burn only a part of nested assets.
- // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.
- await doOperationAndCheck({
- amount: firstUnnestAmount,
- shouldBeNestedAfterOp: true,
- });
-
- // Transfer/burn all remaining nested assets.
- // Check that NFT's balance of the nested assets is 0 and NFT has no more children.
- await doOperationAndCheck({
- amount: restUnnestAmount,
- shouldBeNestedAfterOp: false,
- });
- }));
-
- ownerOrAdminUnnestCases(['nft']).map(testCase =>
- itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {
- const owner = alice;
- const admin = bob;
-
- const unnester = (testCase.sender === 'owner')
- ? owner
- : admin;
-
- const collectionNFT = await helper.nft.mintCollection(owner);
- await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
-
- const collectionNested = await helper.nft.mintCollection(owner, {
- limits: {
- ownerCanTransfer: true,
- },
- });
- await collectionNested.addAdmin(owner, {Substrate: admin.address});
-
- const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
- const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});
-
- await nested.transfer(charlie, targetNft.nestingAccount());
- expect(await targetNft.getChildren()).to.be.deep.equal([{
- collectionId: nested.collectionId,
- tokenId: nested.tokenId,
- }]);
-
- if(testCase.op === 'transfer') {
- await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});
- } else {
- await nested.burnFrom(unnester, targetNft.nestingAccount());
- }
-
- expect((await targetNft.getChildren()).length).to.be.equal(0);
- }));
-});
-
-describe('Negative Test: Unnesting', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
- });
- });
-
- itSub('Disallows a non-owner to unnest/burn a token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- // Create a nested token
- const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
-
- // Try to unnest
- await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-
- // Try to burn
- await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
- });
-
- // todo another test for creating excessive depth matryoshka with Ethereum?
-
- // Recursive nesting
- itSub('Prevents Ouroboros creation', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- // Fail to create a nested token ouroboros
- const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
- await expect(targetToken.nest(alice, nestedToken)).to.be.rejectedWith(/^structure\.OuroborosDetected$/);
- });
-});
js-packages/tests/src/nextSponsoring.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/nextSponsoring.test.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from './util/index.js';
-
-const SPONSORING_TIMEOUT = 5;
-
-describe('Integration Test getNextSponsored(collection_id, owner, item_id):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
- });
- });
-
- itSub('NFT', async ({helper}) => {
- // Non-existing collection
- expect(await helper.collection.getTokenNextSponsored(0, 0, {Substrate: alice.address})).to.be.null;
-
- const collection = await helper.nft.mintCollection(alice, {});
- const token = await collection.mintToken(alice);
-
- // Check with Disabled sponsoring state
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null;
-
- // Check with Unconfirmed sponsoring state
- await collection.setSponsor(alice, bob.address);
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null;
-
- // Check with Confirmed sponsoring state
- await collection.confirmSponsorship(bob);
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.equal(0);
-
- // Check after transfer
- await token.transfer(alice, {Substrate: bob.address});
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
-
- // Non-existing token
- expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
- });
-
- itSub('Fungible', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {});
- await collection.mint(alice, 10n);
-
- // Check with Disabled sponsoring state
- expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
-
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
-
- // Check with Confirmed sponsoring state
- expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.equal(0);
-
- // Check after transfer
- await collection.transfer(alice, {Substrate: bob.address});
- expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
- });
-
- itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {});
- const token = await collection.mintToken(alice, 10n);
-
- // Check with Disabled sponsoring state
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null;
-
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
-
- // Check with Confirmed sponsoring state
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.equal(0);
-
- // Check after transfer
- await token.transfer(alice, {Substrate: bob.address});
- expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
-
- // Non-existing token
- expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
- });
-});
js-packages/tests/src/pallet-presence.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/pallet-presence.test.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-
-// Pallets that must always be present
-const requiredPallets = [
- 'balances',
- 'balancesadapter',
- 'common',
- 'timestamp',
- 'transactionpayment',
- 'treasury',
- 'statetriemigration',
- 'structure',
- 'system',
- 'utility',
- 'vesting',
- 'parachainsystem',
- 'parachaininfo',
- 'evm',
- 'evmcodersubstrate',
- 'evmcontracthelpers',
- 'evmmigration',
- 'evmtransactionpayment',
- 'ethereum',
- 'fungible',
- 'xcmpqueue',
- 'polkadotxcm',
- 'cumulusxcm',
- 'dmpqueue',
- 'inflation',
- 'unique',
- 'nonfungible',
- 'charging',
- 'configuration',
- 'tokens',
- 'xtokens',
- 'maintenance',
-];
-
-// Pallets that depend on consensus and governance configuration
-const consensusPallets = [
- 'sudo',
- 'aura',
- 'auraext',
-];
-
-describe('Pallet presence', () => {
- before(async () => {
- await usingPlaygrounds(async helper => {
- const runtimeVersion = await helper.callRpc('api.rpc.state.getRuntimeVersion', []);
- const chain = runtimeVersion.specName;
-
- const refungible = 'refungible';
- const foreignAssets = 'foreignassets';
- const appPromotion = 'apppromotion';
- const collatorSelection = ['authorship', 'session', 'collatorselection'];
- const preimage = ['preimage'];
- const governance = [
- 'council',
- 'councilmembership',
- 'democracy',
- 'fellowshipcollective',
- 'fellowshipreferenda',
- 'origins',
- 'scheduler',
- 'technicalcommittee',
- 'technicalcommitteemembership',
- 'identity',
- ];
- const testUtils = 'testutils';
-
- if(chain.eq('opal')) {
- requiredPallets.push(
- refungible,
- foreignAssets,
- appPromotion,
- testUtils,
- ...collatorSelection,
- ...preimage,
- ...governance,
- );
- } else if(chain.eq('quartz') || chain.eq('sapphire')) {
- requiredPallets.push(
- refungible,
- appPromotion,
- foreignAssets,
- ...collatorSelection,
- ...preimage,
- ...governance,
- );
- } else if(chain.eq('unique')) {
- // Insert Unique additional pallets here
- requiredPallets.push(
- refungible,
- foreignAssets,
- appPromotion,
- ...preimage,
- ...governance,
- );
- }
- });
- });
-
- itSub('Required pallets are present', ({helper}) => {
- expect(helper.fetchAllPalletNames()).to.contain.members([...requiredPallets].sort());
- });
-
- itSub('Governance and consensus pallets are present', ({helper}) => {
- expect(helper.fetchAllPalletNames()).to.contain.members([...consensusPallets].sort());
- });
-
- itSub('No extra pallets are included', ({helper}) => {
- expect(helper.fetchAllPalletNames().sort()).to.be.deep.equal([...requiredPallets, ...consensusPallets].sort());
- });
-});
js-packages/tests/src/performance.seq.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/performance.seq.test.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2019-2023 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {ApiPromise} from '@polkadot/api';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from './util/index.js';
-import type {ICrossAccountId, IProperty} from '@unique/playgrounds/src/types.js';
-import {UniqueHelper} from '@unique/playgrounds/src/unique.js';
-
-describe('Performace tests', () => {
- let alice: IKeyringPair;
- const MAX_TOKENS_TO_MINT = 120;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([100_000n], donor);
- });
- });
-
- itSub('NFT tokens minting', async ({helper}) => {
- const propertyKey = 'prop-a';
- const collection = await helper.nft.mintCollection(alice, {
- name: 'test properties',
- description: 'test properties collection',
- tokenPrefix: 'TPC',
- tokenPropertyPermissions: [
- {key: propertyKey, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}},
- ],
- });
-
- const step = 1_000;
- const sizeOfKey = sizeOfEncodedStr(propertyKey);
- let currentSize = step;
- let startCount = 0;
- let minterFunc = tryMintUnsafeRPC;
- try {
- startCount = await tryMintUnsafeRPC(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});
- }
- catch (e) {
- startCount = await tryMintExplicit(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address});
- minterFunc = tryMintExplicit;
- }
-
- expect(startCount).to.be.equal(MAX_TOKENS_TO_MINT);
-
- while(currentSize <= 32_000) {
- const property = {key: propertyKey, value: 'A'.repeat(currentSize - sizeOfKey - sizeOfInt(currentSize))};
- const tokens = await minterFunc(helper, alice, MAX_TOKENS_TO_MINT, collection.collectionId, {Substrate: alice.address}, property);
- expect(tokens).to.be.equal(MAX_TOKENS_TO_MINT);
-
- currentSize += step;
- await helper.wait.newBlocks(2);
- }
- });
-});
-
-
-const dryRun = async (api: ApiPromise, signer: IKeyringPair, tx: any) => {
- const signed = await tx.signAsync(signer);
- const dryRun = await api.rpc.system.dryRun(signed.toHex());
- return dryRun.isOk && dryRun.asOk.isOk;
-};
-
-const getTokens = (tokensCount: number, owner: ICrossAccountId, property?: IProperty) => (new Array(tokensCount)).fill(0).map(() => {
- const token = {owner} as {owner: ICrossAccountId, properties?: IProperty[]};
- if(property) token.properties = [property];
- return token;
-});
-
-const tryMintUnsafeRPC = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {
- if(tokensCount < 10) console.log('try mint', tokensCount, 'tokens');
- const tokens = getTokens(tokensCount, owner, property);
- const tx = helper.constructApiCall('api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
- if(!(await dryRun(helper.getApi(), signer, tx))) {
- if(tokensCount < 2) return 0;
- return await tryMintUnsafeRPC(helper, signer, tokensCount - 1, collectionId, owner, property);
- }
- await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
- return tokensCount;
-};
-
-const tryMintExplicit = async (helper: UniqueHelper, signer: IKeyringPair, tokensCount: number, collectionId: number, owner: ICrossAccountId, property?: IProperty): Promise<number> => {
- const tokens = getTokens(tokensCount, owner, property);
- try {
- await helper.executeExtrinsic(signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}]);
- }
- catch (e) {
- if(tokensCount < 2) return 0;
- return await tryMintExplicit(helper, signer, tokensCount - 1, collectionId, owner, property);
- }
- return tokensCount;
-};
-
-function sizeOfInt(i: number) {
- if(i < 0 || i > 0xffffffff) throw new Error('out of range');
- if(i < 0b11_1111) {
- return 1;
- } else if(i < 0b11_1111_1111_1111) {
- return 2;
- } else if(i < 0b11_1111_1111_1111_1111_1111_1111_1111) {
- return 4;
- } else {
- return 5;
- }
-}
-
-const UTF8_ENCODER = new TextEncoder();
-function sizeOfEncodedStr(v: string) {
- const encoded = UTF8_ENCODER.encode(v);
- return sizeOfInt(encoded.length) + encoded.length;
-}
js-packages/tests/src/refungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/refungible.test.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from './util/index.js';
-
-const MAX_REFUNGIBLE_PIECES = 1_000_000_000_000_000_000_000n;
-
-describe('integration test: Refungible functionality:', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
- });
- });
-
- itSub('Create refungible collection and token', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const itemCountBefore = await collection.getLastTokenId();
- const token = await collection.mintToken(alice, 100n);
-
- const itemCountAfter = await collection.getLastTokenId();
-
- // What to expect
- expect(token?.tokenId).to.be.gte(itemCountBefore);
- expect(itemCountAfter).to.be.equal(itemCountBefore + 1);
- expect(itemCountAfter.toString()).to.be.equal(token?.tokenId.toString());
- });
-
- itSub('Checking RPC methods when interacting with maximum allowed values (MAX_REFUNGIBLE_PIECES)', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const token = await collection.mintToken(alice, MAX_REFUNGIBLE_PIECES);
-
- expect(await collection.getTokenBalance(token.tokenId, {Substrate: alice.address})).to.be.equal(MAX_REFUNGIBLE_PIECES);
-
- await collection.transferToken(alice, token.tokenId, {Substrate: bob.address}, MAX_REFUNGIBLE_PIECES);
- expect(await collection.getTokenBalance(token.tokenId, {Substrate: bob.address})).to.be.equal(MAX_REFUNGIBLE_PIECES);
- expect(await token.getTotalPieces()).to.be.equal(MAX_REFUNGIBLE_PIECES);
-
- await expect(collection.mintToken(alice, MAX_REFUNGIBLE_PIECES + 1n))
- .to.eventually.be.rejectedWith(/refungible\.WrongRefungiblePieces/);
- });
-
- itSub('RPC method tokenOwners for refungible collection and token', async ({helper}) => {
- const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
- const facelessCrowd = (await helper.arrange.createAccounts(Array(7).fill(0n), donor)).map(keyring => ({Substrate: keyring.address}));
-
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
- const token = await collection.mintToken(alice, 10_000n);
-
- await token.transfer(alice, {Substrate: bob.address}, 1000n);
- await token.transfer(alice, ethAcc, 900n);
-
- for(let i = 0; i < 7; i++) {
- await token.transfer(alice, facelessCrowd[i], 50n * BigInt(i + 1));
- }
-
- const owners = await token.getTop10Owners();
-
- // What to expect
- expect(owners).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]);
- expect(owners.length).to.be.equal(10);
-
- const [eleven] = await helper.arrange.createAccounts([0n], donor);
- expect(await token.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true;
- expect((await token.getTop10Owners()).length).to.be.equal(10);
- });
-
- itSub('Create multiple tokens', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- // TODO: fix mintMultipleTokens
- // await collection.mintMultipleTokens(alice, [
- // {owner: {Substrate: alice.address}, pieces: 1n},
- // {owner: {Substrate: alice.address}, pieces: 2n},
- // {owner: {Substrate: alice.address}, pieces: 100n},
- // ]);
- await helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, [
- {pieces: 1n},
- {pieces: 2n},
- {pieces: 100n},
- ]);
- const lastTokenId = await collection.getLastTokenId();
- expect(lastTokenId).to.be.equal(3);
- expect(await collection.getTokenBalance(lastTokenId, {Substrate: alice.address})).to.be.equal(100n);
- });
-
- itSub('Set allowance for token', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
-
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n);
-
- expect(await token.approve(alice, {Substrate: bob.address}, 60n)).to.be.true;
- expect(await token.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(60n);
-
- expect(await token.transferFrom(bob, {Substrate: alice.address}, {Substrate: bob.address}, 20n)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(80n);
- expect(await token.getBalance({Substrate: bob.address})).to.be.equal(20n);
- expect(await token.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(40n);
- });
-
- itSub('Create new collection with properties', async ({helper}) => {
- const properties = [{key: 'key1', value: 'val1'}];
- const tokenPropertyPermissions = [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}];
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test', properties, tokenPropertyPermissions});
- const info = await collection.getData();
- expect(info?.raw.properties).to.be.deep.equal(properties);
- expect(info?.raw.tokenPropertyPermissions).to.be.deep.equal(tokenPropertyPermissions);
- });
-});
js-packages/tests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/removeCollectionAdmin.test.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test removeCollectionAdmin(collection_id, account_id):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
- });
- });
-
- itSub('Remove collection admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-1', tokenPrefix: 'RCA'});
- const collectionInfo = await collection.getData();
- expect(collectionInfo?.raw.owner.toString()).to.be.deep.eq(alice.address);
- // first - add collection admin Bob
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- const adminListAfterAddAdmin = await collection.getAdmins();
- expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
-
- // then remove bob from admins of collection
- await collection.removeAdmin(alice, {Substrate: bob.address});
-
- const adminListAfterRemoveAdmin = await collection.getAdmins();
- expect(adminListAfterRemoveAdmin).not.to.be.deep.contains({Substrate: bob.address});
- });
-
- itSub('Remove admin from collection that has no admins', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-2', tokenPrefix: 'RCA'});
-
- const adminListBeforeAddAdmin = await collection.getAdmins();
- expect(adminListBeforeAddAdmin).to.have.lengthOf(0);
-
- await expect(collection.removeAdmin(alice, {Substrate: alice.address})).to.be.rejectedWith('common.UserIsNotCollectionAdmin');
- });
-});
-
-describe('Negative Integration Test removeCollectionAdmin(collection_id, account_id):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
- });
- });
-
- itSub('Can\'t remove collection admin from not existing collection', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
-
- await expect(helper.collection.removeAdmin(alice, collectionId, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Can\'t remove collection admin from deleted collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-2', tokenPrefix: 'RCA'});
-
- expect(await collection.burn(alice)).to.be.true;
-
- await expect(helper.collection.removeAdmin(alice, collection.collectionId, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Regular user can\'t remove collection admin', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-3', tokenPrefix: 'RCA'});
-
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- await expect(collection.removeAdmin(charlie, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('Admin can\'t remove collection admin.', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-4', tokenPrefix: 'RCA'});
-
- await collection.addAdmin(alice, {Substrate: bob.address});
- await collection.addAdmin(alice, {Substrate: charlie.address});
-
- const adminListAfterAddAdmin = await collection.getAdmins();
- expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});
- expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: charlie.address});
-
- await expect(collection.removeAdmin(charlie, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.NoPermission/);
-
- const adminListAfterRemoveAdmin = await collection.getAdmins();
- expect(adminListAfterRemoveAdmin).to.be.deep.contains({Substrate: bob.address});
- expect(adminListAfterRemoveAdmin).to.be.deep.contains({Substrate: charlie.address});
- });
-});
js-packages/tests/src/removeCollectionSponsor.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/removeCollectionSponsor.test.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('integration test: ext. removeCollectionSponsor():', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
- });
- });
-
- itSub('Removing NFT collection sponsor stops sponsorship', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-1', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- await collection.removeSponsor(alice);
-
- // Find unused address
- const [zeroBalance] = await helper.arrange.createAccounts([0n], donor);
-
- // Mint token for unused address
- const token = await collection.mintToken(alice, {Substrate: zeroBalance.address});
-
- // Transfer this tokens from unused address to Alice - should fail
- const sponsorBalanceBefore = await helper.balance.getSubstrate(bob.address);
- await expect(token.transfer(zeroBalance, {Substrate: alice.address}))
- .to.be.rejectedWith('Inability to pay some fees');
- const sponsorBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);
- });
-
- itSub('Remove a sponsor after it was already removed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-2', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- await expect(collection.removeSponsor(alice)).to.not.be.rejected;
- await expect(collection.removeSponsor(alice)).to.not.be.rejected;
- });
-
- itSub('Remove sponsor in a collection that never had the sponsor set', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-3', tokenPrefix: 'RCS'});
- await expect(collection.removeSponsor(alice)).to.not.be.rejected;
- });
-
- itSub('Remove sponsor for a collection that had the sponsor set, but not confirmed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-4', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await expect(collection.removeSponsor(alice)).to.not.be.rejected;
- });
-
- itSub('Remove a sponsor from a collection with collection admin permissions', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-1', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await collection.addAdmin(alice, {Substrate: charlie.address});
- await expect(collection.removeSponsor(charlie)).not.to.be.rejected;
- });
-});
-
-describe('(!negative test!) integration test: ext. removeCollectionSponsor():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
- });
- });
-
- itSub('(!negative test!) Remove sponsor for a collection that never existed', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- await expect(helper.collection.removeSponsor(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('(!negative test!) Remove sponsor for a collection by regular user', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-2', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await expect(collection.removeSponsor(charlie)).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('(!negative test!) Remove sponsor in a destroyed collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-3', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await collection.burn(alice);
- await expect(collection.removeSponsor(alice)).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('Set - remove - confirm: fails', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-4', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await collection.removeSponsor(alice);
- await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- });
-
- itSub('Set - confirm - remove - confirm: Sponsor cannot come back', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-5', tokenPrefix: 'RCS'});
- await collection.setSponsor(alice, bob.address);
- await collection.confirmSponsorship(bob);
- await collection.removeSponsor(alice);
- await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
- });
-});
js-packages/tests/src/rpc.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/rpc.test.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect} from './util/index.js';
-import {ICrossAccountId} from '@unique/playgrounds/src/types.js';
-
-describe('integration test: RPC methods', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
- });
- });
-
- itSub('returns None for fungible collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'RPC-1', tokenPrefix: 'RPC'});
- const owner = (await helper.callRpc('api.rpc.unique.tokenOwner', [collection.collectionId, 0])).toJSON() as any;
- expect(owner).to.be.null;
- });
-
- itSub('RPC method tokenOwners for fungible collection and token', async ({helper}) => {
- // Set-up a few token owners of all stripes
- const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
- const facelessCrowd = (await helper.arrange.createAccounts([0n, 0n, 0n, 0n, 0n, 0n, 0n], donor))
- .map(i => ({Substrate: i.address}));
-
- const collection = await helper.ft.mintCollection(alice, {name: 'RPC-2', tokenPrefix: 'RPC'});
- // mint some maximum (u128) amounts of tokens possible
- await collection.mint(alice, (1n << 128n) - 1n);
-
- await collection.transfer(alice, {Substrate: bob.address}, 1000n);
- await collection.transfer(alice, ethAcc, 900n);
-
- for(let i = 0; i < facelessCrowd.length; i++) {
- await collection.transfer(alice, facelessCrowd[i], 1n);
- }
- // Set-up over
-
- const owners = await helper.callRpc('api.rpc.unique.tokenOwners', [collection.collectionId, 0]);
- const ids = owners.toHuman() as ICrossAccountId[];
-
- expect(ids).to.have.deep.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]);
- expect(owners.length == 10).to.be.true;
-
- // Make sure only 10 results are returned with this RPC
- const [eleven] = await helper.arrange.createAccounts([0n], donor);
- expect(await collection.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true;
- expect((await helper.callRpc('api.rpc.unique.tokenOwners', [collection.collectionId, 0])).length).to.be.equal(10);
- });
-});
js-packages/tests/src/scheduler.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/scheduler.seqtest.ts
+++ /dev/null
@@ -1,796 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util/index.js';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {DevUniqueHelper, Event} from '@unique/playgrounds/src/unique.dev.js';
-
-describe('Scheduling token and balance transfers', () => {
- let superuser: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.UniqueScheduler]);
-
- superuser = await privateKey('//Alice');
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
-
- await helper.testUtils.enable(Pallets.TestUtils);
- });
- });
-
- beforeEach(async () => {
- await usingPlaygrounds(async (helper) => {
- await helper.wait.noScheduledTasks();
- });
- });
-
- itSched('Can delay a transfer of an owned token', async (scheduleKind, {helper}) => {
- const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(alice);
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const blocksBeforeExecution = 4;
- await helper.scheduler.scheduleAfter(blocksBeforeExecution, {scheduledId})
- .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
- const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
- });
-
- itSched('Can transfer funds periodically', async (scheduleKind, {helper}) => {
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const waitForBlocks = 1;
-
- const amount = 1n * helper.balance.getOneTokenNominal();
- const periodic = {
- period: 2,
- repetitions: 2,
- };
-
- const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic})
- .balance.transferToSubstrate(alice, bob.address, amount);
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);
- expect(bobsBalanceAfterFirst)
- .to.be.equal(
- bobsBalanceBefore + 1n * amount,
- '#1 Balance of the recipient should be increased by 1 * amount',
- );
-
- await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
-
- const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);
- expect(bobsBalanceAfterSecond)
- .to.be.equal(
- bobsBalanceBefore + 2n * amount,
- '#2 Balance of the recipient should be increased by 2 * amount',
- );
- });
-
- itSub('Can cancel a scheduled operation which has not yet taken effect', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(alice);
-
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 4;
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
- .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.scheduler.cancelScheduled(alice, scheduledId);
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('Can cancel a periodic operation (transfer of funds)', async ({helper}) => {
- const waitForBlocks = 1;
- const periodic = {
- period: 3,
- repetitions: 2,
- };
-
- const scheduledId = helper.arrange.makeScheduledId();
-
- const amount = 1n * helper.balance.getOneTokenNominal();
-
- const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic})
- .balance.transferToSubstrate(alice, bob.address, amount);
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);
-
- expect(bobsBalanceAfterFirst)
- .to.be.equal(
- bobsBalanceBefore + 1n * amount,
- '#1 Balance of the recipient should be increased by 1 * amount',
- );
-
- await helper.scheduler.cancelScheduled(alice, scheduledId);
- await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
-
- const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);
- expect(bobsBalanceAfterSecond)
- .to.be.equal(
- bobsBalanceAfterFirst,
- '#2 Balance of the recipient should not be changed',
- );
- });
-
- itSched('scheduler will not insert more tasks than allowed', async (scheduleKind, {helper}) => {
- const maxScheduledPerBlock = 50;
- let fillScheduledIds = new Array(maxScheduledPerBlock);
- let extraScheduledId = undefined;
-
- if(scheduleKind == 'named') {
- const scheduledIds = helper.arrange.makeScheduledIds(maxScheduledPerBlock + 1);
- fillScheduledIds = scheduledIds.slice(0, maxScheduledPerBlock);
- extraScheduledId = scheduledIds[maxScheduledPerBlock];
- }
-
- // Since the dev node has Instant Seal,
- // we need a larger gap between the current block and the target one.
- //
- // We will schedule `maxScheduledPerBlock` transaction into the target block,
- // so we need at least `maxScheduledPerBlock`-wide gap.
- // We add some additional blocks to this gap to mitigate possible PolkadotJS delays.
- const waitForBlocks = await helper.arrange.isDevNode() ? maxScheduledPerBlock + 5 : 5;
-
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks;
-
- const amount = 1n * helper.balance.getOneTokenNominal();
-
- const balanceBefore = await helper.balance.getSubstrate(bob.address);
-
- // Fill the target block
- for(let i = 0; i < maxScheduledPerBlock; i++) {
- await helper.scheduler.scheduleAt(executionBlock, {scheduledId: fillScheduledIds[i]})
- .balance.transferToSubstrate(superuser, bob.address, amount);
- }
-
- // Try to schedule a task into a full block
- await expect(helper.scheduler.scheduleAt(executionBlock, {scheduledId: extraScheduledId})
- .balance.transferToSubstrate(superuser, bob.address, amount))
- .to.be.rejectedWith(/scheduler\.AgendaIsExhausted/);
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const balanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(balanceAfter > balanceBefore).to.be.true;
-
- const diff = balanceAfter - balanceBefore;
- expect(diff).to.be.equal(amount * BigInt(maxScheduledPerBlock));
- });
-
- itSched.ifWithPallets('Scheduled tasks are transactional', [Pallets.TestUtils], async (scheduleKind, {helper}) => {
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const waitForBlocks = 4;
-
- const initTestVal = 42;
- const changedTestVal = 111;
-
- await helper.testUtils.setTestValue(alice, initTestVal);
-
- await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId})
- .testUtils.setTestValueAndRollback(alice, changedTestVal);
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const testVal = await helper.testUtils.testValue();
- expect(testVal, 'The test value should NOT be commited')
- .to.be.equal(initTestVal);
- });
-
- itSched.ifWithPallets('Scheduled tasks should take correct fees', [Pallets.TestUtils], async function(scheduleKind, {helper}) {
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const waitForBlocks = 4;
- const periodic = {
- period: 2,
- repetitions: 2,
- };
-
- const dummyTx = helper.constructApiCall('api.tx.testUtils.justTakeFee', []);
- const scheduledLen = dummyTx.callIndex.length;
-
- const expectedScheduledFee = (await helper.getPaymentInfo(alice, dummyTx, scheduledLen))
- .partialFee.toBigInt();
-
- await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId, periodic})
- .testUtils.justTakeFee(alice);
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- const aliceInitBalance = await helper.balance.getSubstrate(alice.address);
- let diff;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const aliceBalanceAfterFirst = await helper.balance.getSubstrate(alice.address);
- expect(
- aliceBalanceAfterFirst < aliceInitBalance,
- '[after execution #1] Scheduled task should take a fee',
- ).to.be.true;
-
- diff = aliceInitBalance - aliceBalanceAfterFirst;
- expect(diff).to.be.equal(
- expectedScheduledFee,
- 'Scheduled task should take the right amount of fees',
- );
-
- await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
-
- const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);
- expect(
- aliceBalanceAfterSecond < aliceBalanceAfterFirst,
- '[after execution #2] Scheduled task should take a fee',
- ).to.be.true;
-
- diff = aliceBalanceAfterFirst - aliceBalanceAfterSecond;
- expect(diff).to.be.equal(
- expectedScheduledFee,
- 'Scheduled task should take the right amount of fees',
- );
- });
-
- // Check if we can cancel a scheduled periodic operation
- // in the same block in which it is running
- itSub.ifWithPallets('Can cancel the periodic sheduled tx when the tx is running', [Pallets.TestUtils], async ({helper}) => {
- const currentBlockNumber = await helper.chain.getLatestBlockNumber();
- const blocksBeforeExecution = 10;
- const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
-
- const [
- scheduledId,
- scheduledCancelId,
- ] = helper.arrange.makeScheduledIds(2);
-
- const periodic = {
- period: 5,
- repetitions: 5,
- };
-
- const initTestVal = 0;
- const incTestVal = initTestVal + 1;
- const finalTestVal = initTestVal + 2;
-
- await helper.testUtils.setTestValue(alice, initTestVal);
-
- await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {scheduledId, periodic})
- .testUtils.incTestValue(alice);
-
- // Cancel the inc tx after 2 executions
- // *in the same block* in which the second execution is scheduled
- await helper.scheduler.scheduleAt(
- firstExecutionBlockNumber + periodic.period,
- {scheduledId: scheduledCancelId},
- ).scheduler.cancelScheduled(alice, scheduledId);
-
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
-
- // execution #0
- expect(await helper.testUtils.testValue())
- .to.be.equal(incTestVal);
-
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);
-
- // execution #1
- expect(await helper.testUtils.testValue())
- .to.be.equal(finalTestVal);
-
- for(let i = 1; i < periodic.repetitions; i++) {
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period * (i + 1));
- expect(await helper.testUtils.testValue())
- .to.be.equal(finalTestVal);
- }
- });
-
- itSub.ifWithPallets('A scheduled operation can cancel itself', [Pallets.TestUtils], async ({helper}) => {
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 4;
- const periodic = {
- period: 2,
- repetitions: 5,
- };
-
- const initTestVal = 0;
- const maxTestVal = 2;
-
- await helper.testUtils.setTestValue(alice, initTestVal);
-
- await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId, periodic})
- .testUtils.selfCancelingInc(alice, scheduledId, maxTestVal);
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- // execution #0
- expect(await helper.testUtils.testValue())
- .to.be.equal(initTestVal + 1);
-
- await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
-
- // execution #1
- expect(await helper.testUtils.testValue())
- .to.be.equal(initTestVal + 2);
-
- await helper.wait.forParachainBlockNumber(executionBlock + 2 * periodic.period);
-
- // <canceled>
- expect(await helper.testUtils.testValue())
- .to.be.equal(initTestVal + 2);
- });
-
- itSub('Root can cancel any scheduled operation', async ({helper}) => {
- const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(bob);
-
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 4;
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
- .nft.transferToken(bob, collection.collectionId, token.tokenId, {Substrate: alice.address});
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.getSudo().scheduler.cancelScheduled(superuser, scheduledId);
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
- });
-
- itSched('Root can set prioritized scheduled operation', async (scheduleKind, {helper}) => {
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const waitForBlocks = 4;
-
- const amount = 42n * helper.balance.getOneTokenNominal();
-
- const balanceBefore = await helper.balance.getSubstrate(charlie.address);
-
- await helper.getSudo()
- .scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42})
- .balance.forceTransferToSubstrate(superuser, bob.address, charlie.address, amount);
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const balanceAfter = await helper.balance.getSubstrate(charlie.address);
-
- expect(balanceAfter > balanceBefore).to.be.true;
-
- const diff = balanceAfter - balanceBefore;
- expect(diff).to.be.equal(amount);
- });
-
- itSub("Root can change scheduled operation's priority", async ({helper}) => {
- const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(bob);
-
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 6;
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
- .nft.transferToken(bob, collection.collectionId, token.tokenId, {Substrate: alice.address});
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- const priority = 112;
- await helper.getSudo().scheduler.changePriority(superuser, scheduledId, priority);
-
- const priorityChanged = await helper.wait.expectEvent(waitForBlocks, Event.UniqueScheduler.PriorityChanged);
-
- const [blockNumber, index] = priorityChanged.task();
- expect(blockNumber).to.be.equal(executionBlock);
- expect(index).to.be.equal(0);
-
- expect(priorityChanged.priority().toString()).to.be.equal(priority.toString());
- });
-
- itSub('Prioritized operations execute in valid order', async ({helper}) => {
- const [
- scheduledFirstId,
- scheduledSecondId,
- ] = helper.arrange.makeScheduledIds(2);
-
- const currentBlockNumber = await helper.chain.getLatestBlockNumber();
- const blocksBeforeExecution = 6;
- const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
-
- const prioHigh = 0;
- const prioLow = 255;
-
- const periodic = {
- period: 6,
- repetitions: 2,
- };
-
- const amount = 1n * helper.balance.getOneTokenNominal();
-
- // Scheduler a task with a lower priority first, then with a higher priority
- await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, {
- scheduledId: scheduledFirstId,
- priority: prioLow,
- periodic,
- }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);
-
- await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, {
- scheduledId: scheduledSecondId,
- priority: prioHigh,
- periodic,
- }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);
-
- const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');
-
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
-
- // Flip priorities
- await helper.getSudo().scheduler.changePriority(superuser, scheduledFirstId, prioHigh);
- await helper.getSudo().scheduler.changePriority(superuser, scheduledSecondId, prioLow);
-
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);
-
- const dispatchEvents = capture.extractCapturedEvents();
- expect(dispatchEvents.length).to.be.equal(4);
-
- const dispatchedIds = dispatchEvents.map(r => r.event.data[1].toString());
-
- const firstExecuctionIds = [dispatchedIds[0], dispatchedIds[1]];
- const secondExecuctionIds = [dispatchedIds[2], dispatchedIds[3]];
-
- expect(firstExecuctionIds[0]).to.be.equal(scheduledSecondId);
- expect(firstExecuctionIds[1]).to.be.equal(scheduledFirstId);
-
- expect(secondExecuctionIds[0]).to.be.equal(scheduledFirstId);
- expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);
- });
-
- itSched('Periodic operations always can be rescheduled', async (scheduleKind, {helper}) => {
- const maxScheduledPerBlock = 50;
- const numFilledBlocks = 3;
- const ids = helper.arrange.makeScheduledIds(numFilledBlocks * maxScheduledPerBlock + 1);
- const periodicId = scheduleKind == 'named' ? ids[0] : undefined;
- const fillIds = ids.slice(1);
-
- const fillScheduleFn = scheduleKind == 'named' ? 'scheduleNamed' : 'schedule';
-
- const initTestVal = 0;
- const firstExecTestVal = 1;
- const secondExecTestVal = 2;
- await helper.testUtils.setTestValue(alice, initTestVal);
-
- const currentBlockNumber = await helper.chain.getLatestBlockNumber();
- const blocksBeforeExecution = 8;
- const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
-
- const period = 5;
-
- const periodic = {
- period,
- repetitions: 2,
- };
-
- // Fill `numFilledBlocks` blocks beginning from the block in which the second execution should occur
- const txs = [];
- for(let offset = 0; offset < numFilledBlocks; offset ++) {
- for(let i = 0; i < maxScheduledPerBlock; i++) {
-
- const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]);
-
- const when = firstExecutionBlockNumber + period + offset;
- const mandatoryArgs = [when, null, null, scheduledTx];
- const scheduleArgs = scheduleKind == 'named'
- ? [fillIds[i + offset * maxScheduledPerBlock], ...mandatoryArgs]
- : mandatoryArgs;
-
- const tx = helper.constructApiCall(`api.tx.scheduler.${fillScheduleFn}`, scheduleArgs);
-
- txs.push(tx);
- }
- }
- await helper.executeExtrinsic(alice, 'api.tx.testUtils.batchAll', [txs], true);
-
- await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {
- scheduledId: periodicId,
- periodic,
- }).testUtils.incTestValue(alice);
-
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
- expect(await helper.testUtils.testValue()).to.be.equal(firstExecTestVal);
-
- await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + period + numFilledBlocks);
-
- // The periodic operation should be postponed by `numFilledBlocks`
- for(let i = 0; i < numFilledBlocks; i++) {
- expect(await helper.testUtils.testValue(firstExecutionBlockNumber + period + i)).to.be.equal(firstExecTestVal);
- }
-
- // After the `numFilledBlocks` the periodic operation will eventually be executed
- expect(await helper.testUtils.testValue()).to.be.equal(secondExecTestVal);
- });
-
- itSched('scheduled operations does not change nonce', async (scheduleKind, {helper}) => {
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const blocksBeforeExecution = 4;
-
- await helper.scheduler
- .scheduleAfter<DevUniqueHelper>(blocksBeforeExecution, {scheduledId})
- .balance.transferToSubstrate(alice, bob.address, 1n);
- const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;
-
- const initNonce = await helper.chain.getNonce(alice.address);
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const finalNonce = await helper.chain.getNonce(alice.address);
-
- expect(initNonce).to.be.equal(finalNonce);
- });
-});
-
-describe('Negative Test: Scheduling', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.UniqueScheduler]);
-
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
-
- await helper.testUtils.enable(Pallets.TestUtils);
- });
- });
-
- itSub("Can't overwrite a scheduled ID", async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(alice);
-
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 4;
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
- .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId});
- await expect(scheduled.balance.transferToSubstrate(alice, bob.address, 1n * helper.balance.getOneTokenNominal()))
- .to.be.rejectedWith(/scheduler\.FailedToSchedule/);
-
- const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(bobsBalanceBefore).to.be.equal(bobsBalanceAfter);
- });
-
- itSub("Can't cancel an operation which is not scheduled", async ({helper}) => {
- const scheduledId = helper.arrange.makeScheduledId();
- await expect(helper.scheduler.cancelScheduled(alice, scheduledId))
- .to.be.rejectedWith(/scheduler\.NotFound/);
- });
-
- itSub("Can't cancel a non-owned scheduled operation", async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(alice);
-
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 4;
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
- .nft.transferToken(alice, collection.collectionId, token.tokenId, {Substrate: bob.address});
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await expect(helper.scheduler.cancelScheduled(bob, scheduledId))
- .to.be.rejectedWith(/BadOrigin/);
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});
- });
-
- itSched("Regular user can't set prioritized scheduled operation", async (scheduleKind, {helper}) => {
- const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
- const waitForBlocks = 4;
-
- const amount = 42n * helper.balance.getOneTokenNominal();
-
- const balanceBefore = await helper.balance.getSubstrate(bob.address);
-
- const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42});
-
- await expect(scheduled.balance.transferToSubstrate(alice, bob.address, amount))
- .to.be.rejectedWith(/BadOrigin/);
-
- const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
-
- await helper.wait.forParachainBlockNumber(executionBlock);
-
- const balanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(balanceAfter).to.be.equal(balanceBefore);
- });
-
- itSub("Regular user can't change scheduled operation's priority", async ({helper}) => {
- const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});
- const token = await collection.mintToken(bob);
-
- const scheduledId = helper.arrange.makeScheduledId();
- const waitForBlocks = 4;
-
- await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId})
- .nft.transferToken(bob, collection.collectionId, token.tokenId, {Substrate: alice.address});
-
- const priority = 112;
- await expect(helper.scheduler.changePriority(alice, scheduledId, priority))
- .to.be.rejectedWith(/BadOrigin/);
-
- await helper.wait.expectEvent(waitForBlocks, Event.UniqueScheduler.PriorityChanged);
- });
-});
-
-// Implementation of the functionality tested here was postponed/shelved
-describe.skip('Sponsoring scheduling', () => {
- // let alice: IKeyringPair;
- // let bob: IKeyringPair;
-
- // before(async() => {
- // await usingApi(async (_, privateKey) => {
- // alice = privateKey('//Alice');
- // bob = privateKey('//Bob');
- // });
- // });
-
- it('Can sponsor scheduling a transaction', async () => {
- // const collectionId = await createCollectionExpectSuccess();
- // await setCollectionSponsorExpectSuccess(collectionId, bob.address);
- // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
-
- // await usingApi(async api => {
- // const scheduledId = await makeScheduledId();
- // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-
- // const bobBalanceBefore = await getFreeBalance(bob);
- // const waitForBlocks = 4;
- // // no need to wait to check, fees must be deducted on scheduling, immediately
- // await scheduleTransferExpectSuccess(api, collectionId, tokenId, alice, bob, 0, waitForBlocks, scheduledId);
- // const bobBalanceAfter = await getFreeBalance(bob);
- // // expect(aliceBalanceAfter == aliceBalanceBefore).to.be.true;
- // expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
- // // wait for sequentiality matters
- // await waitNewBlocks(waitForBlocks - 1);
- // });
- });
-
- it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => {
- // await usingApi(async (api, privateKey) => {
- // // Find an empty, unused account
- // const zeroBalance = await findUnusedAddress(api, privateKey);
-
- // const collectionId = await createCollectionExpectSuccess();
-
- // // Add zeroBalance address to allow list
- // await enablePublicMintingExpectSuccess(alice, collectionId);
- // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
-
- // // Grace zeroBalance with money, enough to cover future transactions
- // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
- // await submitTransactionAsync(alice, balanceTx);
-
- // // Mint a fresh NFT
- // const tokenId = await createItemExpectSuccess(zeroBalance, collectionId, 'NFT');
- // const scheduledId = await makeScheduledId();
-
- // // Schedule transfer of the NFT a few blocks ahead
- // const waitForBlocks = 5;
- // await scheduleTransferExpectSuccess(api, collectionId, tokenId, zeroBalance, alice, 1, waitForBlocks, scheduledId);
-
- // // Get rid of the account's funds before the scheduled transaction takes place
- // const balanceTx2 = api.tx.balances.transfer(alice.address, UNIQUE * 68n / 100n);
- // const events = await submitTransactionAsync(zeroBalance, balanceTx2);
- // expect(getGenericResult(events).success).to.be.true;
- // /*const emptyBalanceTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); // do not null reserved?
- // const sudoTx = api.tx.sudo.sudo(emptyBalanceTx as any);
- // const events = await submitTransactionAsync(alice, sudoTx);
- // expect(getGenericResult(events).success).to.be.true;*/
-
- // // Wait for a certain number of blocks, discarding the ones that already happened while accepting the late transactions
- // await waitNewBlocks(waitForBlocks - 3);
-
- // expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(alice.address));
- // });
- });
-
- it('Sponsor going bankrupt does not impact a scheduled transaction', async () => {
- // const collectionId = await createCollectionExpectSuccess();
-
- // await usingApi(async (api, privateKey) => {
- // const zeroBalance = await findUnusedAddress(api, privateKey);
- // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
- // await submitTransactionAsync(alice, balanceTx);
-
- // await setCollectionSponsorExpectSuccess(collectionId, zeroBalance.address);
- // await confirmSponsorshipByKeyExpectSuccess(collectionId, zeroBalance);
-
- // const scheduledId = await makeScheduledId();
- // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-
- // const waitForBlocks = 5;
- // await scheduleTransferExpectSuccess(api, collectionId, tokenId, alice, zeroBalance, 1, waitForBlocks, scheduledId);
-
- // const emptyBalanceSponsorTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0);
- // const sudoTx = api.tx.sudo.sudo(emptyBalanceSponsorTx as any);
- // const events = await submitTransactionAsync(alice, sudoTx);
- // expect(getGenericResult(events).success).to.be.true;
-
- // // Wait for a certain number of blocks, save for the ones that already happened while accepting the late transactions
- // await waitNewBlocks(waitForBlocks - 3);
-
- // expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(zeroBalance.address));
- // });
- });
-
- it('Exceeding sponsor rate limit without having enough funds prevents scheduling a periodic transaction', async () => {
- // const collectionId = await createCollectionExpectSuccess();
- // await setCollectionSponsorExpectSuccess(collectionId, bob.address);
- // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
-
- // await usingApi(async (api, privateKey) => {
- // const zeroBalance = await findUnusedAddress(api, privateKey);
-
- // await enablePublicMintingExpectSuccess(alice, collectionId);
- // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
-
- // const bobBalanceBefore = await getFreeBalance(bob);
-
- // const createData = {nft: {const_data: [], variable_data: []}};
- // const creationTx = api.tx.unique.createItem(collectionId, normalizeAccountId(zeroBalance), createData as any);
- // const scheduledId = await makeScheduledId();
-
- // /*const badTransaction = async function () {
- // await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);
- // };
- // await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');*/
-
- // await expect(scheduleAfter(api, creationTx, zeroBalance, 3, scheduledId, 1, 3)).to.be.rejectedWith(/Inability to pay some fees/);
-
- // expect(await getFreeBalance(bob)).to.be.equal(bobBalanceBefore);
- // });
- });
-});
js-packages/tests/src/setCollectionLimits.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/setCollectionLimits.test.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-const accountTokenOwnershipLimit = 0;
-const sponsoredDataSize = 0;
-const sponsorTransferTimeout = 1;
-const tokenLimit = 10;
-
-describe('setCollectionLimits positive', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
- });
- });
-
- itSub('execute setCollectionLimits with predefined params', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-1', tokenPrefix: 'SCL'});
-
- await collection.setLimits(
- alice,
- {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: true,
- ownerCanDestroy: true,
- },
- );
-
- // get collection limits defined previously
- const collectionInfo = await collection.getEffectiveLimits();
-
- expect(collectionInfo.accountTokenOwnershipLimit).to.be.equal(accountTokenOwnershipLimit);
- expect(collectionInfo.sponsoredDataSize).to.be.equal(sponsoredDataSize);
- expect(collectionInfo.tokenLimit).to.be.equal(tokenLimit);
- expect(collectionInfo.sponsorTransferTimeout).to.be.equal(sponsorTransferTimeout);
- expect(collectionInfo.ownerCanTransfer).to.be.true;
- expect(collectionInfo.ownerCanDestroy).to.be.true;
- });
-
- itSub('Set the same token limit twice', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-2', tokenPrefix: 'SCL'});
-
- const collectionLimits = {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: true,
- ownerCanDestroy: true,
- };
-
- await collection.setLimits(alice, collectionLimits);
-
- const collectionInfo1 = await collection.getEffectiveLimits();
-
- expect(collectionInfo1.tokenLimit).to.be.equal(tokenLimit);
-
- await collection.setLimits(alice, collectionLimits);
- const collectionInfo2 = await collection.getEffectiveLimits();
- expect(collectionInfo2.tokenLimit).to.be.equal(tokenLimit);
- });
-
- itSub('execute setCollectionLimits from admin collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-3', tokenPrefix: 'SCL'});
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- const collectionLimits = {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- // sponsoredMintSize,
- tokenLimit,
- };
-
- await expect(collection.setLimits(alice, collectionLimits)).to.not.be.rejected;
- });
-});
-
-describe('setCollectionLimits negative', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor);
- });
- });
-
- itSub('execute setCollectionLimits for not exists collection', async ({helper}) => {
- const nonExistentCollectionId = NON_EXISTENT_COLLECTION_ID;
- await expect(helper.collection.setLimits(
- alice,
- nonExistentCollectionId,
- {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- // sponsoredMintSize,
- tokenLimit,
- },
- )).to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('execute setCollectionLimits from user who is not owner of this collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-1', tokenPrefix: 'SCL'});
-
- await expect(collection.setLimits(bob, {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- // sponsoredMintSize,
- tokenLimit,
- })).to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('fails when trying to enable OwnerCanTransfer after it was disabled', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-2', tokenPrefix: 'SCL'});
-
- await collection.setLimits(alice, {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: false,
- ownerCanDestroy: true,
- });
-
- await expect(collection.setLimits(alice, {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: true,
- ownerCanDestroy: true,
- })).to.be.rejectedWith(/common\.OwnerPermissionsCantBeReverted/);
- });
-
- itSub('fails when trying to enable OwnerCanDestroy after it was disabled', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-3', tokenPrefix: 'SCL'});
-
- await collection.setLimits(alice, {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: true,
- ownerCanDestroy: false,
- });
-
- await expect(collection.setLimits(alice, {
- accountTokenOwnershipLimit,
- sponsoredDataSize,
- tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: true,
- ownerCanDestroy: true,
- })).to.be.rejectedWith(/common\.OwnerPermissionsCantBeReverted/);
- });
-
- itSub('Setting the higher token limit fails', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-4', tokenPrefix: 'SCL'});
-
- const collectionLimits = {
- accountTokenOwnershipLimit: accountTokenOwnershipLimit,
- sponsoredMintSize: sponsoredDataSize,
- tokenLimit: tokenLimit,
- sponsorTransferTimeout,
- ownerCanTransfer: true,
- ownerCanDestroy: true,
- };
-
- // The first time
- await collection.setLimits(alice, collectionLimits);
-
- // The second time - higher token limit
- collectionLimits.tokenLimit += 1;
- await expect(collection.setLimits(alice, collectionLimits)).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/);
- });
-});
js-packages/tests/src/setCollectionSponsor.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/setCollectionSponsor.test.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect, Pallets} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('integration test: ext. setCollectionSponsor():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
- });
- });
-
- itSub('Set NFT collection sponsor', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-1-NFT', tokenPrefix: 'SCS'});
- await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
- Unconfirmed: bob.address,
- });
- });
-
- itSub('Set Fungible collection sponsor', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'SetCollectionSponsor-1-FT', tokenPrefix: 'SCS'});
- await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
- Unconfirmed: bob.address,
- });
- });
-
- itSub.ifWithPallets('Set ReFungible collection sponsor', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'SetCollectionSponsor-1-RFT', tokenPrefix: 'SCS'});
- await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
- Unconfirmed: bob.address,
- });
- });
-
- itSub('Set the same sponsor repeatedly', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-2', tokenPrefix: 'SCS'});
- await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
- await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
- Unconfirmed: bob.address,
- });
- });
-
- itSub('Replace collection sponsor', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-3', tokenPrefix: 'SCS'});
- await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected;
- await expect(collection.setSponsor(alice, charlie.address)).to.be.not.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
- Unconfirmed: charlie.address,
- });
- });
-
- itSub('Collection admin add sponsor', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-4', tokenPrefix: 'SCS'});
- await collection.addAdmin(alice, {Substrate: bob.address});
- await expect(collection.setSponsor(bob, charlie.address)).to.be.not.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.deep.equal({
- Unconfirmed: charlie.address,
- });
- });
-});
-
-describe('(!negative test!) integration test: ext. setCollectionSponsor():', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([10n, 5n], donor);
- });
- });
-
- itSub('(!negative test!) Add sponsor with a non-owner', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-Neg-1', tokenPrefix: 'SCS'});
- await expect(collection.setSponsor(bob, bob.address))
- .to.be.rejectedWith(/common\.NoPermission/);
- });
-
- itSub('(!negative test!) Add sponsor to a collection that never existed', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- await expect(helper.collection.setSponsor(alice, collectionId, bob.address))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('(!negative test!) Add sponsor to a collection that was destroyed', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-Neg-2', tokenPrefix: 'SCS'});
- await collection.burn(alice);
- await expect(collection.setSponsor(alice, bob.address))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-});
js-packages/tests/src/setPermissions.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/setPermissions.test.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test: Set Permissions', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
- });
- });
-
- itSub('can all be enabled twice', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-1', tokenPrefix: 'SP'});
- expect((await collection.getData())?.raw.permissions.access).to.not.equal('AllowList');
-
- await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}});
- await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}});
-
- const permissions = (await collection.getData())?.raw.permissions;
- expect(permissions).to.be.deep.equal({
- access: 'AllowList',
- mintMode: true,
- nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]},
- });
- });
-
- itSub('can all be disabled twice', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-2', tokenPrefix: 'SP'});
- expect((await collection.getData())?.raw.permissions.access).to.equal('Normal');
-
- await collection.setPermissions(alice, {access: 'AllowList', nesting: {collectionAdmin: false, tokenOwner: true, restricted: [1, 2]}});
- expect((await collection.getData())?.raw.permissions).to.be.deep.equal({
- access: 'AllowList',
- mintMode: false,
- nesting: {collectionAdmin: false, tokenOwner: true, restricted: [1, 2]},
- });
-
- await collection.setPermissions(alice, {access: 'Normal', mintMode: false, nesting: {}});
- await collection.setPermissions(alice, {access: 'Normal', mintMode: false, nesting: {}});
- expect((await collection.getData())?.raw.permissions).to.be.deep.equal({
- access: 'Normal',
- mintMode: false,
- nesting: {collectionAdmin: false, tokenOwner: false, restricted: null},
- });
- });
-
- itSub('collection admin can set permissions', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-2', tokenPrefix: 'SP'});
- await collection.addAdmin(alice, {Substrate: bob.address});
- await collection.setPermissions(bob, {access: 'AllowList', mintMode: true});
-
- expect((await collection.getData())?.raw.permissions.access).to.equal('AllowList');
- expect((await collection.getData())?.raw.permissions.mintMode).to.equal(true);
- });
-});
-
-describe('Negative Integration Test: Set Permissions', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
- });
- });
-
- itSub('fails on not existing collection', async ({helper}) => {
- const collectionId = NON_EXISTENT_COLLECTION_ID;
- await expect(helper.collection.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('fails on removed collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-Neg-1', tokenPrefix: 'SP'});
- await collection.burn(alice);
-
- await expect(collection.setPermissions(alice, {access: 'AllowList', mintMode: true}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('fails when non-owner tries to set permissions', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-Neg-2', tokenPrefix: 'SP'});
-
- await expect(collection.setPermissions(bob, {access: 'AllowList', mintMode: true}))
- .to.be.rejectedWith(/common\.NoPermission/);
- });
-});
js-packages/tests/src/sub/appPromotion/appPromotion.seqtest.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/appPromotion/appPromotion.seqtest.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '../../util/index.js';
-import {expect} from '../../eth/util/index.js';
-
-let superuser: IKeyringPair;
-let donor: IKeyringPair;
-let palletAdmin: IKeyringPair;
-
-describe('App promotion', () => {
- before(async function () {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]);
- superuser = await privateKey('//Alice');
- donor = await privateKey({url: import.meta.url});
- palletAdmin = await privateKey('//PromotionAdmin');
- const api = helper.getApi();
- await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
- });
- });
-
- after(async function () {
- await usingPlaygrounds(async (helper) => {
- if(helper.fetchMissingPalletNames([Pallets.AppPromotion]).length != 0) return;
- const api = helper.getApi();
- await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
- });
- });
-
- describe('admin adress', () => {
- itSub('can be set by sudo only', async ({helper}) => {
- const api = helper.getApi();
- const [nonAdmin] = await helper.arrange.createAccounts([10n], donor);
- // nonAdmin can not set admin not from himself nor as a sudo
- await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected;
- await expect(helper.signTransaction(nonAdmin, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected;
- });
-
- itSub('can be any valid CrossAccountId', async ({helper}) => {
- // We are not going to set an eth address as a sponsor,
- // but we do want to check, it doesn't break anything;
- const api = helper.getApi();
- const [account] = await helper.arrange.createAccounts([10n], donor);
- const ethAccount = helper.address.substrateToEth(account.address);
- // Alice sets Ethereum address as a sudo. Then Substrate address back...
- await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled;
- await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled;
-
- // ...It doesn't break anything;
- const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
- await expect(helper.signTransaction(account, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
- });
-
- itSub('can be reassigned', async ({helper}) => {
- const api = helper.getApi();
- const [oldAdmin, newAdmin, collectionOwner] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
-
- await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: oldAdmin.address})))).to.be.fulfilled;
- await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: newAdmin.address})))).to.be.fulfilled;
- await expect(helper.signTransaction(oldAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
-
- await expect(helper.signTransaction(newAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
- });
- });
-});
-
js-packages/tests/src/sub/appPromotion/appPromotion.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/appPromotion/appPromotion.test.ts
+++ /dev/null
@@ -1,1008 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {
- itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip, LOCKING_PERIOD, UNLOCKING_PERIOD,
-} from '../../util/index.js';
-import {DevUniqueHelper} from '@unique/playgrounds/src/unique.dev.js';
-import {itEth, expect, SponsoringMode} from '../../eth/util/index.js';
-
-let donor: IKeyringPair;
-let palletAdmin: IKeyringPair;
-let nominal: bigint;
-let palletAddress: string;
-let accounts: IKeyringPair[];
-let usedAccounts: IKeyringPair[] = [];
-
-async function getAccounts(accountsNumber: number, balance?: bigint) {
- let accs: IKeyringPair[] = [];
- if(balance) {
- await usingPlaygrounds(async (helper) => {
- accs = await helper.arrange.createAccounts(new Array(accountsNumber).fill(balance), donor);
- });
- } else {
- accs = accounts.splice(0, accountsNumber);
- }
- usedAccounts.push(...accs);
- return accs;
-}
-// App promotion periods:
-// LOCKING_PERIOD = 12 blocks of relay
-// UNLOCKING_PERIOD = 6 blocks of parachain
-
-describe('App promotion', () => {
- before(async function () {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]);
- donor = await privateKey({url: import.meta.url});
- palletAddress = helper.arrange.calculatePalletAddress('appstake');
- palletAdmin = await privateKey('//PromotionAdmin');
-
- nominal = helper.balance.getOneTokenNominal();
-
- const accountBalances = new Array(200).fill(1000n);
- accounts = await helper.arrange.createAccounts(accountBalances, donor); // create accounts-pool to speed up tests
- });
- });
-
- afterEach(async () => {
- await usingPlaygrounds(async (helper) => {
- let unstakeTxs = [];
- for(const account of usedAccounts) {
- if(unstakeTxs.length === 3) {
- await Promise.all(unstakeTxs);
- unstakeTxs = [];
- }
- unstakeTxs.push(helper.staking.unstakeAll(account));
- }
- await Promise.all(unstakeTxs);
- usedAccounts = [];
- expect(await helper.staking.getTotalStaked()).to.eq(0n); // there are no active stakes after each test
- // Make sure previousCalculatedRecord is None to avoid problem with payout stakers;
- await helper.admin.payoutStakers(palletAdmin, 100);
- expect((await helper.getApi().query.appPromotion.previousCalculatedRecord() as any).isNone).to.be.true;
- });
- });
-
- describe('stake extrinsic', () => {
- itSub('should "freeze" staking balance, add it to "staked" map, and increase "totalStaked" amount', async ({helper}) => {
- const [staker, recepient] = await getAccounts(2);
- const totalStakedBefore = await helper.staking.getTotalStaked();
-
- // Minimum stake amount is 100:
- await expect(helper.staking.stake(staker, 100n * nominal - 1n)).to.be.rejected;
- await helper.staking.stake(staker, 100n * nominal);
-
- // Staker balance is: frozen: 100, reserved: 0n...
- // ...so he can not transfer 900
- expect(await helper.balance.getSubstrateFull(staker.address)).to.contain({frozen: 100n * nominal, reserved: 0n});
- expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: 100n * nominal}]);
- await expect(helper.balance.transferToSubstrate(staker, recepient.address, 900n * nominal)).to.be.rejectedWith(/^Token: Frozen$/);
-
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(100n * nominal);
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
- // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo?
- expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 100n * nominal); // total tokens amount staked in app-promotion increased
-
- await helper.staking.stake(staker, 200n * nominal);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal);
- const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(totalStakedPerBlock[0].amount).to.equal(100n * nominal);
- expect(totalStakedPerBlock[1].amount).to.equal(200n * nominal);
- });
-
- [
- {unstake: 'unstakeAll' as const},
- {unstake: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.unstake}] should allow to create maximum 10 stakes for account`, async ({helper}) => {
- const [staker] = await getAccounts(1, 2000n);
- const ONE_STAKE = 100n * nominal;
- for(let i = 0; i < 10; i++) {
- await helper.staking.stake(staker, ONE_STAKE);
- }
-
- // can have 10 stakes
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(1000n * nominal);
- expect(await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).to.have.length(10);
-
- await expect(helper.staking.stake(staker, ONE_STAKE)).to.be.rejectedWith('appPromotion.NoPermission');
-
- // After unstake can stake again
-
- // CASE 1: unstakeAll
- if(testCase.unstake === 'unstakeAll') {
- await helper.staking.unstakeAll(staker);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
- await helper.staking.stake(staker, 100n * nominal);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.equal(100n * nominal);
- }
- // CASE 2: unstakePartial
- else {
- await helper.staking.unstakePartial(staker, ONE_STAKE);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(9);
- await helper.staking.stake(staker, 100n * nominal);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(10);
- await expect(helper.staking.stake(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.NoPermission');
- await helper.staking.unstakePartial(staker, 150n * nominal);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(9);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.equal(850n * nominal);
- }
- });
- });
- // TODO: Now AppPromo makes freezes. Probably this test should be changed\removed.
- itSub.skip('should allow to stake() if balance is locked with different id', async ({helper}) => {
- const [staker] = await getAccounts(1);
-
- // staker has tokens locked with vesting id:
- await helper.balance.vestedTransfer(donor, staker.address, {start: 0n, period: 1n, periodCount: 1n, perPeriod: 200n * nominal});
- expect(await helper.balance.getSubstrateFull(staker.address))
- .to.deep.contain({free: 1200n * nominal, frozen: 200n * nominal, reserved: 0n});
-
- // Locked balance can be staked. staker can stake 1200 tokens (minus fee):
- await helper.staking.stake(staker, 1000n * nominal);
- await helper.staking.stake(staker, 199n * nominal);
- // check balances
- expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'ormlvest', amount: 200n * nominal, reasons: 'All'}]);
- expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: 1199n * nominal}]);
- expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 1199n * nominal});
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(1199n);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(1199n * nominal);
-
- // staker can unstake
- await helper.staking.unstakeAll(staker);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(1199n * nominal);
- const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
- await helper.wait.forParachainBlockNumber(pendingUnstake.block);
-
- // check balances
- expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'ormlvest', amount: 200n * nominal, reasons: 'All'}]);
- expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 200n * nominal});
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(1199n);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
-
- // staker can transfer balances now
- await helper.balance.transferToSubstrate(staker, donor.address, 900n * nominal);
- });
-
- itSub('should not allow to stake(), if stake amount is more than total free balance minus locked by staking', async ({helper}) => {
- const [staker] = await getAccounts(1);
-
- // Can't stake full balance because Alice needs to pay some fee
- await expect(helper.staking.stake(staker, 1000n * nominal)).to.be.rejected; // With('Arithmetic')
- await helper.staking.stake(staker, 500n * nominal);
-
- // Can't stake 500 tkn because Alice has Less than 500 transferable;
- await expect(helper.staking.stake(staker, 500n * nominal)).to.be.rejected; // With('Arithmetic');
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(500n * nominal);
- });
-
- itSub('for different accounts in one block is possible', async ({helper}) => {
- const crowd = await getAccounts(4);
-
- const crowdStartsToStake = crowd.map(user => helper.staking.stake(user, 100n * nominal));
- await expect(Promise.all(crowdStartsToStake)).to.be.fulfilled;
-
- const crowdStakes = await Promise.all(crowd.map(address => helper.staking.getTotalStaked({Substrate: address.address})));
- expect(crowdStakes).to.deep.equal([100n * nominal, 100n * nominal, 100n * nominal, 100n * nominal]);
- });
- });
-
- describe('Unstaking', () => {
- [
- {method: 'unstakeAll' as const},
- {method: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.method}] should move tokens to "pendingUnstake" and subtract it from totalStaked`, async ({helper}) => {
- const [staker, recepient] = await getAccounts(2);
- const totalStakedBefore = await helper.staking.getTotalStaked();
- const STAKE_AMOUNT = 900n * nominal;
-
- await helper.staking.stake(staker, STAKE_AMOUNT);
- testCase.method === 'unstakeAll'
- ? await helper.staking.unstakeAll(staker)
- : await helper.staking.unstakePartial(staker, STAKE_AMOUNT);
-
- // Right after unstake tokens are still locked
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
- expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: STAKE_AMOUNT}]);
- expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: STAKE_AMOUNT});
- // Staker can not transfer
- await expect(helper.balance.transferToSubstrate(staker, recepient.address, 100n * nominal)).to.be.rejectedWith(/^Token: Frozen$/);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(STAKE_AMOUNT);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
- expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore);
- });
- });
-
- [
- {method: 'unstakeAll' as const},
- {method: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.method}] should unlock balance after unlocking period ends and remove it from "pendingUnstake"`, async ({helper}) => {
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- testCase.method === 'unstakeAll'
- ? await helper.staking.unstakeAll(staker)
- : await helper.staking.unstakePartial(staker, 100n * nominal);
- const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
-
- // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n
- await helper.wait.forParachainBlockNumber(pendingUnstake.block);
- expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
-
- // staker can transfer:
- await helper.balance.transferToSubstrate(staker, donor.address, 998n * nominal);
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(1n);
- });
- });
-
- [
- {method: 'unstakeAll' as const},
- {method: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.method}] should successfully unstake multiple stakes`, async ({helper}) => {
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 200n * nominal);
- await helper.staking.stake(staker, 300n * nominal);
-
- // staked: [100, 200, 300]; unstaked: 0
- let totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
- let pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
- let stakes = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(totalPendingUnstake).to.be.deep.equal(0n);
- expect(pendingUnstake).to.be.deep.equal([]);
- expect(stakes[0].amount).to.equal(100n * nominal);
- expect(stakes[1].amount).to.equal(200n * nominal);
- expect(stakes[2].amount).to.equal(300n * nominal);
-
- // Can unstake multiple stakes
- testCase.method === 'unstakeAll'
- ? await helper.staking.unstakeAll(staker)
- : await helper.staking.unstakePartial(staker, 600n * nominal);
-
- pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
- totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
- stakes = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(totalPendingUnstake).to.be.equal(600n * nominal);
- expect(stakes).to.be.deep.equal([]);
- expect(pendingUnstake[0].amount).to.equal(600n * nominal);
-
- expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 600n * nominal});
- expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
- await helper.wait.forParachainBlockNumber(pendingUnstake[0].block);
- expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
- expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
- });
- });
-
- [
- {method: 'unstakeAll' as const},
- {method: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.method}] should not have any effects if no active stakes`, async ({helper}) => {
- const [staker] = await getAccounts(1);
-
- // unstake has no effect if no stakes at all
- testCase.method === 'unstakeAll'
- ? await helper.staking.unstakeAll(staker)
- : await expect(helper.staking.unstakePartial(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
-
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(0n);
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); // TODO bigint closeTo helper
-
- // TODO stake() unstake() waitUnstaked() unstake();
-
- // can't unstake if there are only pendingUnstakes
- await helper.staking.stake(staker, 100n * nominal);
-
- if(testCase.method === 'unstakeAll') {
- await helper.staking.unstakeAll(staker);
- await helper.staking.unstakeAll(staker);
- } else {
- await helper.staking.unstakePartial(staker, 100n * nominal);
- await expect(helper.staking.unstakePartial(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
- }
-
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
- });
- });
-
- [
- {method: 'unstakeAll' as const},
- {method: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.method}] should create different pending-unlock for each unlocking stake`, async ({helper}) => {
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- testCase.method === 'unstakeAll'
- ? await helper.staking.unstakeAll(staker)
- : await helper.staking.unstakePartial(staker, 100n * nominal);
- await helper.staking.stake(staker, 120n * nominal);
- testCase.method === 'unstakeAll'
- ? await helper.staking.unstakeAll(staker)
- : await helper.staking.unstakePartial(staker, 120n * nominal);
-
- const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
- expect(unstakingPerBlock).has.length(2);
- expect(unstakingPerBlock[0].amount).to.equal(100n * nominal);
- expect(unstakingPerBlock[1].amount).to.equal(120n * nominal);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.equal(0);
- });
- });
-
- [
- {method: 'unstakeAll' as const},
- {method: 'unstakePartial' as const},
- ].map(testCase => {
- itSub(`[${testCase.method}] should be possible for 3 accounts in one block`, async ({helper}) => {
- const stakers = await getAccounts(3);
-
- await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
- await Promise.all(stakers.map(staker => testCase.method === 'unstakeAll'
- ? helper.staking.unstakeAll(staker)
- : helper.staking.unstakePartial(staker, 100n * nominal)));
-
- await Promise.all(stakers.map(async (staker) => {
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
- }));
- });
- });
-
- itSub('should not be possible for more than 3 accounts in one block', async ({helper}) => {
- if(!await helper.arrange.isDevNode()) {
- const stakers = await getAccounts(10);
-
- await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
- const unstakingResults = await Promise.allSettled(stakers.map((staker, i) => i % 2 === 0
- ? helper.staking.unstakeAll(staker)
- : helper.staking.unstakePartial(staker, 100n * nominal)));
-
- const successfulUnstakes = unstakingResults.filter(result => result.status === 'fulfilled');
- expect(successfulUnstakes).to.have.length(3);
- }
- });
-
- itSub('Cannot partially unstake more than staked', async ({helper}) => {
- const [staker] = await getAccounts(1);
- // Staker stakes 300:
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 200n * nominal);
-
- // cannot usntake 300.00000...1
- await expect(helper.staking.unstakePartial(staker, 300n * nominal + 1n)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(2);
-
- await helper.staking.unstakePartial(staker, 150n * nominal);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(1);
- await expect(helper.staking.unstakePartial(staker, 150n * nominal + 1n)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(1);
-
- // nothing broken, can unstake full amount:
- await helper.staking.unstakePartial(staker, 150n * nominal);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(0);
- });
-
- itSub('Can partially unstake arbitrary amount', async ({helper}) => {
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 200n * nominal);
-
- // 0. Staker cannot unstake negative amount
- await expect(helper.staking.unstakePartial(staker, -1n)).to.be.rejected;
-
- // 1. Staker can unstake 0 wei
- await helper.staking.unstakePartial(staker, 0n);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(2);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(300n * nominal);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(0n);
-
- // 2. Staker can unstake 1 wei
- await helper.staking.unstakePartial(staker, 1n);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(2);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(300n * nominal - 1n);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(1n);
- // 2.1 The oldest stake decreased:
- let [stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(stake1.amount).to.eq(100n * nominal - 1n);
- expect(stake2.amount).to.eq(200n * nominal);
-
- // 3. Staker can unstake all but 1 wei
- await helper.staking.unstakePartial(staker, 100n * nominal - 2n);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(2);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(200n * nominal + 1n);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(100n * nominal - 1n);
- [stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(stake1.amount).to.eq(1n);
- expect(stake2.amount).to.eq(200n * nominal);
- });
-
- itSub('can mix different type of unstakes', async ({helper}) => {
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 200n * nominal);
-
- await helper.staking.unstakePartial(staker, 50n * nominal);
- await helper.staking.unstakeAll(staker);
- expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(300n * nominal);
-
- const [_unstake1, unstake2] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
- await helper.wait.forParachainBlockNumber(unstake2.block);
-
- expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([]);
- expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(999n);
- expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
- expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(0n);
- expect(await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).to.deep.eq([]);
- });
- });
-
- describe('collection sponsoring', () => {
- itSub('should actually sponsor transactions', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner, tokenSender, receiver] = await getAccounts(3);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'Name', description: 'Description', tokenPrefix: 'Prefix', limits: {sponsorTransferTimeout: 0}});
- const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address});
- await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
- const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);
-
- await token.transfer(tokenSender, {Substrate: receiver.address});
- expect (await token.getOwner()).to.be.deep.equal({Substrate: receiver.address});
- const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress);
-
- // senders balance the same, transaction has sponsored
- expect (await helper.balance.getSubstrate(tokenSender.address)).to.be.equal(1000n * nominal);
- expect (palletBalanceBefore > palletBalanceAfter).to.be.true;
- });
-
- itSub('can not be set by non admin', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner, nonAdmin] = await getAccounts(2);
-
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
-
- await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
- expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled');
- });
-
- itSub('should set pallet address as confirmed admin', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner, oldSponsor] = await getAccounts(2);
-
- // Can set sponsoring for collection without sponsor
- const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.fulfilled;
- expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
-
- // Can set sponsoring for collection with unconfirmed sponsor
- const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: {Substrate: oldSponsor.address}});
- expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address});
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.fulfilled;
- expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
-
- // Can set sponsoring for collection with confirmed sponsor
- const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: {Substrate: oldSponsor.address}});
- await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor);
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.fulfilled;
- expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
- });
-
- itSub('can be overwritten by collection owner', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner, newSponsor] = await getAccounts(2);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
- const collectionId = collection.collectionId;
-
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionId))).to.be.fulfilled;
-
- // Collection limits still can be changed by the owner
- expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true;
- expect((await collection.getData())?.raw.limits.sponsorTransferTimeout).to.be.equal(0);
- expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
-
- // Collection sponsor can be changed too
- expect((await collection.setSponsor(collectionOwner, newSponsor.address))).to.be.true;
- expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: newSponsor.address});
- });
-
- itSub('should not overwrite collection limits set by the owner earlier', async ({helper}) => {
- const [owner] = await getAccounts(1);
- const api = helper.getApi();
- const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};
- const collectionWithLimits = await helper.nft.mintCollection(owner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
-
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.fulfilled;
- expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);
- });
-
- itSub('should reject transaction if collection doesn\'t exist', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner] = await getAccounts(1);
-
- // collection has never existed
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(999999999))).to.be.rejected;
- // collection has been burned
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
- await collection.burn(collectionOwner);
-
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
- });
- });
-
- describe('stopSponsoringCollection', () => {
- itSub('can not be called by non-admin', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner, nonAdmin] = await getAccounts(2);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
-
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
-
- await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;
- expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
- });
-
- itSub('should set sponsoring as disabled', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner, recepient] = await getAccounts(2);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}});
- const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address});
-
- await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
- await helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId));
-
- expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');
-
- // Transactions are not sponsored anymore:
- const ownerBalanceBefore = await helper.balance.getSubstrate(collectionOwner.address);
- await token.transfer(collectionOwner, {Substrate: recepient.address});
- const ownerBalanceAfter = await helper.balance.getSubstrate(collectionOwner.address);
- expect(ownerBalanceAfter < ownerBalanceBefore).to.be.equal(true);
- });
-
- itSub('should not affect collection which is not sponsored by pallete', async ({helper}) => {
- const api = helper.getApi();
- const [collectionOwner] = await getAccounts(1);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: {Substrate: collectionOwner.address}});
- await collection.confirmSponsorship(collectionOwner);
-
- await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;
-
- expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address});
- });
-
- itSub('should reject transaction if collection does not exist', async ({helper}) => {
- const [collectionOwner] = await getAccounts(1);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
-
- await collection.burn(collectionOwner);
- await expect(helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringCollection', [collection.collectionId], true)).to.be.rejectedWith('common.CollectionNotFound');
- await expect(helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringCollection', [999_999_999], true)).to.be.rejectedWith('common.CollectionNotFound');
- });
- });
-
- describe('contract sponsoring', () => {
- itEth('should set palletes address as a sponsor', async ({helper}) => {
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
-
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]);
-
- expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
- expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
- expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
- confirmed: {
- substrate: palletAddress,
- },
- });
- });
-
- itEth('should overwrite sponsoring mode and existed sponsor', async ({helper}) => {
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
-
- await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
-
- // Contract is self sponsored
- expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.be.deep.equal({
- confirmed: {
- ethereum: flipper.options.address.toLowerCase(),
- },
- });
-
- // set promotion sponsoring
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
-
- // new sponsor is pallet address
- expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
- expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
- expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
- confirmed: {
- substrate: palletAddress,
- },
- });
- });
-
- itEth('can be overwritten by contract owner', async ({helper}) => {
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
-
- // contract sponsored by pallet
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
-
- // owner sets self sponsoring
- await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
-
- expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
- expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
- expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
- confirmed: {
- ethereum: flipper.options.address.toLowerCase(),
- },
- });
- });
-
- itEth('can not be set by non admin', async ({helper}) => {
- const [nonAdmin] = await getAccounts(1);
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
-
- await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
-
- // nonAdmin calls sponsorContract
- await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission');
-
- // contract still self-sponsored
- expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
- confirmed: {
- ethereum: flipper.options.address.toLowerCase(),
- },
- });
- });
-
- itEth('should actually sponsor transactions', async ({helper}) => {
- // Contract caller
- const caller = await helper.eth.createAccountWithBalance(donor, 1000n);
- const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);
-
- // Deploy flipper
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
-
- // Owner sets to sponsor every tx
- await contractHelper.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: contractOwner});
- await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner});
- await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address, 1000n); // transferBalanceToEth(api, alice, flipper.options.address, 1000n);
-
- // Set promotion to the Flipper
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
-
- // Caller calls Flipper
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- // The contracts and caller balances have not changed
- const callerBalance = await helper.balance.getEthereum(caller);
- const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address);
- expect(callerBalance).to.be.equal(1000n * nominal);
- expect(1000n * nominal === contractBalanceAfter).to.be.true;
-
- // The pallet balance has decreased
- const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress);
- expect(palletBalanceAfter < palletBalanceBefore).to.be.true;
- });
- });
-
- describe('stopSponsoringContract', () => {
- itEth('should remove pallet address from contract sponsors', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor, 1000n);
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner);
- await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
-
- await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner});
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true);
-
- expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false;
- expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
- expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
- disabled: null,
- });
-
- await flipper.methods.flip().send({from: caller});
- expect(await flipper.methods.getValue().call()).to.be.true;
-
- const callerBalance = await helper.balance.getEthereum(caller);
- const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address);
-
- // caller payed for call
- expect(1000n * nominal > callerBalance).to.be.true;
- expect(contractBalanceAfter).to.be.equal(100n * nominal);
- });
-
- itEth('can not be called by non-admin', async ({helper}) => {
- const [nonAdmin] = await getAccounts(1);
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner);
-
- await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]);
- await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address]))
- .to.be.rejectedWith(/appPromotion\.NoPermission/);
- });
-
- itEth('should not affect a contract which is not sponsored by pallete', async ({helper}) => {
- const [nonAdmin] = await getAccounts(1);
- const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
- const flipper = await helper.eth.deployFlipper(contractOwner);
- const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
- await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
-
- await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission');
- });
- });
-
- describe('payoutStakers', () => {
- itSub('can not be called by non admin', async ({helper}) => {
- const [nonAdmin] = await getAccounts(1);
- await expect(helper.admin.payoutStakers(nonAdmin, 100)).to.be.rejectedWith('appPromotion.NoPermission');
- });
-
- itSub('should increase total staked', async ({helper}) => {
- const [staker] = await getAccounts(1);
- const totalStakedBefore = await helper.staking.getTotalStaked();
- await helper.staking.stake(staker, 100n * nominal);
-
- // Wait for rewards and pay
- const [stakedInBlock] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock.block));
-
- const payout = await helper.admin.payoutStakers(palletAdmin, 100);
- const totalPayout = payout.reduce((prev, payout) => prev + payout.payout, 0n);
- const stakerReward = payout.find(p => p.staker === staker.address);
-
- expect(stakerReward?.payout).to.eq(calculateIncome(100n * nominal) - (100n * nominal));
-
- const totalStakedAfter = await helper.staking.getTotalStaked();
- expect(totalStakedAfter).to.equal(totalStakedBefore + (100n * nominal) + totalPayout);
- // staker can unstake
- await helper.staking.unstakeAll(staker);
- expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedAfter - calculateIncome(100n * nominal));
- });
-
- itSub('should credit 0.05% for staking period', async ({helper}) => {
- const [staker] = await getAccounts(1);
-
- await waitPromotionPeriodDoesntEnd(helper);
-
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 200n * nominal);
-
- // wait rewards are available:
- const [_stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
-
- const payoutToStaker = (await helper.admin.payoutStakers(palletAdmin, 100)).find((payout) => payout.staker === staker.address)!.payout;
- expect(payoutToStaker + 300n * nominal).to.equal(calculateIncome(300n * nominal));
-
- const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- const income1 = calculateIncome(100n * nominal);
- const income2 = calculateIncome(200n * nominal);
- expect(totalStakedPerBlock[0].amount).to.equal(income1);
- expect(totalStakedPerBlock[1].amount).to.equal(income2);
-
- const stakerBalance = await helper.balance.getSubstrateFull(staker.address);
- expect(stakerBalance).to.contain({frozen: income1 + income2, reserved: 0n});
- expect(stakerBalance.free / nominal).to.eq(999n);
- });
-
- itSub('shoud be paid for more than one period if payments was missed', async ({helper}) => {
- const [staker] = await getAccounts(1);
-
- await helper.staking.stake(staker, 100n * nominal);
- // wait for two rewards are available:
- let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
-
- await helper.admin.payoutStakers(palletAdmin, 100);
- [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- const frozenBalanceShouldBe = calculateIncome(100n * nominal, 2);
- expect(stake.amount).to.be.equal(frozenBalanceShouldBe);
-
- const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);
-
- expect(stakerFullBalance).to.contain({reserved: 0n, frozen: frozenBalanceShouldBe});
- });
-
- itSub('should not be credited for pending-unstaked tokens', async ({helper}) => {
- // staker unstakes before rewards been payed
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
- await helper.staking.unstakeAll(staker);
-
- // so he did not receive any rewards
- const totalBalanceBefore = await helper.balance.getSubstrate(staker.address);
- await helper.admin.payoutStakers(palletAdmin, 100);
- const totalBalanceAfter = await helper.balance.getSubstrate(staker.address);
-
- expect(totalBalanceBefore).to.be.equal(totalBalanceAfter);
- });
-
- itSub('should bring compound interest', async ({helper}) => {
- const [staker] = await getAccounts(1);
-
- await helper.staking.stake(staker, 100n * nominal);
-
- let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block));
-
- await helper.admin.payoutStakers(palletAdmin, 100);
- [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(stake.amount).to.equal(calculateIncome(100n * nominal));
-
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
- await helper.admin.payoutStakers(palletAdmin, 100);
- [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- expect(stake.amount).to.equal(calculateIncome(100n * nominal, 2));
- });
-
- itSub('can calculate reward for tiny stake', async ({helper}) => {
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.unstakePartial(staker, 100n * nominal - 1n);
-
- const [_stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
-
- const stakerPayout = await payUntilRewardFor(staker.address, helper);
- expect(stakerPayout.stake).to.eq(100n * nominal + 1n);
- });
-
- itSub('can eventually pay all rewards', async ({helper}) => {
- const stakers = await getAccounts(30);
- // Create 30 stakes:
- await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
-
- let unstakingTxs = [];
- for(const staker of stakers) {
- if(unstakingTxs.length == 3) {
- await Promise.all(unstakingTxs);
- unstakingTxs = [];
- }
- unstakingTxs.push(helper.staking.unstakePartial(staker, 100n * nominal - 1n));
- }
-
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block));
-
- let payouts;
- do {
- payouts = await helper.admin.payoutStakers(palletAdmin, 20);
- } while(payouts.length !== 0);
- });
- });
-
- describe('events', () => {
- [
- {method: 'unstakePartial' as const},
- {method: 'unstakeAll' as const},
- ].map(testCase => {
- itSub(testCase.method, async ({helper}) => {
- const unstakeParams: [] | [bigint] = testCase.method === 'unstakePartial'
- ? [100n * nominal - 1n]
- : [];
- const [staker] = await getAccounts(1);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.stake(staker, 200n * nominal);
- const {result} = await helper.executeExtrinsic(staker, `api.tx.appPromotion.${testCase.method}`, unstakeParams);
-
- const event = result.events.find(e => e.event.section === 'appPromotion' && e.event.method === 'Unstake');
- const unstakerEvents = event?.event.data[0].toString();
- const unstakedEvents = BigInt(event?.event.data[1].toString());
- expect(unstakerEvents).to.eq(staker.address);
- expect(unstakedEvents).to.eq(testCase.method === 'unstakeAll' ? 300n * nominal : 100n * nominal - 1n);
- });
- });
-
- itSub('stake', async ({helper}) => {
- const [staker] = await getAccounts(1);
- const {result} = await helper.executeExtrinsic(staker, 'api.tx.appPromotion.stake', [100n * nominal]);
-
- const event = result.events.find(e => e.event.section === 'appPromotion' && e.event.method === 'Stake');
- const stakerEvents = event?.event.data[0].toString();
- const stakedEvents = BigInt(event?.event.data[1].toString());
- expect(stakerEvents).to.eq(staker.address);
- expect(stakedEvents).to.eq(100n * nominal);
- });
-
- // Flaky
- itSub.skip('payoutStakers', async ({helper}) => {
- const [staker1, staker2] = await getAccounts(2);
- const STAKE1 = 100n * nominal;
- const STAKE2 = 200n * nominal;
- await helper.staking.stake(staker1, STAKE1);
- await helper.staking.stake(staker2, STAKE2);
-
- const [stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker2.address});
- await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
-
- const results = await helper.admin.payoutStakers(palletAdmin, 100);
- const stakersEvents = results.filter(ev => ev.staker === staker1.address || ev.staker === staker2.address);
- expect(stakersEvents).has.length(2);
- expect(stakersEvents).has.not.ordered.members([
- {staker: staker1.address, stake: STAKE1, payout: calculateIncome(STAKE1) - STAKE1},
- {staker: staker2.address, stake: STAKE2, payout: calculateIncome(STAKE2) - STAKE2},
- ]);
- });
- });
-});
-
-
-// Sometimes is is required to make a cycle in order for the payment to be calculated for a specific account
-async function payUntilRewardFor(account: string, helper: DevUniqueHelper) {
- for(let i = 0; i < 3; i++) {
- const payouts = await helper.admin.payoutStakers(palletAdmin, 100);
- const accountPayout = payouts.find(p => p.staker === account);
- if(accountPayout) return accountPayout;
- }
- throw Error(`Cannot find payout for ${account}`);
-}
-
-function calculateIncome(base: bigint, iter = 0, calcPeriod: bigint = UNLOCKING_PERIOD): bigint {
- const DAY = 7200n;
- const ACCURACY = 1_000_000_000n;
- // 5n / 10_000n = 0.05% p/day
- const income = base + base * (ACCURACY * (calcPeriod * 5n) / (10_000n * DAY)) / ACCURACY ;
-
- if(iter > 1) {
- return calculateIncome(income, iter - 1, calcPeriod);
- } else return income;
-}
-
-function rewardAvailableInBlock(stakedInBlock: bigint) {
- if(stakedInBlock % LOCKING_PERIOD === 0n) return stakedInBlock + LOCKING_PERIOD;
- return (stakedInBlock - stakedInBlock % LOCKING_PERIOD) + (LOCKING_PERIOD * 2n);
-}
-
-// Wait while promotion period less than specified block, to avoid boundary cases
-// 0 if this should be the beginning of the period.
-async function waitPromotionPeriodDoesntEnd(helper: DevUniqueHelper, waitBlockLessThan = LOCKING_PERIOD / 3n) {
- const relayBlockNumber = (await helper.callRpc('api.query.parachainSystem.validationData', [])).value.relayParentNumber.toNumber(); // await helper.chain.getLatestBlockNumber();
- const currentPeriodBlock = BigInt(relayBlockNumber) % LOCKING_PERIOD;
-
- if(currentPeriodBlock > waitBlockLessThan) {
- await helper.wait.forRelayBlockNumber(BigInt(relayBlockNumber) + LOCKING_PERIOD - currentPeriodBlock);
- }
-}
js-packages/tests/src/sub/nesting/admin.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/nesting/admin.test.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
-import {CrossAccountId} from '@unique/playgrounds/src/unique.js';
-
-describe('Nesting by collection admin', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 10n, 10n], donor);
- });
- });
-
- [
- {restricted: true},
- {restricted: false},
- ].map(testCase => {
- itSub(`can nest tokens if "collectionAdmin" permission set ${testCase.restricted ? ', in restricted mode' : ''}`, async ({helper}) => {
- const collectionA = await helper.nft.mintCollection(alice);
- await collectionA.addAdmin(alice, {Substrate: bob.address});
- const collectionB = await helper.nft.mintCollection(alice);
- await collectionB.addAdmin(alice, {Substrate: bob.address});
- // Collection has permission for collectionAdmin to nest:
- await collectionA.setPermissions(alice, {nesting:
- {collectionAdmin: true, restricted: testCase.restricted ? [collectionA.collectionId, collectionB.collectionId] : null},
- });
- // Token for nesting in from collectionA:
- const targetTokenA = await collectionA.mintToken(alice, {Substrate: charlie.address});
-
- // 1. Create an immediately nested tokens:
- // 1.1 From own collection:
- const nestedTokenA = await collectionA.mintToken(bob, targetTokenA.nestingAccount());
- // 1.2 From different collection:
- const nestedTokenB = await collectionB.mintToken(bob, targetTokenA.nestingAccount());
- expect(await nestedTokenA.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
- expect(await nestedTokenA.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenA.nestingAccount()));
- expect(await nestedTokenB.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
- expect(await nestedTokenB.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenA.nestingAccount()));
-
- // 2. Create a token to be nested and nest:
- const newNestedTokenA = await collectionA.mintToken(bob);
- const newNestedTokenB = await collectionB.mintToken(bob);
- // 2.1 From own collection:
- await newNestedTokenA.nest(bob, targetTokenA);
- // 2.2 From different collection:
- await newNestedTokenB.nest(bob, targetTokenA);
- expect(await newNestedTokenB.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
- expect(await newNestedTokenB.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenA.nestingAccount()));
- });
- });
-
- itSub('can operate together with token owner if "collectionAdmin" and "tokenOwner" permissions set', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true, tokenOwner: true}}});
- await collection.addAdmin(alice, {Substrate: bob.address});
- const targetToken = await collection.mintToken(alice, {Substrate: charlie.address});
-
- // Admin can create an immediately nested token:
- const nestedToken = await collection.mintToken(bob, targetToken.nestingAccount());
- expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
- expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-
- // Owner can create and and nest:
- const newToken = await collection.mintToken(alice, {Substrate: charlie.address});
- await newToken.nest(charlie, targetToken);
- expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
- expect(await newToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
- });
-});
js-packages/tests/src/sub/nesting/common.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/nesting/common.test.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
-import {CrossAccountId, UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/src/unique.js';
-
-let alice: IKeyringPair;
-let bob: IKeyringPair;
-
-describe('Common nesting tests', () => {
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
- {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
- {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
- {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase => {
- itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
- // Only NFT can be target for nesting in
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
-
- const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
- });
-
- // 1. Bob can immediately create nested token:
- const nestedToken1 = testCase.mode === 'nft'
- ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
- : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
- expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await nestedToken1.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenBob.nestingAccount()));
-
- // 2. Bob can mint and nest token:
- const nestedToken2 = await collectionForNesting.mintToken(bob);
- await nestedToken2.nest(bob, targetTokenBob);
- expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await nestedToken2.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenBob.nestingAccount()));
- });
- });
-
-
- [
- {restrictedMode: true},
- {restrictedMode: false},
- ].map(testCase => {
- itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
- // Only NFT allows nesting, permissions should be set:
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
-
- const collectionForNesting = await helper.ft.mintCollection(bob);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
- });
-
- // 1. Alice can immediately create nested tokens:
- await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
- expect(await collectionForNesting.getTop10Owners()).deep.eq([CrossAccountId.toLowerCase(targetTokenBob.nestingAccount())]);
- expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
-
- // 2. Alice can mint and nest token:
- await collectionForNesting.mint(bob, 100n);
- await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
- expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
- expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);
- });
- });
-
- [
- {restrictedMode: true},
- {restrictedMode: false},
- ].map(testCase => {
- itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
- // Only NFT allows nesting, permissions should be set:
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
- expect(await targetTokenBob.getChildren()).to.be.empty;
-
- const collectionForNesting = helper.ft.getCollectionObject(0);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
- });
-
- // Bob can nest Native FT into their NFT:
- await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
- expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
- // Native FT should't be visible in NFT children:
- expect(await targetTokenBob.getChildren()).to.be.deep.equal([]);
- });
- });
-
-
- itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
- const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const tokenA = await collectionToNest.mintToken(alice);
- const tokenB = await collectionToNest.mintToken(alice);
-
- // Create a nested token
- const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
-
- const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
- const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
- await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
- await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
- expect(await nestedNFT.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(tokenA.nestingAccount()));
- expect(await nestedRFT.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(tokenA.nestingAccount()));
- expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
- expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
-
- expect(await tokenA.getChildren()).to.be.length(3);
- expect(await tokenB.getChildren()).to.be.length(0);
-
- // Transfer the nested token to another token
- await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
- await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
- await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
- await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
-
- expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
- expect(await nestedNFT.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(tokenB.nestingAccount()));
-
- expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);
- expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);
-
- expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
- expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
-
- expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
- expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
-
- // RFT, FT, and without native FT
- expect(await tokenA.getChildren()).to.be.length(2);
- // NFT, RFT, FT, and without native FT
- expect(await tokenB.getChildren()).to.be.length(3);
- });
-});
js-packages/tests/src/sub/nesting/e2e.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/nesting/e2e.test.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
-import {CrossAccountId} from '@unique/playgrounds/src/unique.js';
-
-describe('Composite nesting tests', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
- });
- });
-
- itSub('Checks token children e2e', async ({helper}) => {
- const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const collectionB = await helper.ft.mintCollection(alice);
- const collectionC = await helper.rft.mintCollection(alice);
- const collectionNative = helper.ft.getCollectionObject(0);
-
- const targetToken = await collectionA.mintToken(alice);
- expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation');
-
- // Create a nested NFT token
- const tokenA = await collectionA.mintToken(alice, targetToken.nestingAccount());
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- ]).and.has.length(1);
-
- // Create then nest
- const tokenB = await collectionA.mintToken(alice);
- await tokenB.nest(alice, targetToken);
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: tokenB.tokenId, collectionId: collectionA.collectionId},
- ]).and.has.length(2);
-
- // Move token B to a different user outside the nesting tree
- await tokenB.unnest(alice, targetToken, {Substrate: bob.address});
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- ]).and.has.length(1);
-
- // Create a fungible token in another collection and then nest
- await collectionB.mint(alice, 10n);
- await collectionB.transfer(alice, targetToken.nestingAccount(), 2n);
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionB.collectionId},
- ]).and.has.length(2);
-
- // Create a refungible token in another collection and then nest
- const tokenC = await collectionC.mintToken(alice, 10n);
- await tokenC.transfer(alice, targetToken.nestingAccount(), 2n);
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionB.collectionId},
- {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
- ]).and.has.length(3);
-
- // Nest native fungible token into another collection
- await collectionNative.transfer(alice, targetToken.nestingAccount(), 2n);
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionB.collectionId},
- {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
- ]).and.has.length(3);
-
- // Burn all nested pieces
- await tokenC.burnFrom(alice, targetToken.nestingAccount(), 2n);
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionB.collectionId},
- ])
- .and.has.length(2);
-
- // Move part of the fungible token inside token A deeper in the nesting tree
- await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
- expect(await targetToken.getChildren()).to.be.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionB.collectionId},
- ]).and.has.length(2);
- // Nested token also has children now:
- expect(await tokenA.getChildren()).to.have.deep.members([
- {tokenId: 0, collectionId: collectionB.collectionId},
- ]).and.has.length(1);
-
- // Move the remaining part of the fungible token inside token A deeper in the nesting tree
- await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
- expect(await targetToken.getChildren()).to.have.deep.members([
- {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- ]).and.has.length(1);
- expect(await tokenA.getChildren()).to.have.deep.members([
- {tokenId: 0, collectionId: collectionB.collectionId},
- ]).and.has.length(1);
- });
-
- /// TODO review this test
- itSub('Performs the full suite: bundles a token, transfers, and unnests', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- // Create an immediately nested token
- const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
- expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
- expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-
- // Create a token to be nested
- const newToken = await collection.mintToken(alice);
-
- // Nest
- await newToken.nest(alice, targetToken);
- expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
- expect(await newToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-
- // Move bundle to different user
- await targetToken.transfer(alice, {Substrate: bob.address});
- expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
- expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await newToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-
- // Unnest
- await newToken.unnest(bob, targetToken, {Substrate: bob.address});
- expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await newToken.getOwner()).to.be.deep.equal({Substrate: bob.address});
- });
-});
js-packages/tests/src/sub/nesting/nesting.negative.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/nesting/nesting.negative.test.ts
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
-import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '@unique/playgrounds/src/unique.js';
-import {itEth} from '../../eth/util/index.js';
-
-let alice: IKeyringPair;
-let bob: IKeyringPair;
-let charlie: IKeyringPair;
-
-describe('Negative Test: Nesting', () => {
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- [
- {mode: 'nft' as const, requiredPallets: []},
- {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
- ].map(testCase => {
- itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {
- // Create default collection, permissions are not set:
- const aliceNFTCollection = await helper.nft.mintCollection(alice);
- const targetToken = await aliceNFTCollection.mintToken(alice);
-
- const collectionForNesting = await helper[testCase.mode].mintCollection(alice);
-
- // 1. Alice cannot create immediately nested tokens:
- const nestingTx = testCase.mode === 'nft'
- ? (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())
- : (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());
- await expect(nestingTx).to.be.rejectedWith('common.UserIsNotAllowedToNest');
-
- // 2. Alice cannot mint and nest token:
- const nestedToken2 = await collectionForNesting.mintToken(alice);
- await expect(nestedToken2.nest(alice, targetToken)).to.be.rejectedWith('common.UserIsNotAllowedToNest');
- });
- });
-
- [
- {mode: 'ft'},
- {mode: 'nativeFt'},
- ].map(testCase => {
- itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled (except for native fungible collection)`, async ({helper}) => {
- // Create default collection, permissions are not set:
- const aliceNFTCollection = await helper.nft.mintCollection(alice);
- const targetToken = await aliceNFTCollection.mintToken(alice);
-
- const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);
-
- // Alice cannot create immediately nested tokens:
- if(testCase.mode === 'ft') {
- await expect(collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest');
- } else {
- await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.not.rejected;
- }
-
- // Alice can't mint and nest tokens:
- if(testCase.mode === 'ft') {
- await collectionForNesting.mint(alice, 100n);
- }
-
- if(testCase.mode === 'ft') {
- await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');
- } else {
- await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.not.rejected;
- }
- });
- });
-
- [
- {mode: 'nft' as const},
- {mode: 'rft' as const},
- {mode: 'ft' as const},
- {mode: 'native ft' as const},
- ].map(testCase => {
- itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens (except for native fungible collection)`, async ({helper}) => {
- const targetCollection = await helper.nft.mintCollection(alice, {permissions:
- {nesting: {tokenOwner: true, collectionAdmin: true}},
- });
- const targetToken = await targetCollection.mintToken(alice);
-
- const nestedCollectionBob = await (
- testCase.mode === 'native ft'
- ? helper.ft.getCollectionObject(0)
- : helper[testCase.mode].mintCollection(bob)
- );
-
- let nestedTokenBob: UniqueNFToken | UniqueRFToken;
- switch (testCase.mode) {
- case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;
- case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;
- case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;
- case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;
- }
-
- // Bob non-owner of targetToken and non admin of targetCollection, so
- // 1. cannot mint nested token:
- switch (testCase.mode) {
- case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
- case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
- case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
- case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;
- }
-
- // 2. cannot nest existing token:
- switch (testCase.mode) {
- case 'nft':
- case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
- case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
- case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.not.rejected; break;
- }
- });
- });
-
- [
- {mode: 'nft' as const, nesting: {tokenOwner: true, collectionAdmin: false}},
- {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},
- ].map(testCase => {
- itSub(`${testCase.nesting.tokenOwner ? 'Admin' : 'Token owner'} cannot nest when only ${testCase.nesting.tokenOwner ? 'tokenOwner' : 'collectionAdmin'} is allowed`, async ({helper}) => {
- // Create collection with tokenOwner or create collection with collectionAdmin permission:
- const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});
- const targetTokenCharlie = await targetCollection.mintToken(alice, {Substrate: charlie.address});
- await targetCollection.addAdmin(alice, {Substrate: bob.address});
-
- const nestedCollectionCharlie = await helper[testCase.mode].mintCollection(charlie);
- const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);
- // if nesting permissions restricted for token owner – minter is bob (admin),
- // if collectionAdmin – charlie (owner)
- testCase.nesting.tokenOwner
- ? await expect(nestedCollectionBob.mintToken(bob, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)
- : await expect(nestedCollectionCharlie.mintToken(charlie, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);
- });
- });
-
- itSub.ifWithPallets('Cannot nest in non existing token (except for native fungible collection)', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice);
- // To avoid UserIsNotAllowedToNest error
- await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});
-
- // The list of non-existing tokens:
- const tokenFromNonExistingCollection = helper.nft.getTokenObject(9999999, 1);
- const tokenBurnt = await collection.mintToken(alice);
- await tokenBurnt.burn(alice);
- const tokenNotMintedYet = helper.nft.getTokenObject(collection.collectionId, 2);
-
- // The list of collections to nest tokens from:
- const nftCollectionForNesting = await helper.nft.mintCollection(alice);
- const rftCollectionForNesting = await helper.rft.mintCollection(alice);
- const ftCollectionForNesting = await helper.ft.mintCollection(alice);
- const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);
-
- const testCases = [
- {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},
- {token: tokenBurnt, error: 'TokenNotFound'},
- {token: tokenNotMintedYet, error: 'TokenNotFound'},
- ];
-
- for(const testCase of testCases) {
- // 1. Alice cannot create nested token to non-existing token
- await expect(nftCollectionForNesting.mintToken(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
- await expect(rftCollectionForNesting.mintToken(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
- await expect(ftCollectionForNesting.mint(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
-
- // 2. Alice cannot mint and nest token:
- const nft = await nftCollectionForNesting.mintToken(alice);
- const rft = await rftCollectionForNesting.mintToken(alice, 100n);
- await ftCollectionForNesting.mint(alice, 100n);
- await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
- await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
- await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);
- await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.not.rejected;
- }
- });
-
- itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {
- const existingCollection = await helper.nft.mintCollection(alice);
- const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);
- const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);
-
- const nftCollectionForNesting = await helper.nft.mintCollection(alice);
-
- // 1. Alice cannot create nested token to collection address
- await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
- await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
-
- // 2. Alice cannot mint and nest token to collection address:
- const nft = await nftCollectionForNesting.mintToken(alice);
- await expect(nft.transfer(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
- await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
- });
-
- itEth.ifWithPallets('Cannot nest in RFT or FT (except for native fungible collection)', [Pallets.ReFungible], async ({helper}) => {
- // Create default collection, permissions are not set:
- const rftCollection = await helper.rft.mintCollection(alice);
- const ftCollection = await helper.ft.mintCollection(alice);
- const nativeFtCollection = helper.ft.getCollectionObject(0);
-
- const rftToken = await rftCollection.mintToken(alice);
- await ftCollection.mint(alice, 100n);
-
- const collectionForNesting = await helper.nft.mintCollection(alice);
-
- // 1. Alice cannot create immediately nested tokens:
- await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');
- await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');
- await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');
-
- // 2. Alice cannot mint and nest token:
- const nestedToken2 = await collectionForNesting.mintToken(alice);
- await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');
- await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');
- await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.not.rejected;
- });
-
- itSub('Cannot nest in restricted collection if collection is not in the list (except native fungible collection)', async ({helper}) => {
- const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);
- const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);
- const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);
- const notAllowedCollectionFT = await helper.ft.mintCollection(alice);
- const allowedCollectionNativeFT = helper.ft.getCollectionObject(0);
-
- // Collection restricted to allowedCollectionId
- const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:
- {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},
- });
- // Create collection with restricted nesting -- even self is not allowed
- const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:
- {nesting: {tokenOwner: true, restricted: []}},
- });
-
- const targetTokenA = await restrictedCollectionA.mintToken(alice);
- const targetTokenB = await restrictedCollectionB.mintToken(alice);
-
- // 1. Cannot mint in own collection after allowlisting the accounts:
- await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
-
- // 2. Cannot mint from notAllowedCollection:
- await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
- await expect(allowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.not.rejected;
- await expect(allowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.not.rejected;
- });
-
- itSub('Cannot create nesting chains greater than 5', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- let token = await collection.mintToken(alice);
-
- const maxNestingLevel = 5;
-
- // Create a nested-token matryoshka
- for(let i = 0; i < maxNestingLevel; i++) {
- token = await collection.mintToken(alice, token.nestingAccount());
- }
-
- // The nesting depth is limited by `maxNestingLevel`
- // 1. Cannot mint:
- await expect(collection.mintToken(alice, token.nestingAccount()))
- .to.be.rejectedWith(/structure\.DepthLimit/);
- // 2. Cannot transfer:
- const anotherToken = await collection.mintToken(alice);
- await expect(anotherToken.transfer(alice, token.nestingAccount()))
- .to.be.rejectedWith(/structure\.DepthLimit/);
- // 3. Cannot nest FT pieces:
- const ftCollection = await helper.ft.mintCollection(alice);
- await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))
- .to.be.rejectedWith(/structure\.DepthLimit/);
-
- expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
- expect(await token.getChildren()).to.has.length(0);
- });
-});
js-packages/tests/src/sub/nesting/refungible.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/nesting/refungible.test.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
-
-describe('ReFungible-specific nesting tests', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([200n], donor);
- });
- });
-
- itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice, {
- permissions: {
- nesting: {
- tokenOwner: true,
- },
- },
- });
- const collectionRFT = await helper.rft.mintCollection(alice);
-
- const nft = await collectionNFT.mintToken(alice, {Substrate: alice.address});
- const rft = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
-
- expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
-
- await rft.transfer(alice, nft.nestingAccount(), 40n);
-
- expect(await rft.getTopmostOwner()).deep.equal(null);
-
- await rft.transfer(alice, nft.nestingAccount(), 60n);
-
- expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
-
- await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 30n);
-
- expect(await rft.getTopmostOwner()).deep.equal(null);
-
- await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 70n);
-
- expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
- });
-});
js-packages/tests/src/sub/nesting/unnesting.negative.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/nesting/unnesting.negative.test.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
-import {CrossAccountId} from '@unique/playgrounds/src/unique.js';
-
-describe('Negative Test: Unnesting', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 50n], donor);
- });
- });
-
- // TODO: make this test a bit more generic
- itSub('Admin (NFT): disallows an Admin to unnest someone else\'s token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {limits: {ownerCanTransfer: true}, permissions: {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true}}});
- //await collection.addAdmin(alice, {Substrate: bob.address});
- const targetToken = await collection.mintToken(alice, {Substrate: bob.address});
- await collection.addToAllowList(alice, {Substrate: bob.address});
- await collection.addToAllowList(alice, targetToken.nestingAccount());
-
- // Try to nest somebody else's token
- const newToken = await collection.mintToken(bob);
- await expect(newToken.nest(alice, targetToken))
- .to.be.rejectedWith(/common\.NoPermission/);
-
- // Try to unnest a token belonging to someone else as collection admin
- const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
- await expect(nestedToken.unnest(alice, targetToken, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
-
- expect(await targetToken.getChildren()).to.be.length(1);
- expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
- });
-
- [
- {mode: 'ft' as const},
- {mode: 'native ft' as const},
- ].map(md => [
- {mode: md.mode, restrictedMode: true},
- {mode: md.mode, restrictedMode: false},
- ].map(testCase => {
- itSub(`Fungible: disallows a non-Owner to unnest someone else's token [${testCase.mode}${testCase.restrictedMode ? ' (Restricted nesting)' : ''}]`, async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice);
- const collectionFT = await (
- testCase.mode === 'ft'
- ? helper.ft.mintCollection(alice)
- : helper.ft.getCollectionObject(0)
- );
- const targetToken = await collectionNFT.mintToken(alice, {Substrate: bob.address});
-
- await collectionNFT.setPermissions(alice, {nesting: {
- collectionAdmin: true, tokenOwner: true, restricted: testCase.restrictedMode ? [collectionFT.collectionId] : null,
- }});
-
- // Nest some tokens as Alice into Bob's token
- await (
- testCase.mode === 'ft'
- ? collectionFT.mint(alice, 5n, targetToken.nestingAccount())
- : collectionFT.transfer(alice, targetToken.nestingAccount(), 5n)
- );
-
- // Try to pull it out as Alice still
- await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: bob.address}, 1n))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);
- });
- }));
-});
js-packages/tests/src/sub/refungible/burn.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/refungible/burn.test.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../../util/index.js';
-
-describe('Refungible: burn', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
- });
- });
-
- itSub('can burn some pieces', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
- expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n);
- await token.burn(alice, 99n);
- expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(1n);
- });
-
- itSub('can burn all pieces', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
-
- expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n);
-
- await token.burn(alice, 100n);
- expect(await collection.doesTokenExist(token.tokenId)).to.be.false;
- });
-
- itSub('burn pieces for multiple users', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
-
- await token.transfer(alice, {Substrate: bob.address}, 60n);
-
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(40n);
- expect(await token.getBalance({Substrate: bob.address})).to.be.equal(60n);
-
- await token.burn(alice, 40n);
-
- expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(0n);
-
- await token.burn(bob, 59n);
-
- expect(await token.getBalance({Substrate: bob.address})).to.be.equal(1n);
- expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
-
- await token.burn(bob, 1n);
-
- expect(await collection.doesTokenExist(token.tokenId)).to.be.false;
- });
-
- itSub('burn pieces by admin', async function({helper}) {
- const collection = await helper.rft.mintCollection(alice);
- await collection.setLimits(alice, {ownerCanTransfer: true});
- await collection.addAdmin(alice, {Substrate: bob.address});
- const token = await collection.mintToken(alice, 100n);
-
- await token.burnFrom(bob, {Substrate: alice.address}, 100n);
- expect(await token.doesExist()).to.be.false;
- });
-});
-
-describe('Refungible: burn negative tests', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
- });
- });
-
- itSub('cannot burn non-owned token pieces', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice);
- const aliceToken = await collection.mintToken(alice, 10n, {Substrate: alice.address});
- const bobToken = await collection.mintToken(alice, 10n, {Substrate: bob.address});
-
- // 1. Cannot burn non-owned token:
- await expect(bobToken.burn(alice, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
- await expect(bobToken.burn(alice, 5n)).to.be.rejectedWith('common.TokenValueTooLow');
- // 2. Cannot burn non-existing token:
- await expect(helper.rft.burnToken(alice, 99999, 10)).to.be.rejectedWith('common.CollectionNotFound');
- await expect(helper.rft.burnToken(alice, collection.collectionId, 99999)).to.be.rejectedWith('common.TokenValueTooLow');
- // 3. Can burn zero amount of owned tokens (EIP-20)
- await aliceToken.burn(alice, 0n);
-
- // 4. Storage is not corrupted:
- expect(await aliceToken.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
- expect(await bobToken.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
-
- // 4.1 Tokens can be transfered:
- await aliceToken.transfer(alice, {Substrate: bob.address}, 10n);
- await bobToken.transfer(bob, {Substrate: alice.address}, 10n);
- expect(await aliceToken.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
- expect(await bobToken.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
- });
-});
js-packages/tests/src/sub/refungible/nesting.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/refungible/nesting.test.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../../util/index.js';
-
-describe('Refungible nesting', () => {
- let alice: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- const donor = await privateKey({url: import.meta.url});
- [alice, charlie] = await helper.arrange.createAccounts([50n, 10n], donor);
- });
- });
-
- [
- {restrictedMode: true},
- {restrictedMode: false},
- ].map(testCase => {
- itSub(`Owner can nest their token${testCase.restrictedMode ? ': Restricted mode' : ''}`, async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true}}});
- const collectionRFT = await helper.rft.mintCollection(alice);
- const targetToken = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
-
- await collectionNFT.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionRFT.collectionId] : null}});
- await collectionNFT.addToAllowList(alice, {Substrate: charlie.address});
- await collectionNFT.addToAllowList(alice, targetToken.nestingAccount());
-
- await collectionRFT.setPermissions(alice, {access: 'AllowList', mintMode: true});
- await collectionRFT.addToAllowList(alice, {Substrate: charlie.address});
- await collectionRFT.addToAllowList(alice, targetToken.nestingAccount());
-
- // Create an immediately nested token
- const nestedToken = await collectionRFT.mintToken(charlie, 5n, targetToken.nestingAccount());
- expect(await nestedToken.getBalance(targetToken.nestingAccount())).to.be.equal(5n);
-
- // Create a token to be nested and nest
- const newToken = await collectionRFT.mintToken(charlie, 5n);
- await newToken.transfer(charlie, targetToken.nestingAccount(), 2n);
- expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);
- expect(await newToken.getBalance({Substrate: charlie.address})).to.be.equal(3n);
- });
- });
-
- itSub('Owner can unnest nested token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- // Owner mints nested RFT token:
- const collectionRFT = await helper.rft.mintCollection(alice);
- const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());
-
- // 1.1 Owner can partially unnest token pieces with transferFrom:
- await token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n);
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);
- expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
-
- // 1.2 Owner can unnest all pieces:
- await token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 1n);
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(10n);
- expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
- });
-
- itSub('Owner can burn nested token pieces', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const targetToken = await collection.mintToken(alice);
-
- // Owner mints nested RFT token:
- const collectionRFT = await helper.rft.mintCollection(alice);
- const token = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
- await token.transfer(alice, targetToken.nestingAccount(), 30n);
-
- // 1.1 Owner can partially burnFrom nested pieces:
- await token.burnFrom(alice, targetToken.nestingAccount(), 10n);
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(70n);
- expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(20n);
- expect(await targetToken.getChildren()).to.has.length(1);
-
- // 1.1 Owner can burnFrom all nested pieces:
- await token.burnFrom(alice, targetToken.nestingAccount(), 20n);
- expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
- expect(await targetToken.getChildren()).to.has.length(0);
- expect(await token.doesExist()).to.be.true;
-
- // 2. Target token does not contain any pieces and can be burnt:
- await targetToken.burn(alice);
- expect(await targetToken.doesExist()).to.be.false;
- });
-});
-
-describe('Refungible nesting negative tests', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 50n], donor);
- });
- });
-
- [
- {restrictedMode: true},
- {restrictedMode: false},
- ].map(testCase => {
- itSub(`non-Owner cannot nest someone else's token${testCase.restrictedMode ? ': Restricted mode' : ''}`, async ({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice);
- const collectionRFT = await helper.rft.mintCollection(alice);
- const targetToken = await collectionNFT.mintToken(alice);
-
- await collectionNFT.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionRFT.collectionId] : null}});
- await collectionNFT.addToAllowList(alice, {Substrate: bob.address});
- await collectionNFT.addToAllowList(alice, targetToken.nestingAccount());
-
- // Try to create a token to be nested and nest
- const newToken = await collectionRFT.mintToken(alice);
- await expect(newToken.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.TokenValueTooLow/);
-
- expect(await targetToken.getChildren()).to.be.length(0);
- expect(await newToken.getBalance({Substrate: alice.address})).to.be.equal(1n);
-
- // Nest some tokens as Alice into Bob's token
- await newToken.transfer(alice, targetToken.nestingAccount());
-
- // Try to pull it out
- await expect(newToken.transferFrom(bob, targetToken.nestingAccount(), {Substrate: alice.address}, 1n))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
- });
- });
-});
js-packages/tests/src/sub/refungible/repartition.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/refungible/repartition.test.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../../util/index.js';
-
-describe('integration test: Refungible functionality:', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
- });
- });
-
- itSub('Repartition', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
-
- expect(await token.repartition(alice, 200n)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(200n);
- expect(await token.getTotalPieces()).to.be.equal(200n);
-
- expect(await token.transfer(alice, {Substrate: bob.address}, 110n)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(90n);
- expect(await token.getBalance({Substrate: bob.address})).to.be.equal(110n);
-
- await expect(token.repartition(alice, 80n))
- .to.eventually.be.rejectedWith(/refungible\.RepartitionWhileNotOwningAllPieces/);
-
- expect(await token.transfer(alice, {Substrate: bob.address}, 90n)).to.be.true;
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(0n);
- expect(await token.getBalance({Substrate: bob.address})).to.be.equal(200n);
-
- expect(await token.repartition(bob, 150n)).to.be.true;
- await expect(token.transfer(bob, {Substrate: alice.address}, 160n))
- .to.eventually.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub('Repartition with increased amount', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
- await token.repartition(alice, 200n);
- const chainEvents = helper.chainLog.slice(-1)[0].events;
- const event = chainEvents.find((event: any) => event.section === 'common' && event.method === 'ItemCreated');
- expect(event).to.deep.include({
- section: 'common',
- method: 'ItemCreated',
- index: [66, 2],
- data: [
- collection.collectionId,
- token.tokenId,
- {substrate: alice.address},
- 100n,
- ],
- });
- });
-
- itSub('Repartition with decreased amount', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
- await token.repartition(alice, 50n);
- const chainEvents = helper.chainLog.slice(-1)[0].events;
- const event = chainEvents.find((event: any) => event.section === 'common' && event.method === 'ItemDestroyed');
- expect(event).to.deep.include({
- section: 'common',
- method: 'ItemDestroyed',
- index: [66, 3],
- data: [
- collection.collectionId,
- token.tokenId,
- {substrate: alice.address},
- 50n,
- ],
- });
- });
-});
-
js-packages/tests/src/sub/refungible/transfer.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/sub/refungible/transfer.test.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../../util/index.js';
-
-describe('Refungible transfer tests', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
- donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
- });
- });
-
- itSub('Can transfer token pieces', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const token = await collection.mintToken(alice, 100n);
-
- expect(await token.transfer(alice, {Substrate: bob.address}, 60n)).to.be.true;
- // 1. Can transfer less or equal than have:
- expect(await token.getBalance({Substrate: alice.address})).to.be.equal(40n);
- expect(await token.getBalance({Substrate: bob.address})).to.be.equal(60n);
- });
-
- itSub('Cannot transfer incorrect amount of token pieces', async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
- const tokenAlice = await collection.mintToken(alice, 10n, {Substrate: alice.address});
- const tokenBob = await collection.mintToken(alice, 10n, {Substrate: bob.address});
-
- // 1. Alice cannot transfer Bob's token:
- await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
- await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
- await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 10n)).to.be.rejectedWith('common.TokenValueTooLow');
- await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow');
-
- // 2. Alice cannot transfer non-existing token:
- await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
- await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
-
- // 3. Cannot transfer more than have:
- await expect(tokenAlice.transfer(alice, {Substrate: bob.address}, 11n))
- .to.eventually.be.rejectedWith(/common\.TokenValueTooLow/);
-
- // 4. Zero transfer allowed (EIP-20):
- await tokenAlice.transfer(alice, {Substrate: charlie.address}, 0n);
-
- expect(await tokenAlice.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
- expect(await tokenBob.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
- expect(await tokenAlice.getBalance({Substrate: alice.address})).to.eq(10n);
- expect(await tokenBob.getBalance({Substrate: bob.address})).to.eq(10n);
- expect(await tokenBob.getBalance({Substrate: charlie.address})).to.eq(0n);
- });
-});
js-packages/tests/src/transfer.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/transfer.test.ts
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from './eth/util/index.js';
-import {itSub, Pallets, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
- let donor: IKeyringPair;
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
- });
- });
-
- itSub('Balance transfers and check balance', async ({helper}) => {
- const alicesBalanceBefore = await helper.balance.getSubstrate(alice.address);
- const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
- expect(await helper.balance.transferToSubstrate(alice, bob.address, 1n)).to.be.true;
-
- const alicesBalanceAfter = await helper.balance.getSubstrate(alice.address);
- const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
- expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;
- });
-
- itSub('Inability to pay fees error message is correct', async ({helper}) => {
- const [zero] = await helper.arrange.createAccounts([0n], donor);
-
- // console.error = () => {};
- // The following operation throws an error into the console and the logs. Pay it no heed as long as the test succeeds.
- await expect(helper.balance.transferToSubstrate(zero, donor.address, 1n))
- .to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');
- });
-
- itSub('[nft] User can transfer owned token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-1-NFT', description: '', tokenPrefix: 'T'});
- const nft = await collection.mintToken(alice);
-
- await nft.transfer(alice, {Substrate: bob.address});
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: bob.address});
- });
-
- itSub('[fungible] User can transfer owned token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-1-FT', description: '', tokenPrefix: 'T'});
- await collection.mint(alice, 10n);
-
- await collection.transfer(alice, {Substrate: bob.address}, 9n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('[refungible] User can transfer owned token', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});
- const rft = await collection.mintToken(alice, 10n);
-
- await rft.transfer(alice, {Substrate: bob.address}, 9n);
- expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);
- });
-
- itSub('[nft] Collection admin can transfer owned token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-2-NFT', description: '', tokenPrefix: 'T'});
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- const nft = await collection.mintToken(bob, {Substrate: bob.address});
- await nft.transfer(bob, {Substrate: alice.address});
-
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('[fungible] Collection admin can transfer owned token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-2-FT', description: '', tokenPrefix: 'T'});
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- await collection.mint(bob, 10n, {Substrate: bob.address});
- await collection.transfer(bob, {Substrate: alice.address}, 1n);
-
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('[refungible] Collection admin can transfer owned token', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-2-RFT', description: '', tokenPrefix: 'T'});
- await collection.addAdmin(alice, {Substrate: bob.address});
-
- const rft = await collection.mintToken(bob, 10n, {Substrate: bob.address});
- await rft.transfer(bob, {Substrate: alice.address}, 1n);
-
- expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);
- });
-});
-
-describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
- });
- });
-
-
- itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {
- await expect(helper.nft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {
- await expect(helper.ft.transfer(alice, NON_EXISTENT_COLLECTION_ID, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {
- await expect(helper.rft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('[nft] Transfer with deleted collection_id', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-1-NFT', description: '', tokenPrefix: 'T'});
- const nft = await collection.mintToken(alice);
-
- await nft.burn(alice);
- await collection.burn(alice);
-
- await expect(nft.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('[fungible] Transfer with deleted collection_id', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-1-FT', description: '', tokenPrefix: 'T'});
- await collection.mint(alice, 10n);
-
- await collection.burnTokens(alice, 10n);
- await collection.burn(alice);
-
- await expect(collection.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub.ifWithPallets('[refungible] Transfer with deleted collection_id', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-1-RFT', description: '', tokenPrefix: 'T'});
- const rft = await collection.mintToken(alice, 10n);
-
- await rft.burn(alice, 10n);
- await collection.burn(alice);
-
- await expect(rft.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- itSub('[nft] Transfer with not existed item_id', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-2-NFT', description: '', tokenPrefix: 'T'});
- await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.TokenNotFound/);
- });
-
- itSub('[fungible] Transfer with not existed item_id', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-2-FT', description: '', tokenPrefix: 'T'});
- await expect(collection.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub.ifWithPallets('[refungible] Transfer with not existed item_id', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-2-RFT', description: '', tokenPrefix: 'T'});
- await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub('Zero transfer NFT', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});
- const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});
- const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});
- // 1. Zero transfer of own tokens allowed:
- await helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: bob.address}, collection.collectionId, tokenAlice.tokenId, 0]);
- // 2. Zero transfer of non-owned tokens not allowed:
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');
- // 3. Zero transfer of non-existing tokens not allowed:
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, 10, 0])).to.be.rejectedWith('common.TokenNotFound');
- expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});
- expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});
- // 4. Storage is not corrupted:
- await tokenAlice.transfer(alice, {Substrate: bob.address});
- await tokenBob.transfer(bob, {Substrate: alice.address});
- expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});
- expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});
- });
-
- itSub('[nft] Transfer with deleted item_id', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});
- const nft = await collection.mintToken(alice);
-
- await nft.burn(alice);
-
- await expect(nft.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.TokenNotFound/);
- });
-
- itSub('[fungible] Transfer with deleted item_id', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-3-FT', description: '', tokenPrefix: 'T'});
- await collection.mint(alice, 10n);
-
- await collection.burnTokens(alice, 10n);
-
- await expect(collection.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub.ifWithPallets('[refungible] Transfer with deleted item_id', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-3-RFT', description: '', tokenPrefix: 'T'});
- const rft = await collection.mintToken(alice, 10n);
-
- await rft.burn(alice, 10n);
-
- await expect(rft.transfer(alice, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub('[nft] Transfer with recipient that is not owner', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-4-NFT', description: '', tokenPrefix: 'T'});
- const nft = await collection.mintToken(alice);
-
- await expect(nft.transfer(bob, {Substrate: bob.address}))
- .to.be.rejectedWith(/common\.NoPermission/);
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('[fungible] Transfer with recipient that is not owner', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-4-FT', description: '', tokenPrefix: 'T'});
- await collection.mint(alice, 10n);
-
- await expect(collection.transfer(bob, {Substrate: bob.address}, 9n))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(10n);
- });
-
- itSub.ifWithPallets('[refungible] Transfer with recipient that is not owner', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});
- const rft = await collection.mintToken(alice, 10n);
-
- await expect(rft.transfer(bob, {Substrate: bob.address}, 9n))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(0n);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(10n);
- });
-});
-
-describe('Transfers to self (potentially over substrate-evm boundary)', () => {
- let donor: IKeyringPair;
-
- before(async function() {
- await usingEthPlaygrounds(async (_, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- });
- });
-
- itEth('Transfers to self. In case of same frontend', async ({helper}) => {
- const [owner] = await helper.arrange.createAccounts([10n], donor);
- const collection = await helper.ft.mintCollection(owner, {});
- await collection.mint(owner, 100n);
-
- const ownerProxy = helper.address.substrateToEth(owner.address);
-
- // transfer to own proxy
- await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);
- expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);
-
- // transfer-from own proxy to own proxy again
- await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Ethereum: ownerProxy}, 5n);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);
- expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);
- });
-
- itEth('Transfers to self. In case of substrate-evm boundary', async ({helper}) => {
- const [owner] = await helper.arrange.createAccounts([10n], donor);
- const collection = await helper.ft.mintCollection(owner, {});
- await collection.mint(owner, 100n);
-
- const ownerProxy = helper.address.substrateToEth(owner.address);
-
- // transfer to own proxy
- await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);
- expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);
-
- // transfer-from own proxy to self
- await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Substrate: owner.address}, 5n);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(95n);
- expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(5n);
- });
-
- itEth('Transfers to self. In case of inside substrate-evm', async ({helper}) => {
- const [owner] = await helper.arrange.createAccounts([10n], donor);
- const collection = await helper.ft.mintCollection(owner, {});
- await collection.mint(owner, 100n);
-
- // transfer to self again
- await collection.transfer(owner, {Substrate: owner.address}, 10n);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);
-
- // transfer-from self to self again
- await collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 5n);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);
- });
-
- itEth('Transfers to self. In case of inside substrate-evm when not enought "Fungibles"', async ({helper}) => {
- const [owner] = await helper.arrange.createAccounts([10n], donor);
- const collection = await helper.ft.mintCollection(owner, {});
- await collection.mint(owner, 10n);
-
- // transfer to self again
- await expect(collection.transfer(owner, {Substrate: owner.address}, 11n))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
-
- // transfer-from self to self again
- await expect(collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 12n))
- .to.be.rejectedWith(/common\.TokenValueTooLow/);
- expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(10n);
- });
-});
js-packages/tests/src/transferFrom.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/transferFrom.test.ts
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect} from './util/index.js';
-import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/src/types.js';
-
-describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
- });
- });
-
- itSub('[nft] Execute the extrinsic and check nftItemList - owner of token', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-1', description: '', tokenPrefix: 'TF'});
- const nft = await collection.mintToken(alice);
- await nft.approve(alice, {Substrate: bob.address});
- expect(await nft.isApproved({Substrate: bob.address})).to.be.true;
-
- await nft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address});
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: charlie.address});
- });
-
- itSub('[fungible] Execute the extrinsic and check nftItemList - owner of token', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-2', description: '', tokenPrefix: 'TF'});
- await collection.mint(alice, 10n);
- await collection.approveTokens(alice, {Substrate: bob.address}, 7n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(7n);
-
- await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 6n);
- expect(await collection.getBalance({Substrate: charlie.address})).to.be.equal(6n);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(4n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(1n);
- });
-
- itSub.ifWithPallets('[refungible] Execute the extrinsic and check nftItemList - owner of token', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-3', description: '', tokenPrefix: 'TF'});
- const rft = await collection.mintToken(alice, 10n);
- await rft.approve(alice, {Substrate: bob.address}, 7n);
- expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(7n);
-
- await rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 6n);
- expect(await rft.getBalance({Substrate: charlie.address})).to.be.equal(6n);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(4n);
- expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(1n);
- });
-
- itSub('Should reduce allowance if value is big', async ({helper}) => {
- // fungible
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-4', description: '', tokenPrefix: 'TF'});
- await collection.mint(alice, 500000n);
-
- await collection.approveTokens(alice, {Substrate: bob.address}, 500000n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(500000n);
- await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 500000n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(0n);
- });
-
- itSub('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-5', description: '', tokenPrefix: 'TF'});
- await collection.setLimits(alice, {ownerCanTransfer: true});
-
- const nft = await collection.mintToken(alice, {Substrate: bob.address});
- await nft.transferFrom(alice, {Substrate: bob.address}, {Substrate: charlie.address});
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: charlie.address});
- });
-});
-
-describe('Negative Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
- let charlie: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob, charlie] = await helper.arrange.createAccounts([50n, 10n, 10n], donor);
- });
- });
-
- itSub('transferFrom for a collection that does not exist', async ({helper}) => {
- await expect(helper.collection.approveToken(alice, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: bob.address}, 1n))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- await expect(helper.collection.transferTokenFrom(bob, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))
- .to.be.rejectedWith(/common\.CollectionNotFound/);
- });
-
- /* itSub('transferFrom for a collection that was destroyed', async ({helper}) => {
- this test copies approve negative test
- }); */
-
- /* itSub('transferFrom a token that does not exist', async ({helper}) => {
- this test copies approve negative test
- }); */
-
- /* itSub('transferFrom a token that was deleted', async ({helper}) => {
- this test copies approve negative test
- }); */
-
- itSub('[nft] transferFrom for not approved address', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-1', description: '', tokenPrefix: 'TF'});
- const nft = await collection.mintToken(alice);
-
- await expect(nft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('[fungible] transferFrom for not approved address', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-1', description: '', tokenPrefix: 'TF'});
- await collection.mint(alice, 10n);
-
- await expect(collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 5n))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
- expect(await collection.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
- });
-
- itSub.ifWithPallets('[refungible] transferFrom for not approved address', [Pallets.ReFungible], async({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-3', description: '', tokenPrefix: 'TF'});
- const rft = await collection.mintToken(alice, 10n);
-
- await expect(rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
- expect(await rft.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
- expect(await rft.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
- });
-
- itSub('[nft] transferFrom incorrect token count', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-4', description: '', tokenPrefix: 'TF'});
- const nft = await collection.mintToken(alice);
-
- await nft.approve(alice, {Substrate: bob.address});
- expect(await nft.isApproved({Substrate: bob.address})).to.be.true;
-
- await expect(helper.collection.transferTokenFrom(
- bob,
- collection.collectionId,
- nft.tokenId,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- 2n,
- )).to.be.rejectedWith(/nonfungible\.NonfungibleItemsHaveNoAmount/);
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('[fungible] transferFrom incorrect token count', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-5', description: '', tokenPrefix: 'TF'});
- await collection.mint(alice, 10n);
-
- await collection.approveTokens(alice, {Substrate: bob.address}, 2n);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(2n);
-
- await expect(collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 5n))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
- expect(await collection.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
- });
-
- itSub.ifWithPallets('[refungible] transferFrom incorrect token count', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-6', description: '', tokenPrefix: 'TF'});
- const rft = await collection.mintToken(alice, 10n);
-
- await rft.approve(alice, {Substrate: bob.address}, 5n);
- expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(5n);
-
- await expect(rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 7n))
- .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
- expect(await rft.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
- expect(await rft.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
- });
-
- itSub('[nft] execute transferFrom from account that is not owner of collection', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-7', description: '', tokenPrefix: 'TF'});
- const nft = await collection.mintToken(alice);
-
- await expect(nft.approve(charlie, {Substrate: bob.address})).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
- expect(await nft.isApproved({Substrate: bob.address})).to.be.false;
-
- await expect(nft.transferFrom(
- charlie,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
- });
-
- itSub('[fungible] execute transferFrom from account that is not owner of collection', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-8', description: '', tokenPrefix: 'TF'});
- await collection.mint(alice, 10000n);
-
- await expect(collection.approveTokens(charlie, {Substrate: bob.address}, 1n)).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(0n);
- expect(await collection.getApprovedTokens({Substrate: charlie.address}, {Substrate: bob.address})).to.be.eq(0n);
-
- await expect(collection.transferFrom(
- charlie,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10000n);
- expect(await collection.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
- expect(await collection.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
- });
-
- itSub.ifWithPallets('[refungible] execute transferFrom from account that is not owner of collection', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-9', description: '', tokenPrefix: 'TF'});
- const rft = await collection.mintToken(alice, 10000n);
-
- await expect(rft.approve(charlie, {Substrate: bob.address}, 1n)).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
- expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(0n);
- expect(await rft.getApprovedPieces({Substrate: charlie.address}, {Substrate: bob.address})).to.be.eq(0n);
-
- await expect(rft.transferFrom(
- charlie,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10000n);
- expect(await rft.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
- expect(await rft.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
- });
-
- itSub('transferFrom burnt token before approve NFT', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-10', description: '', tokenPrefix: 'TF'});
- await collection.setLimits(alice, {ownerCanTransfer: true});
- const nft = await collection.mintToken(alice);
-
- await nft.burn(alice);
- await expect(nft.approve(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.TokenNotFound/);
-
- await expect(nft.transferFrom(
- bob,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- });
-
- itSub('transferFrom burnt token before approve Fungible', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-11', description: '', tokenPrefix: 'TF'});
- await collection.setLimits(alice, {ownerCanTransfer: true});
- await collection.mint(alice, 10n);
-
- await collection.burnTokens(alice, 10n);
- await expect(collection.approveTokens(alice, {Substrate: bob.address})).to.be.not.rejected;
-
- await expect(collection.transferFrom(
- alice,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub.ifWithPallets('transferFrom burnt token before approve ReFungible', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-12', description: '', tokenPrefix: 'TF'});
- await collection.setLimits(alice, {ownerCanTransfer: true});
- const rft = await collection.mintToken(alice, 10n);
-
- await rft.burn(alice, 10n);
- await expect(rft.approve(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
-
- await expect(rft.transferFrom(
- alice,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub('transferFrom burnt token after approve NFT', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-13', description: '', tokenPrefix: 'TF'});
- const nft = await collection.mintToken(alice);
-
- await nft.approve(alice, {Substrate: bob.address});
- expect(await nft.isApproved({Substrate: bob.address})).to.be.true;
-
- await nft.burn(alice);
-
- await expect(nft.transferFrom(
- bob,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- });
-
- itSub('transferFrom burnt token after approve Fungible', async ({helper}) => {
- const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-14', description: '', tokenPrefix: 'TF'});
- await collection.mint(alice, 10n);
-
- await collection.approveTokens(alice, {Substrate: bob.address});
- expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(1n);
-
- await collection.burnTokens(alice, 10n);
-
- await expect(collection.transferFrom(
- bob,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.TokenValueTooLow/);
- });
-
- itSub.ifWithPallets('transferFrom burnt token after approve ReFungible', [Pallets.ReFungible], async ({helper}) => {
- const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-15', description: '', tokenPrefix: 'TF'});
- const rft = await collection.mintToken(alice, 10n);
-
- await rft.approve(alice, {Substrate: bob.address}, 10n);
- expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(10n);
-
- await rft.burn(alice, 10n);
-
- await expect(rft.transferFrom(
- bob,
- {Substrate: alice.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- });
-
- itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-16', description: '', tokenPrefix: 'TF'});
- const nft = await collection.mintToken(alice, {Substrate: bob.address});
-
- await collection.setLimits(alice, {ownerCanTransfer: false});
-
- await expect(nft.transferFrom(
- alice,
- {Substrate: bob.address},
- {Substrate: charlie.address},
- )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
- });
-
- itSub('zero transfer NFT', async ({helper}) => {
- const collection = await helper.nft.mintCollection(alice, {name: 'Zero', description: 'Zero transfer', tokenPrefix: 'TF'});
- const notApprovedNft = await collection.mintToken(alice, {Substrate: bob.address});
- const approvedNft = await collection.mintToken(alice, {Substrate: bob.address});
- await approvedNft.approve(bob, {Substrate: alice.address});
-
- // 1. Cannot zero transferFrom (non-existing token)
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, 9999, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
- // 2. Cannot zero transferFrom (not approved token)
- await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, notApprovedNft.tokenId, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
- // 3. Can zero transferFrom (approved token):
- await helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, approvedNft.tokenId, 0]);
-
- // 4.1 approvedNft still approved:
- expect(await approvedNft.isApproved({Substrate: alice.address})).to.be.true;
- // 4.2 bob is still the owner:
- expect(await approvedNft.getOwner()).to.deep.eq({Substrate: bob.address});
- expect(await notApprovedNft.getOwner()).to.deep.eq({Substrate: bob.address});
- // 4.3 Alice can transfer approved nft:
- await approvedNft.transferFrom(alice, {Substrate: bob.address}, {Substrate: alice.address});
- expect(await approvedNft.getOwner()).to.deep.eq({Substrate: alice.address});
- });
-});
js-packages/tests/src/tx-version-presence.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/tx-version-presence.test.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {Metadata} from '@polkadot/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-
-let metadata: Metadata;
-
-describe('TxVersion is present', () => {
- before(async () => {
- await usingPlaygrounds(async helper => {
- metadata = await helper.callRpc('api.rpc.state.getMetadata', []);
- });
- });
-
- itSub('Signed extension CheckTxVersion is present', () => {
- expect(metadata.asLatest.extrinsic.signedExtensions.map(se => se.identifier.toString())).to.include('CheckTxVersion');
- });
-});
js-packages/tests/src/util/authorizeEnactUpgrade.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/authorizeEnactUpgrade.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import {readFile} from 'fs/promises';
-import {u8aToHex} from '@polkadot/util';
-import {usingPlaygrounds} from './index.js';
-import {blake2AsHex} from '@polkadot/util-crypto';
-
-
-const codePath = process.argv[2];
-if(!codePath) throw new Error('missing code path argument');
-
-const code = await readFile(codePath);
-
-await usingPlaygrounds(async (helper, privateKey) => {
- const alice = await privateKey('//Alice');
- const hex = blake2AsHex(code);
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.parachainSystem.authorizeUpgrade', [hex, true]);
- await helper.getSudo().executeExtrinsicUncheckedWeight(alice, 'api.tx.parachainSystem.enactAuthorizedUpgrade', [u8aToHex(code)]);
-});
-// We miss disconnect/unref somewhere.
-process.exit(0);
js-packages/tests/src/util/createHrmp.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/createHrmp.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import {usingPlaygrounds} from './index.js';
-import config from '../config.js';
-
-const profile = process.argv[2];
-if(!profile) throw new Error('missing profile/relay argument');
-
-await usingPlaygrounds(async (helper, privateKey) => {
- const bidirOpen = async (a: number, b: number) => {
- console.log(`Opening ${a} <=> ${b}`);
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.hrmp.forceOpenHrmpChannel', [a, b, 8, 512]);
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.hrmp.forceOpenHrmpChannel', [b, a, 8, 512]);
- };
- const alice = await privateKey('//Alice');
- switch (profile) {
- case 'opal':
- await bidirOpen(1001, 1002);
- break;
- case 'quartz':
- await bidirOpen(1001, 1002);
- await bidirOpen(1001, 1003);
- await bidirOpen(1001, 1004);
- await bidirOpen(1001, 1005);
- break;
- case 'unique':
- await bidirOpen(1001, 1002);
- await bidirOpen(1001, 1003);
- await bidirOpen(1001, 1004);
- await bidirOpen(1001, 1005);
- await bidirOpen(1001, 1006);
- break;
- default:
- throw new Error(`unknown hrmp config profile: ${profile}`);
- }
-}, config.relayUrl);
-// We miss disconnect/unref somewhere.
-process.exit(0);
js-packages/tests/src/util/frankensteinMigrate.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/frankensteinMigrate.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import {migration as locksToFreezesMigration} from '../migrations/942057-appPromotion/index.js';
-export interface Migration {
- before: () => Promise<void>,
- after: () => Promise<void>,
-}
-
-export const migrations: {[key: string]: Migration} = {
- 'v942057': locksToFreezesMigration,
-};
js-packages/tests/src/util/globalSetup.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/globalSetup.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-import {
- usingPlaygrounds, Pallets, DONOR_FUNDING, MINIMUM_DONOR_FUND, LOCKING_PERIOD, UNLOCKING_PERIOD, makeNames,
-} from './index.js';
-import * as path from 'path';
-import {promises as fs} from 'fs';
-
-const {dirname} = makeNames(import.meta.url);
-
-// This function should be called before running test suites.
-const globalSetup = async (): Promise<void> => {
- await usingPlaygrounds(async (helper, privateKey) => {
- try {
- // 1. Wait node producing blocks
- await helper.wait.newBlocks(1, 600_000);
-
- // 2. Create donors for test files
- await fundFilenamesWithRetries(3)
- .then((result) => {
- if(!result) throw Error('Some problems with fundFilenamesWithRetries');
- });
-
- // 3. Configure App Promotion
- const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]);
- if(missingPallets.length === 0) {
- const superuser = await privateKey('//Alice');
- const palletAddress = helper.arrange.calculatePalletAddress('appstake');
- const palletAdmin = await privateKey('//PromotionAdmin');
- const api = helper.getApi();
- await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
- const nominal = helper.balance.getOneTokenNominal();
- await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 10000n * nominal);
- await helper.balance.transferToSubstrate(superuser, palletAddress, 10000n * nominal);
- await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.configuration
- .setAppPromotionConfigurationOverride({
- recalculationInterval: LOCKING_PERIOD,
- pendingInterval: UNLOCKING_PERIOD})], true);
- }
- } catch (error) {
- console.error(error);
- throw Error('Error during globalSetup');
- }
- });
-};
-
-async function getFiles(rootPath: string): Promise<string[]> {
- const files = await fs.readdir(rootPath, {withFileTypes: true});
- const filenames: string[] = [];
- for(const entry of files) {
- const res = path.resolve(rootPath, entry.name);
- if(entry.isDirectory()) {
- filenames.push(...await getFiles(res));
- } else {
- filenames.push(res);
- }
- }
- return filenames;
-}
-
-const fundFilenames = async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const oneToken = helper.balance.getOneTokenNominal();
- const alice = await privateKey('//Alice');
- const nonce = await helper.chain.getNonce(alice.address);
- const filenames = await getFiles(path.resolve(dirname, '..'));
-
- // batching is actually undesireable, it takes away the time while all the transactions actually succeed
- const batchSize = 300;
- let balanceGrantedCounter = 0;
- for(let b = 0; b < filenames.length; b += batchSize) {
- const tx: Promise<boolean>[] = [];
- let batchBalanceGrantedCounter = 0;
- for(let i = 0; batchBalanceGrantedCounter < batchSize && b + i < filenames.length; i++) {
- const f = filenames[b + i];
- if(!f.endsWith('.test.ts') && !f.endsWith('seqtest.ts') || f.includes('.outdated')) continue;
- const account = await privateKey({filename: f, ignoreFundsPresence: true});
- const aliceBalance = await helper.balance.getSubstrate(account.address);
-
- if(aliceBalance < MINIMUM_DONOR_FUND * oneToken) {
- tx.push(helper.executeExtrinsic(
- alice,
- 'api.tx.balances.transfer',
- [account.address, DONOR_FUNDING * oneToken],
- true,
- {nonce: nonce + balanceGrantedCounter++},
- ).then(() => true).catch(() => {console.error(`Transaction to ${path.basename(f)} registered as failed. Strange.`); return false;}));
- batchBalanceGrantedCounter++;
- }
- }
-
- if(tx.length > 0) {
- console.log(`Granting funds to ${batchBalanceGrantedCounter} filename accounts.`);
- const result = await Promise.all(tx);
- if(result && result.lastIndexOf(false) > -1) throw new Error('The transactions actually probably succeeded, should check the balances.');
- }
- }
-
- if(balanceGrantedCounter == 0) console.log('No account needs additional funding.');
- });
-};
-
-const fundFilenamesWithRetries = (retriesLeft: number): Promise<boolean> => {
- if(retriesLeft <= 0) return Promise.resolve(false);
- return fundFilenames()
- .then(() => Promise.resolve(true))
- .catch(e => {
- console.error(e);
- console.error(`Some transactions might have failed. ${retriesLeft > 1 ? 'Retrying...' : 'Something is wrong.'}\n`);
- return fundFilenamesWithRetries(--retriesLeft);
- });
-};
-
-globalSetup().catch(e => {
- console.error('Setup error');
- console.error(e);
- process.exit(1);
-});
js-packages/tests/src/util/identitySetter.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/identitySetter.ts
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-//
-// Pulls identities and sub-identities from a chain and then makes a preimage to later force upload them into another.
-// Only changed or previously non-existent data are inserted.
-//
-// Usage: `yarn setIdentities [relay WS URL] [parachain WS URL] [user key]
-// Example: `yarn setIdentities wss://polkadot-rpc.dwellir.com ws://localhost:9944 escape pattern miracle train sudden cart adapt embark wedding alien lamp mesh`
-
-import {encodeAddress} from '@polkadot/keyring';
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, Pallets} from './index.js';
-import {ChainHelperBase} from '@unique/playgrounds/src/unique.js';
-
-const relayUrl = process.argv[2] ?? 'ws://localhost:9844';
-const paraUrl = process.argv[3] ?? 'ws://localhost:9944';
-const key = process.argv.length > 4 ? process.argv.slice(4).join(' ') : '//Alice';
-
-export function extractAccountId(key: any): string {
- return (key as any).toHuman()[0];
-}
-
-export function extractIdentityInfo(value: any): object {
- const heart = (value as any).unwrap();
- const identity = heart.toJSON();
- identity.judgements = heart.judgements.toHuman();
- return identity;
-}
-
-export function extractIdentity(key: any, value: any): [string, any] {
- return [extractAccountId(key), extractIdentityInfo(value)];
-}
-
-export async function getIdentities(helper: ChainHelperBase, noneCasePredicate?: (key: any, value: any) => void) {
- const identities: [string, any][] = [];
- for(const [key, v] of await helper.getApi().query.identity.identityOf.entries()) {
- const value = v as any;
- if(value.isNone) {
- if(noneCasePredicate) noneCasePredicate(key, value);
- continue;
- }
- identities.push(extractIdentity(key, value));
- }
- return identities;
-}
-
-// whether the existing chain data is more important than the coming
-function isCurrentChainDataPriority(helper: ChainHelperBase, currentChainId: number | undefined, relayChainId: number) {
- if(!currentChainId) return false;
- // information has come from local chain, and is automatically superior
- if(currentChainId == helper.chain.getChainProperties().ss58Format) return true;
- // the lower the id, the more important it is (Polkadot has ss58 prefix = 0, Kusama has ss58 prefix = 2)
- return currentChainId < relayChainId;
-}
-
-// construct an object with all data necessary for insertion from storage query results
-export function constructSubInfo(identityAccount: string, subQuery: any, supers: any[], ss58?: number): [string, any] {
- const deposit = subQuery.toJSON()[0];
- const subIdentities = subQuery.toHuman()[1];
- subIdentities.map((sub: string) => supers.find((sup: any) => sup[0] === sub));
-
- return [
- encodeAddress(identityAccount, ss58), [
- deposit,
- subIdentities.map((sub: string): [string, object] | null => {
- const sup = supers.find((sup: any) => sup[0] === sub);
- if(!sup) {
- console.error(`Error: Could not find info on super for \nsub-identity account\t${sub} of \nsuper account \t\t${identityAccount}, skipping.`);
- return null;
- }
- return [encodeAddress(sub, ss58), sup[1].toJSON()[1]];
- }).filter((x: any) => x),
- ],
- ];
-}
-
-export async function getSubs(helper: ChainHelperBase) {
- return (await helper.getApi().query.identity.subsOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);
-}
-
-export async function getSupers(helper: ChainHelperBase) {
- return (await helper.getApi().query.identity.superOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);
-}
-
-async function uploadPreimage(helper: ChainHelperBase, preimageMaker: IKeyringPair, preimage: string) {
- try {
- await helper.executeExtrinsic(preimageMaker, 'api.tx.preimage.notePreimage', [preimage]);
- } catch (e: any) {
- if(e.message.includes('AlreadyNoted')) {
- console.warn('Warning: The same preimage already exists on the chain. Nothing was uploaded.');
- } else {
- console.error(e);
- }
- }
-}
-
-// The utility for pulling identity and sub-identity data
-const forceInsertIdentities = async (): Promise<void> => {
- let relaySS58Prefix = 0;
- const identitiesOnRelay: any[] = [];
- const subsOnRelay: any[] = [];
- const identitiesToRemove: string[] = [];
- await usingPlaygrounds(async helper => {
- try {
- relaySS58Prefix = helper.chain.getChainProperties().ss58Format;
- // iterate over every identity
- for(const [key, value] of await getIdentities(helper, (key, _value) => identitiesToRemove.push((key as any).toHuman()[0]))) {
- // if any of the judgements resulted in a good confirmed outcome, keep this identity
- let knownGood = false, reasonable = false;
- for(const [_id, judgement] of value.judgements) {
- if(judgement == 'KnownGood') knownGood = true;
- if(judgement == 'Reasonable') reasonable = true;
- }
- if(!(reasonable || knownGood)) continue;
- // replace the registrator id with the relay chain's ss58 format
- value.judgements = [[helper.chain.getChainProperties().ss58Format, knownGood ? 'KnownGood' : 'Reasonable']];
- identitiesOnRelay.push([key, value]);
- }
-
- const sublessIdentities = [...identitiesOnRelay];
- const supersOfSubs = await getSupers(helper);
-
- // iterate over every sub-identity
- for(const [key, value] of await getSubs(helper)) {
- // only get subs of the identities interesting to us
- const identityIndex = sublessIdentities.findIndex((x: any) => x[0] == key);
- if(identityIndex == -1) continue;
- sublessIdentities.splice(identityIndex, 1);
- subsOnRelay.push(constructSubInfo(key, value, supersOfSubs));
- }
-
- // mark the rest of sub-identities for deletion with empty arrays
- /*for(const [account, _identity] of sublessIdentities) {
- subsOnRelay.push([account, ['0', []]]);
- }*/
- } catch (error) {
- console.error(error);
- throw Error('Error during fetching identities');
- }
- }, relayUrl);
-
- await usingPlaygrounds(async (helper, privateKey) => {
- if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) console.error('pallet-identity is not included in parachain.');
- if(helper.fetchMissingPalletNames([Pallets.Preimage]).length != 0) console.error('pallet-preimage is not included in parachain.');
-
- try {
- const preimageMaker = await privateKey(key);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const paraIdentities = await getIdentities(helper);
- const identitiesToAdd: any[] = [];
- const paraAccountsRegistrators: {[name: string]: number} = {};
-
- // cross-reference every account for changes
- for(const [key, value] of identitiesOnRelay) {
- const encodedKey = encodeAddress(key, ss58Format);
-
- // only update if the identity info does not exist or is changed
- const identity = paraIdentities.find(i => i[0] === encodedKey);
- if(identity) {
- const registratorId = identity[1].judgements[0][0];
- paraAccountsRegistrators[encodedKey] = registratorId;
- if(isCurrentChainDataPriority(helper, registratorId, value.judgements[0][0])
- || JSON.stringify(value.info) === JSON.stringify(identity[1].info)) {
- continue;
- }
- }
-
- identitiesToAdd.push([key, value]);
- // exercise caution - in case we have an identity and the realy doesn't, it might mean one of two things:
- // 1) it was deleted on the relay;
- // 2) it is our own identity, we don't want to delete it.
- // identitiesToRemove.push((key as any).toHuman()[0]);
- }
-
- if(identitiesToRemove.length != 0)
- await uploadPreimage(
- helper,
- preimageMaker,
- helper.constructApiCall('api.tx.identity.forceRemoveIdentities', [identitiesToRemove]).method.toHex(),
- );
- if(identitiesToAdd.length != 0)
- await uploadPreimage(
- helper,
- preimageMaker,
- helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex(),
- );
-
- console.log(`Tried to push ${identitiesToAdd.length} identities`
- + ` and found ${identitiesToRemove.length} identities for potential removal.`
- + ` Currently there are ${(await helper.getApi().query.identity.identityOf.keys()).length} identities on the chain.`);
-
- // fill sub-identities
- const paraSubs = await getSubs(helper);
- const supersOfSubs = await getSupers(helper);
- const subsToUpdate: any[] = [];
-
- for(const [key, value] of subsOnRelay) {
- const encodedKey = encodeAddress(key, ss58Format);
- const sub = paraSubs.find(i => i[0] === encodedKey);
- if(sub) {
- // only update if the sub-identity info does not exist or is changed
- if(isCurrentChainDataPriority(helper, paraAccountsRegistrators[encodedKey], relaySS58Prefix)
- || JSON.stringify(value) === JSON.stringify(constructSubInfo(sub[0], sub[1], supersOfSubs)[1])) {
- continue;
- }
- } else if(value[1].length == 0)
- continue;
-
- subsToUpdate.push([key, value]);
- }
-
- if(subsToUpdate.length != 0)
- await uploadPreimage(
- helper,
- preimageMaker,
- helper.constructApiCall('api.tx.identity.forceSetSubs', [subsToUpdate]).method.toHex(),
- );
-
- console.log(`Also tried to push ${subsToUpdate.length} identities with their sub-identities.`
- + ` Currently there are ${(await helper.getApi().query.identity.subsOf.keys()).length} identities with subs.`);
- } catch (error) {
- console.error(error);
- throw Error('Error during setting identities');
- }
- }, paraUrl);
-};
-
-if(process.argv[1] === module.filename)
- forceInsertIdentities().catch(() => process.exit(1));
js-packages/tests/src/util/index.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/index.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-import * as path from 'path';
-import * as crypto from 'crypto';
-import type {IKeyringPair} from '@polkadot/types/types/interfaces';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import chaiSubset from 'chai-subset';
-import {Context} from 'mocha';
-import config from '../config.js';
-import {ChainHelperBase} from '@unique/playgrounds/src/unique.js';
-import type {ILogger} from '@unique/playgrounds/src/types.js';
-import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper, DevAstarHelper, DevShidenHelper, DevPolkadexHelper} from '@unique/playgrounds/src/unique.dev.js';
-import {dirname} from 'path';
-import {fileURLToPath} from 'url';
-
-chai.config.truncateThreshold = 0;
-chai.use(chaiAsPromised);
-chai.use(chaiSubset);
-export const expect = chai.expect;
-
-const getTestHash = (filename: string) => crypto.createHash('md5').update(filename).digest('hex');
-
-export const getTestSeed = (filename: string) => `//Alice+${getTestHash(filename)}`;
-
-async function usingPlaygroundsGeneral<T extends ChainHelperBase, R = void>(
- helperType: new (logger: ILogger) => T,
- url: string,
- code: (helper: T, privateKey: (seed: string | { filename?: string, url?: string, ignoreFundsPresence?: boolean }) => Promise<IKeyringPair>) => Promise<R>,
-): Promise<R> {
- const silentConsole = new SilentConsole();
- silentConsole.enable();
-
- const helper = new helperType(new SilentLogger());
- let result;
- try {
- await helper.connect(url);
- const ss58Format = helper.chain.getChainProperties().ss58Format;
- const privateKey = async (seed: string | {filename?: string, url?: string, ignoreFundsPresence?: boolean}) => {
- if(typeof seed === 'string') {
- return helper.util.fromSeed(seed, ss58Format);
- }
- if(seed.url) {
- const {filename} = makeNames(seed.url);
- seed.filename = filename;
- } else if(seed.filename) {
- // Pass
- } else {
- throw new Error('no url nor filename set');
- }
- const actualSeed = getTestSeed(seed.filename);
- let account = helper.util.fromSeed(actualSeed, ss58Format);
- // here's to hoping that no
- if(!seed.ignoreFundsPresence && ((helper as any)['balance'] == undefined || await (helper as any).balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND)) {
- console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
- account = helper.util.fromSeed('//Alice', ss58Format);
- }
- return account;
- };
- result = await code(helper, privateKey);
- }
- finally {
- await helper.disconnect();
- silentConsole.disable();
- }
- return result as any as R;
-}
-
-export const usingPlaygrounds = <R = void>(code: (helper: DevUniqueHelper, privateKey: (seed: string | {filename?: string, url?: string, ignoreFundsPresence?: boolean}) => Promise<IKeyringPair>) => Promise<R>, url: string = config.substrateUrl) => usingPlaygroundsGeneral<DevUniqueHelper, R>(DevUniqueHelper, url, code);
-
-export const usingWestmintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevWestmintHelper>(DevWestmintHelper, url, code);
-
-export const usingStateminePlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevStatemineHelper>(DevWestmintHelper, url, code);
-
-export const usingStatemintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevStatemintHelper>(DevWestmintHelper, url, code);
-
-export const usingRelayPlaygrounds = (url: string, code: (helper: DevRelayHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevRelayHelper>(DevRelayHelper, url, code);
-
-export const usingAcalaPlaygrounds = (url: string, code: (helper: DevAcalaHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevAcalaHelper>(DevAcalaHelper, url, code);
-
-export const usingKaruraPlaygrounds = (url: string, code: (helper: DevKaruraHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevKaruraHelper>(DevAcalaHelper, url, code);
-
-export const usingMoonbeamPlaygrounds = (url: string, code: (helper: DevMoonbeamHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevMoonbeamHelper>(DevMoonbeamHelper, url, code);
-
-export const usingMoonriverPlaygrounds = (url: string, code: (helper: DevMoonbeamHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevMoonriverHelper>(DevMoonriverHelper, url, code);
-
-export const usingAstarPlaygrounds = (url: string, code: (helper: DevAstarHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevAstarHelper>(DevAstarHelper, url, code);
-
-export const usingShidenPlaygrounds = (url: string, code: (helper: DevShidenHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevShidenHelper>(DevShidenHelper, url, code);
-
-export const usingPolkadexPlaygrounds = (url: string, code: (helper: DevPolkadexHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevPolkadexHelper>(DevPolkadexHelper, url, code);
-
-export const MINIMUM_DONOR_FUND = 4_000_000n;
-export const DONOR_FUNDING = 4_000_000n;
-
-// App-promotion periods:
-export const LOCKING_PERIOD = 12n; // 12 blocks of relay
-export const UNLOCKING_PERIOD = 6n; // 6 blocks of parachain
-
-// Native contracts
-export const COLLECTION_HELPER = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f';
-export const CONTRACT_HELPER = '0x842899ECF380553E8a4de75bF534cdf6fBF64049';
-
-export enum Pallets {
- Inflation = 'inflation',
- ReFungible = 'refungible',
- Fungible = 'fungible',
- NFT = 'nonfungible',
- Scheduler = 'scheduler',
- UniqueScheduler = 'uniqueScheduler',
- AppPromotion = 'apppromotion',
- CollatorSelection = 'collatorselection',
- Session = 'session',
- Identity = 'identity',
- Democracy = 'democracy',
- Council = 'council',
- //CouncilMembership = 'councilmembership',
- TechnicalCommittee = 'technicalcommittee',
- Fellowship = 'fellowshipcollective',
- Preimage = 'preimage',
- Maintenance = 'maintenance',
- TestUtils = 'testutils',
-}
-
-export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: readonly string[]) {
- const missingPallets = helper.fetchMissingPalletNames(requiredPallets);
-
- if(missingPallets.length > 0) {
- const skipMsg = `\tSkipping test '${test.test?.title}'.\n\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
- console.warn('\x1b[38:5:208m%s\x1b[0m', skipMsg);
- test.skip();
- }
-}
-
-export function itSub(name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: readonly string[] } = {}) {
- (opts.only ? it.only :
- opts.skip ? it.skip : it)(name, async function () {
- await usingPlaygrounds(async (helper, privateKey) => {
- if(opts.requiredPallets) {
- requirePalletsOrSkip(this, helper, opts.requiredPallets);
- }
-
- await cb({helper, privateKey});
- });
- });
-}
-export function itSubIfWithPallet(name: string, required: readonly string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: readonly string[] } = {}) {
- return itSub(name, cb, {requiredPallets: required, ...opts});
-}
-itSub.only = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSub(name, cb, {only: true});
-itSub.skip = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSub(name, cb, {skip: true});
-
-itSubIfWithPallet.only = (name: string, required: readonly string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSubIfWithPallet(name, required, cb, {only: true});
-itSubIfWithPallet.skip = (name: string, required: readonly string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSubIfWithPallet(name, required, cb, {skip: true});
-itSub.ifWithPallets = itSubIfWithPallet;
-
-export type SchedKind = 'anon' | 'named';
-
-export function itSched(
- name: string,
- cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any,
- opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},
-) {
- itSub(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);
- itSub(name + ' (named scheduling)', (apis) => cb('named', apis), opts);
-}
-itSched.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSched(name, cb, {only: true});
-itSched.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSched(name, cb, {skip: true});
-itSched.ifWithPallets = itSchedIfWithPallets;
-
-function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
- return itSched(name, cb, {requiredPallets: required, ...opts});
-}
-
-export function describeXCM(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) {
- (process.env.RUN_XCM_TESTS && !opts.skip
- ? describe
- : describe.skip)(title, fn);
-}
-
-describeXCM.skip = (name: string, fn: (this: Mocha.Suite) => void) => describeXCM(name, fn, {skip: true});
-
-export function describeGov(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) {
- (process.env.RUN_GOV_TESTS && !opts.skip
- ? describe
- : describe.skip)(title, fn);
-}
-
-describeGov.skip = (name: string, fn: (this: Mocha.Suite) => void) => describeGov(name, fn, {skip: true});
-
-export function sizeOfInt(i: number) {
- if(i < 0 || i > 0xffffffff) throw new Error('out of range');
- if(i < 0b11_1111) {
- return 1;
- } else if(i < 0b11_1111_1111_1111) {
- return 2;
- } else if(i < 0b11_1111_1111_1111_1111_1111_1111_1111) {
- return 4;
- } else {
- return 5;
- }
-}
-
-const UTF8_ENCODER = new TextEncoder();
-export function sizeOfEncodedStr(v: string) {
- const encoded = UTF8_ENCODER.encode(v);
- return sizeOfInt(encoded.length) + encoded.length;
-}
-
-export function sizeOfProperty(prop: {key: string, value: string}) {
- return sizeOfEncodedStr(prop.key) + sizeOfEncodedStr(prop.value);
-}
-
-export function makeNames(url: string) {
- const filename = fileURLToPath(url);
- return {
- filename,
- dirname: dirname(filename),
- };
-}
js-packages/tests/src/util/relayIdentitiesChecker.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/relayIdentitiesChecker.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-//
-// Checks and reports the differences between identities and sub-identities on two chains.
-//
-// Usage: `yarn checkRelayIdentities [relay-1 WS URL] [relay-2 WS URL]`
-// Example: `yarn checkRelayIdentities wss://polkadot-rpc.dwellir.com wss://kusama-rpc.dwellir.com`
-
-import {encodeAddress} from '@polkadot/keyring';
-import {usingPlaygrounds} from './index.js';
-import {getIdentities, getSubs, getSupers, constructSubInfo} from './identitySetter.js';
-
-const relay1Url = process.argv[2] ?? 'ws://localhost:9844';
-const relay2Url = process.argv[3] ?? 'ws://localhost:9844';
-
-async function pullIdentities(relayUrl: string): Promise<[any[], any[]]> {
- const identities: any[] = [];
- const subs: any[] = [];
-
- await usingPlaygrounds(async helper => {
- try {
- // iterate over every identity
- for(const [key, value] of await getIdentities(helper)) {
- // if any of the judgements resulted in a good confirmed outcome, keep this identity
- if(value.toHuman().judgements.filter((x: any) => x[1] == 'Reasonable' || x[1] == 'KnownGood').length == 0) continue;
- identities.push([key, value]);
- }
-
- const supersOfSubs = await getSupers(helper);
-
- // iterate over every sub-identity
- for(const [key, value] of await getSubs(helper)) {
- // only get subs of the identities interesting to us
- if(identities.find((x: any) => x[0] == key) == -1) continue;
- subs.push(constructSubInfo(key, value, supersOfSubs));
- }
- } catch (error) {
- console.error(error);
- throw Error(`Error during fetching identities on ${relayUrl}`);
- }
- }, relayUrl);
-
- return [identities, subs];
-}
-
-// The utility for pulling identity and sub-identity data
-const checkRelayIdentities = async (): Promise<void> => {
- const [identitiesOnRelay1, subIdentitiesOnRelay1] = await pullIdentities(relay1Url);
- const [identitiesOnRelay2, subIdentitiesOnRelay2] = await pullIdentities(relay2Url);
-
- console.log('identities counts:\t', identitiesOnRelay1.length, identitiesOnRelay2.length);
- console.log('sub-identities counts:\t', subIdentitiesOnRelay1.length, subIdentitiesOnRelay2.length);
- console.log();
-
- try {
- const matchingAddresses: string[] = [];
- const inequalIdentities: {[name: string]: [any, any]} = {};
-
- for(const [key1, value1] of identitiesOnRelay1) {
- const address = encodeAddress(key1);
- const identity2 = identitiesOnRelay2.find(([key2, _value2]) => address === encodeAddress(key2));
- if(!identity2) continue;
- matchingAddresses.push(address);
-
- //const [[key2, value2]] = identitiesOnRelay2.splice(index2, 1);
- const [_key2, value2] = identity2;
- if(JSON.stringify(value1.info) === JSON.stringify(value2.info)) continue;
- inequalIdentities[address] = [value1, value2];
- }
-
- /*for (const [v1, v2] of Object.values(inequalIdentities)) {
- console.log(v1.toHuman().info);
- console.log();
- console.log(v2.toHuman().info);
- await new Promise(resolve => setTimeout(resolve, 4000));
- }*/
-
- console.log(`Accounts with identities on both relays:\t${matchingAddresses.length}`);
- console.log(`Sub-identities with conflicting information:\t${Object.entries(inequalIdentities).length}`);
- console.log();
-
- const inequalSubIdentities = [];
- let matchesFound = 0;
- for(const address of matchingAddresses) {
- const sub1 = subIdentitiesOnRelay1.find(([key1, _value1]) => address === encodeAddress(key1));
- if(!sub1) continue;
- const sub2 = subIdentitiesOnRelay2.find(([key2, _value2]) => address === encodeAddress(key2));
- if(!sub2) continue;
-
- const [value1, value2] = [sub1[1], sub2[1]];
- matchesFound++;
-
- if(JSON.stringify(value1[1]) === JSON.stringify(value2[1])) {
- continue;
- }
- inequalSubIdentities.push([value1, value2]);
- }
-
- /*for (const [v1, v2] of inequalSubIdentities) {
- console.log(v1[1]);
- console.log();
- console.log(v2[1]);
- await new Promise(resolve => setTimeout(resolve, 300));
- }*/
- console.log(`Accounts with sub-identities on both relays:\t${matchesFound}`);
- console.log(`Of them, those with conflicting sub-identities:\t${inequalSubIdentities.length}`);
- } catch (error) {
- console.error(error);
- throw Error('Error during comparison');
- }
-};
-
-if(process.argv[1] === module.filename)
- checkRelayIdentities().catch(() => process.exit(1));
js-packages/tests/src/util/setCode.tsdiffbeforeafterboth--- a/js-packages/tests/src/util/setCode.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import {readFile} from 'fs/promises';
-import {u8aToHex} from '@polkadot/util';
-import {usingPlaygrounds} from './index.js';
-
-const codePath = process.argv[2];
-if(!codePath) throw new Error('missing code path argument');
-
-const code = await readFile(codePath);
-
-await usingPlaygrounds(async (helper, privateKey) => {
- const alice = await privateKey('//Alice');
- await helper.getSudo().executeExtrinsicUncheckedWeight(alice, 'api.tx.system.setCode', [u8aToHex(code)]);
-});
-// We miss disconnect/unref somewhere.
-process.exit(0);
js-packages/tests/src/vesting.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/vesting.test.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/index.js';
-
-describe('Vesting', () => {
- let donor: IKeyringPair;
- let nominal: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- donor = await privateKey({url: import.meta.url});
- nominal = helper.balance.getOneTokenNominal();
- });
- });
-
- itSub('can perform vestedTransfer and claim tokens', async ({helper}) => {
- // arrange
- const [sender, recepient] = await helper.arrange.createAccounts([1000n, 1n], donor);
- const currentRelayBlock = await helper.chain.getRelayBlockNumber();
- const SCHEDULE_1_PERIOD = 6n; // 6 blocks one period
- const SCHEDULE_1_START = currentRelayBlock + 6n; // Block when 1 schedule starts
- const SCHEDULE_2_PERIOD = 12n; // 12 blocks one period
- const SCHEDULE_2_START = currentRelayBlock + 12n; // Block when 2 schedule starts
- const schedule1 = {start: SCHEDULE_1_START, period: SCHEDULE_1_PERIOD, periodCount: 2n, perPeriod: 50n * nominal};
- const schedule2 = {start: SCHEDULE_2_START, period: SCHEDULE_2_PERIOD, periodCount: 2n, perPeriod: 100n * nominal};
-
- // act
- await helper.balance.vestedTransfer(sender, recepient.address, schedule1);
- await helper.balance.vestedTransfer(sender, recepient.address, schedule2);
- let schedule = await helper.balance.getVestingSchedules(recepient.address);
-
- // check senders balance after vesting:
- let balanceSender = await helper.balance.getSubstrateFull(sender.address);
- expect(balanceSender.free / nominal).to.eq(699n);
- expect(balanceSender.frozen).to.eq(0n);
- expect(balanceSender.reserved).to.eq(0n);
-
- // check recepient balance after vesting:
- let balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
- expect(balanceRecepient.free).to.eq(301n * nominal);
- expect(balanceRecepient.frozen).to.eq(300n * nominal);
- expect(balanceRecepient.reserved).to.eq(0n);
-
- // Schedules list correct:
- expect(schedule).to.has.length(2);
- expect(schedule[0]).to.deep.eq(schedule1);
- expect(schedule[1]).to.deep.eq(schedule2);
-
- // Wait first part available:
- await helper.wait.forRelayBlockNumber(SCHEDULE_1_START + SCHEDULE_1_PERIOD);
- await helper.balance.claim(recepient);
-
- // check recepient balance after claim (50 tokens claimed, 250 left):
- balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
- expect(balanceRecepient.free / nominal).to.eq(300n);
- expect(balanceRecepient.frozen).to.eq(250n * nominal);
- expect(balanceRecepient.reserved).to.eq(0n);
-
- // Wait first schedule ends and first part od second schedule:
- await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD);
- await helper.balance.claim(recepient);
-
- // check recepient balance after second claim (150 tokens claimed, 100 left):
- balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
- expect(balanceRecepient.free / nominal).to.eq(300n);
- expect(balanceRecepient.frozen).to.eq(100n * nominal);
- expect(balanceRecepient.reserved).to.eq(0n);
-
- // Schedules list contain 1 vesting:
- schedule = await helper.balance.getVestingSchedules(recepient.address);
- expect(schedule).to.has.length(1);
- expect(schedule[0]).to.deep.eq(schedule2);
-
- // Wait 2 schedule ends:
- await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD * 2n);
- await helper.balance.claim(recepient);
-
- // check recepient balance after second claim (100 tokens claimed, 0 left):
- balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
- expect(balanceRecepient.free / nominal).to.eq(300n);
- expect(balanceRecepient.frozen).to.eq(0n);
- expect(balanceRecepient.reserved).to.eq(0n);
-
- // check sender balance does not changed:
- balanceSender = await helper.balance.getSubstrateFull(sender.address);
- expect(balanceSender.free / nominal).to.eq(699n);
- expect(balanceSender.frozen).to.eq(0n);
- expect(balanceSender.reserved).to.eq(0n);
- });
-
- itSub('cannot send more tokens than have', async ({helper}) => {
- const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor);
- const schedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 100n * nominal};
- const manyPeriodsSchedule = {start: 0n, period: 1n, periodCount: 100n, perPeriod: 10n * nominal};
- const oneBigSumSchedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 5000n * nominal};
-
- // Sender cannot send vestedTransfer to self or other
- await expect(helper.balance.vestedTransfer(sender, sender.address, manyPeriodsSchedule)).to.be.rejectedWith(/^vesting.InsufficientBalanceToLock$/);
- await expect(helper.balance.vestedTransfer(sender, receiver.address, manyPeriodsSchedule)).to.be.rejectedWith(/^Token: FundsUnavailable$/);
- await expect(helper.balance.vestedTransfer(sender, sender.address, oneBigSumSchedule)).to.be.rejectedWith(/^vesting.InsufficientBalanceToLock$/);
- await expect(helper.balance.vestedTransfer(sender, receiver.address, oneBigSumSchedule)).to.be.rejectedWith(/^Token: FundsUnavailable$/);
-
- const balanceSender = await helper.balance.getSubstrateFull(sender.address);
- const balanceReceiver = await helper.balance.getSubstrateFull(receiver.address);
-
- // Sender's balance has not changed
- expect(balanceSender.free / nominal).to.eq(999n);
- expect(balanceSender.frozen).to.eq(0n);
- expect(balanceSender.reserved).to.eq(0n);
-
- // Receiver's balance has not changed
- expect(balanceReceiver.free).to.be.eq(1n * nominal);
- expect(balanceReceiver.frozen).to.be.eq(0n);
- expect(balanceReceiver.reserved).to.be.eq(0n);
-
- // Receiver cannot send vestedTransfer back because of freeze
- await expect(helper.balance.vestedTransfer(receiver, sender.address, schedule)).to.be.rejectedWith(/^Token: FundsUnavailable$/);
- });
-
- itSub('cannot send vestedTransfer with incorrect parameters', async ({helper}) => {
- const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor);
- const incorrectperiodSchedule = {start: 0n, period: 0n, periodCount: 10n, perPeriod: 10n * nominal};
- const incorrectPeriodCountSchedule = {start: 0n, period: 1n, periodCount: 0n, perPeriod: 10n * nominal};
- const incorrectPerPeriodSchedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 0n * nominal};
-
- await expect(helper.balance.vestedTransfer(sender, sender.address, incorrectperiodSchedule)).to.be.rejectedWith(/vesting.ZeroVestingPeriod/);
- await expect(helper.balance.vestedTransfer(sender, receiver.address, incorrectPeriodCountSchedule)).to.be.rejectedWith(/vesting.ZeroVestingPeriod/);
- await expect(helper.balance.vestedTransfer(sender, receiver.address, incorrectPerPeriodSchedule)).to.be.rejectedWith(/vesting.AmountLow/);
-
- const balanceSender = await helper.balance.getSubstrateFull(sender.address);
- // Sender's balance has not changed
- expect(balanceSender.free / nominal).to.eq(999n);
- expect(balanceSender.frozen).to.eq(0n);
- expect(balanceSender.reserved).to.eq(0n);
- });
-});
js-packages/tests/src/xcm/lowLevelXcmQuartz.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/xcm/lowLevelXcmQuartz.test.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingMoonriverPlaygrounds, usingShidenPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
-import {QUARTZ_CHAIN, QTZ_DECIMALS, SHIDEN_DECIMALS, karuraUrl, moonriverUrl, shidenUrl, SAFE_XCM_VERSION, XcmTestHelper, TRANSFER_AMOUNT, SENDER_BUDGET, relayUrl} from './xcm.types.js';
-import {hexToString} from '@polkadot/util';
-
-const testHelper = new XcmTestHelper('quartz');
-
-describeXCM('[XCMLL] Integration test: Exchanging tokens with Karura', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccount] = await helper.arrange.createAccounts([0n], alice);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- const metadata = {
- name: 'Quartz',
- symbol: 'QTZ',
- decimals: 18,
- minimalBalance: 1000000000000000000n,
- };
-
- const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>
- hexToString(v.toJSON()['symbol'])) as string[];
-
- if(!assets.includes('QTZ')) {
- await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
- } else {
- console.log('QTZ token already registered on Karura assetRegistry pallet');
- }
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
- });
- });
-
- itSub('Should connect and send QTZ to Karura', async () => {
- await testHelper.sendUnqTo('karura', randomAccount);
- });
-
- itSub('Should connect to Karura and send QTZ back', async () => {
- await testHelper.sendUnqBack('karura', alice, randomAccount);
- });
-
- itSub('Karura can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('karura', alice);
- });
-});
-// These tests are relevant only when
-// the the corresponding foreign assets are not registered
-describeXCM('[XCMLL] Integration test: Quartz rejects non-native tokens', () => {
- let alice: IKeyringPair;
-
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
-
-
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
- });
-
- itSub('Quartz rejects KAR tokens from Karura', async () => {
- await testHelper.rejectNativeTokensFrom('karura', alice);
- });
-
- itSub('Quartz rejects MOVR tokens from Moonriver', async () => {
- await testHelper.rejectNativeTokensFrom('moonriver', alice);
- });
-
- itSub('Quartz rejects SDN tokens from Shiden', async () => {
- await testHelper.rejectNativeTokensFrom('shiden', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: Exchanging QTZ with Moonriver', () => {
- // Quartz constants
- let alice: IKeyringPair;
- let quartzAssetLocation;
-
- let randomAccountQuartz: IKeyringPair;
- let randomAccountMoonriver: IKeyringPair;
-
- // Moonriver constants
- let assetId: string;
-
- const quartzAssetMetadata = {
- name: 'xcQuartz',
- symbol: 'xcQTZ',
- decimals: 18,
- isFrozen: false,
- minimalBalance: 1n,
- };
-
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);
-
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const alithAccount = helper.account.alithAccount();
- const baltatharAccount = helper.account.baltatharAccount();
- const dorothyAccount = helper.account.dorothyAccount();
-
- randomAccountMoonriver = helper.account.create();
-
- // >>> Sponsoring Dorothy >>>
- console.log('Sponsoring Dorothy.......');
- await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring Dorothy.......DONE');
- // <<< Sponsoring Dorothy <<<
-
- quartzAssetLocation = {
- XCM: {
- parents: 1,
- interior: {X1: {Parachain: QUARTZ_CHAIN}},
- },
- };
- const existentialDeposit = 1n;
- const isSufficient = true;
- const unitsPerSecond = 1n;
- const numAssetsWeightHint = 0;
- if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {
- console.log('Quartz asset already registered on Moonriver');
- } else {
- const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
- location: quartzAssetLocation,
- metadata: quartzAssetMetadata,
- existentialDeposit,
- isSufficient,
- unitsPerSecond,
- numAssetsWeightHint,
- });
-
- console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-
- await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
- }
- // >>> Acquire Quartz AssetId Info on Moonriver >>>
- console.log('Acquire Quartz AssetId Info on Moonriver.......');
-
- assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();
-
- console.log('QTZ asset ID is %s', assetId);
- console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');
- // >>> Acquire Quartz AssetId Info on Moonriver >>>
-
- // >>> Sponsoring random Account >>>
- console.log('Sponsoring random Account.......');
- await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring random Account.......DONE');
- // <<< Sponsoring random Account <<<
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
- });
- });
-
- itSub('Should connect and send QTZ to Moonriver', async () => {
- await testHelper.sendUnqTo('moonriver', randomAccountQuartz, randomAccountMoonriver);
- });
-
- itSub('Should connect to Moonriver and send QTZ back', async () => {
- await testHelper.sendUnqBack('moonriver', alice, randomAccountQuartz);
- });
-
- itSub('Moonriver can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('moonriver', alice);
- });
-
- itSub('Should not accept reserve transfer of QTZ from Moonriver', async () => {
- await testHelper.rejectReserveTransferUNQfrom('moonriver', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: Exchanging tokens with Shiden', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- const QTZ_ASSET_ID_ON_SHIDEN = 18_446_744_073_709_551_633n; // The value is taken from the live Shiden
- const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; // The value is taken from the live Shiden
-
- // Quartz -> Shiden
- const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden
- const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- randomAccount = helper.arrange.createEmptyAccount();
- await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
- console.log('sender: ', randomAccount.address);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
- console.log('1. Create foreign asset and metadata');
- await helper.getSudo().assets.forceCreate(
- alice,
- QTZ_ASSET_ID_ON_SHIDEN,
- alice.address,
- QTZ_MINIMAL_BALANCE_ON_SHIDEN,
- );
-
- await helper.assets.setMetadata(
- alice,
- QTZ_ASSET_ID_ON_SHIDEN,
- 'Quartz',
- 'QTZ',
- Number(QTZ_DECIMALS),
- );
-
- console.log('2. Register asset location on Shiden');
- const assetLocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
-
- console.log('3. Set QTZ payment for XCM execution on Shiden');
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
- } else {
- console.log('QTZ is already registered on Shiden');
- }
- console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');
- await helper.balance.transferToSubstrate(alice, randomAccount.address, shidenInitialBalance);
- });
- });
-
- itSub('Should connect and send QTZ to Shiden', async () => {
- await testHelper.sendUnqTo('shiden', randomAccount);
- });
-
- itSub('Should connect to Shiden and send QTZ back', async () => {
- await testHelper.sendUnqBack('shiden', alice, randomAccount);
- });
-
- itSub('Shiden can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('shiden', alice);
- });
-
- itSub('Should not accept reserve transfer of QTZ from Shiden', async () => {
- await testHelper.rejectReserveTransferUNQfrom('shiden', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {
- let sudoer: IKeyringPair;
-
- before(async function () {
- await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {
- sudoer = await privateKey('//Alice');
- });
- });
-
- // At the moment there is no reliable way
- // to establish the correspondence between the `ExecutedDownward` event
- // and the relay's sent message due to `SetTopic` instruction
- // containing an unpredictable topic silently added by the relay's messages on the router level.
- // This changes the message hash on arrival to our chain.
- //
- // See:
- // * The relay's router: https://github.com/paritytech/polkadot-sdk/blob/f60318f68687e601c47de5ad5ca88e2c3f8139a7/polkadot/runtime/westend/src/xcm_config.rs#L83
- // * The `WithUniqueTopic` helper: https://github.com/paritytech/polkadot-sdk/blob/945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e/polkadot/xcm/xcm-builder/src/routing.rs#L36
- //
- // Because of this, we insert time gaps between tests so
- // different `ExecutedDownward` events won't interfere with each other.
- afterEach(async () => {
- await usingPlaygrounds(async (helper) => {
- await helper.wait.newBlocks(3);
- });
- });
-
- itSub('The relay can set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');
- });
-
- itSub('The relay can batch set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');
- });
-
- itSub('The relay can batchAll set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');
- });
-
- itSub('The relay can forceBatch set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');
- });
-
- itSub('[negative] The relay cannot set balance', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');
- });
-
- itSub('[negative] The relay cannot set balance via batch', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');
- });
-
- itSub('[negative] The relay cannot set balance via batchAll', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');
- });
-
- itSub('[negative] The relay cannot set balance via forceBatch', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');
- });
-
- itSub('[negative] The relay cannot set balance via dispatchAs', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');
- });
-});
js-packages/tests/src/xcm/lowLevelXcmUnique.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/xcm/lowLevelXcmUnique.test.ts
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import config from '../config.js';
-import {itSub, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
-import {nToBigInt} from '@polkadot/util';
-import {hexToString} from '@polkadot/util';
-import {ASTAR_DECIMALS, SAFE_XCM_VERSION, SENDER_BUDGET, UNIQUE_CHAIN, UNQ_DECIMALS, XcmTestHelper, acalaUrl, astarUrl, moonbeamUrl, polkadexUrl, relayUrl, uniqueAssetId} from './xcm.types.js';
-
-const testHelper = new XcmTestHelper('unique');
-
-
-
-
-describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- console.log(config.acalaUrl);
- randomAccount = helper.arrange.createEmptyAccount();
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- const metadata = {
- name: 'Unique Network',
- symbol: 'UNQ',
- decimals: 18,
- minimalBalance: 1250_000_000_000_000_000n,
- };
- const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>
- hexToString(v.toJSON()['symbol'])) as string[];
-
- if(!assets.includes('UNQ')) {
- await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
- } else {
- console.log('UNQ token already registered on Acala assetRegistry pallet');
- }
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
- });
- });
-
- itSub('Should connect and send UNQ to Acala', async () => {
- await testHelper.sendUnqTo('acala', randomAccount);
- });
-
- itSub('Should connect to Acala and send UNQ back', async () => {
- await testHelper.sendUnqBack('acala', alice, randomAccount);
- });
-
- itSub('Acala can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('acala', alice);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Acala', async () => {
- await testHelper.rejectReserveTransferUNQfrom('acala', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: Exchanging tokens with Polkadex', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- randomAccount = helper.arrange.createEmptyAccount();
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))
- .toJSON() as [])
- .map(nToBigInt).length != 0;
- /*
- Check whether the Unique token has been added
- to the whitelist, since an error will occur
- if it is added again. Needed for debugging
- when this test is run multiple times.
- */
- if(isWhitelisted) {
- console.log('UNQ token is already whitelisted on Polkadex');
- } else {
- await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);
- }
-
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
- });
- });
-
- itSub('Should connect and send UNQ to Polkadex', async () => {
- await testHelper.sendUnqTo('polkadex', randomAccount);
- });
-
-
- itSub('Should connect to Polkadex and send UNQ back', async () => {
- await testHelper.sendUnqBack('polkadex', alice, randomAccount);
- });
-
- itSub('Polkadex can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('polkadex', alice);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Polkadex', async () => {
- await testHelper.rejectReserveTransferUNQfrom('polkadex', alice);
- });
-});
-
-// These tests are relevant only when
-// the the corresponding foreign assets are not registered
-describeXCM('[XCMLL] Integration test: Unique rejects non-native tokens', () => {
- let alice: IKeyringPair;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
- });
-
- itSub('Unique rejects ACA tokens from Acala', async () => {
- await testHelper.rejectNativeTokensFrom('acala', alice);
- });
-
- itSub('Unique rejects GLMR tokens from Moonbeam', async () => {
- await testHelper.rejectNativeTokensFrom('moonbeam', alice);
- });
-
- itSub('Unique rejects ASTR tokens from Astar', async () => {
- await testHelper.rejectNativeTokensFrom('astar', alice);
- });
-
- itSub('Unique rejects PDX tokens from Polkadex', async () => {
- await testHelper.rejectNativeTokensFrom('polkadex', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: Exchanging UNQ with Moonbeam', () => {
- // Unique constants
- let alice: IKeyringPair;
- let uniqueAssetLocation;
-
- let randomAccountUnique: IKeyringPair;
- let randomAccountMoonbeam: IKeyringPair;
-
- // Moonbeam constants
- let assetId: string;
-
- const uniqueAssetMetadata = {
- name: 'xcUnique',
- symbol: 'xcUNQ',
- decimals: 18,
- isFrozen: false,
- minimalBalance: 1n,
- };
-
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);
-
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const alithAccount = helper.account.alithAccount();
- const baltatharAccount = helper.account.baltatharAccount();
- const dorothyAccount = helper.account.dorothyAccount();
-
- randomAccountMoonbeam = helper.account.create();
-
- // >>> Sponsoring Dorothy >>>
- console.log('Sponsoring Dorothy.......');
- await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring Dorothy.......DONE');
- // <<< Sponsoring Dorothy <<<
- uniqueAssetLocation = {
- XCM: {
- parents: 1,
- interior: {X1: {Parachain: UNIQUE_CHAIN}},
- },
- };
- const existentialDeposit = 1n;
- const isSufficient = true;
- const unitsPerSecond = 1n;
- const numAssetsWeightHint = 0;
-
- if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {
- console.log('Unique asset already registered on Moonbeam');
- } else {
- const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
- location: uniqueAssetLocation,
- metadata: uniqueAssetMetadata,
- existentialDeposit,
- isSufficient,
- unitsPerSecond,
- numAssetsWeightHint,
- });
-
- console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-
- await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);
- }
-
- // >>> Acquire Unique AssetId Info on Moonbeam >>>
- console.log('Acquire Unique AssetId Info on Moonbeam.......');
-
- assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();
-
- console.log('UNQ asset ID is %s', assetId);
- console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');
-
- // >>> Sponsoring random Account >>>
- console.log('Sponsoring random Account.......');
- await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring random Account.......DONE');
- // <<< Sponsoring random Account <<<
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);
- });
- });
-
- itSub('Should connect and send UNQ to Moonbeam', async () => {
- await testHelper.sendUnqTo('moonbeam', randomAccountUnique, randomAccountMoonbeam);
- });
-
- itSub('Should connect to Moonbeam and send UNQ back', async () => {
- await testHelper.sendUnqBack('moonbeam', alice, randomAccountUnique);
- });
-
- itSub('Moonbeam can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('moonbeam', alice);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Moonbeam', async () => {
- await testHelper.rejectReserveTransferUNQfrom('moonbeam', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: Exchanging tokens with Astar', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; // The value is taken from the live Astar
- const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; // The value is taken from the live Astar
-
- // Unique -> Astar
- const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.
- const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- randomAccount = helper.arrange.createEmptyAccount();
- await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
- console.log('randomAccount', randomAccount.address);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {
- console.log('1. Create foreign asset and metadata');
- await helper.getSudo().assets.forceCreate(
- alice,
- UNQ_ASSET_ID_ON_ASTAR,
- alice.address,
- UNQ_MINIMAL_BALANCE_ON_ASTAR,
- );
-
- await helper.assets.setMetadata(
- alice,
- UNQ_ASSET_ID_ON_ASTAR,
- 'Unique Network',
- 'UNQ',
- Number(UNQ_DECIMALS),
- );
-
- console.log('2. Register asset location on Astar');
- const assetLocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);
-
- console.log('3. Set UNQ payment for XCM execution on Astar');
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
- } else {
- console.log('UNQ is already registered on Astar');
- }
- console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');
- await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);
- });
- });
-
- itSub('Should connect and send UNQ to Astar', async () => {
- await testHelper.sendUnqTo('astar', randomAccount);
- });
-
- itSub('Should connect to Astar and send UNQ back', async () => {
- await testHelper.sendUnqBack('astar', alice, randomAccount);
- });
-
- itSub('Astar can send only up to its balance', async () => {
- await testHelper.sendOnlyOwnedBalance('astar', alice);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Astar', async () => {
- await testHelper.rejectReserveTransferUNQfrom('astar', alice);
- });
-});
-
-describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {
- let sudoer: IKeyringPair;
-
- before(async function () {
- await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {
- sudoer = await privateKey('//Alice');
- });
- });
-
- // At the moment there is no reliable way
- // to establish the correspondence between the `ExecutedDownward` event
- // and the relay's sent message due to `SetTopic` instruction
- // containing an unpredictable topic silently added by the relay's messages on the router level.
- // This changes the message hash on arrival to our chain.
- //
- // See:
- // * The relay's router: https://github.com/paritytech/polkadot-sdk/blob/f60318f68687e601c47de5ad5ca88e2c3f8139a7/polkadot/runtime/westend/src/xcm_config.rs#L83
- // * The `WithUniqueTopic` helper: https://github.com/paritytech/polkadot-sdk/blob/945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e/polkadot/xcm/xcm-builder/src/routing.rs#L36
- //
- // Because of this, we insert time gaps between tests so
- // different `ExecutedDownward` events won't interfere with each other.
- afterEach(async () => {
- await usingPlaygrounds(async (helper) => {
- await helper.wait.newBlocks(3);
- });
- });
-
- itSub('The relay can set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');
- });
-
- itSub('The relay can batch set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');
- });
-
- itSub('The relay can batchAll set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');
- });
-
- itSub('The relay can forceBatch set storage', async () => {
- await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');
- });
-
- itSub('[negative] The relay cannot set balance', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');
- });
-
- itSub('[negative] The relay cannot set balance via batch', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');
- });
-
- itSub('[negative] The relay cannot set balance via batchAll', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');
- });
-
- itSub('[negative] The relay cannot set balance via forceBatch', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');
- });
-
- itSub('[negative] The relay cannot set balance via dispatchAs', async () => {
- await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');
- });
-});
js-packages/tests/src/xcm/xcm.types.tsdiffbeforeafterboth--- a/js-packages/tests/src/xcm/xcm.types.ts
+++ /dev/null
@@ -1,621 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {hexToString} from '@polkadot/util';
-import {expect, usingAcalaPlaygrounds, usingAstarPlaygrounds, usingKaruraPlaygrounds, usingMoonbeamPlaygrounds, usingMoonriverPlaygrounds, usingPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds, usingShidenPlaygrounds} from '../util/index.js';
-import {DevUniqueHelper, Event} from '@unique/playgrounds/src/unique.dev.js';
-import config from '../config.js';
-
-export const UNIQUE_CHAIN = +(process.env.RELAY_UNIQUE_ID || 2037);
-export const STATEMINT_CHAIN = +(process.env.RELAY_STATEMINT_ID || 1000);
-export const ACALA_CHAIN = +(process.env.RELAY_ACALA_ID || 2000);
-export const MOONBEAM_CHAIN = +(process.env.RELAY_MOONBEAM_ID || 2004);
-export const ASTAR_CHAIN = +(process.env.RELAY_ASTAR_ID || 2006);
-export const POLKADEX_CHAIN = +(process.env.RELAY_POLKADEX_ID || 2040);
-
-export const QUARTZ_CHAIN = +(process.env.RELAY_QUARTZ_ID || 2095);
-export const STATEMINE_CHAIN = +(process.env.RELAY_STATEMINE_ID || 1000);
-export const KARURA_CHAIN = +(process.env.RELAY_KARURA_ID || 2000);
-export const MOONRIVER_CHAIN = +(process.env.RELAY_MOONRIVER_ID || 2023);
-export const SHIDEN_CHAIN = +(process.env.RELAY_SHIDEN_ID || 2007);
-
-export const relayUrl = config.relayUrl;
-export const statemintUrl = config.statemintUrl;
-export const statemineUrl = config.statemineUrl;
-
-export const acalaUrl = config.acalaUrl;
-export const moonbeamUrl = config.moonbeamUrl;
-export const astarUrl = config.astarUrl;
-export const polkadexUrl = config.polkadexUrl;
-
-export const karuraUrl = config.karuraUrl;
-export const moonriverUrl = config.moonriverUrl;
-export const shidenUrl = config.shidenUrl;
-
-export const SAFE_XCM_VERSION = 3;
-
-
-export const RELAY_DECIMALS = 12;
-export const STATEMINE_DECIMALS = 12;
-export const KARURA_DECIMALS = 12;
-export const SHIDEN_DECIMALS = 18n;
-export const QTZ_DECIMALS = 18n;
-
-export const ASTAR_DECIMALS = 18n;
-export const UNQ_DECIMALS = 18n;
-
-export const maxWaitBlocks = 6;
-
-export const uniqueMultilocation = {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
-};
-export const uniqueVersionedMultilocation = {
- V3: uniqueMultilocation,
-};
-
-export const uniqueAssetId = {
- Concrete: uniqueMultilocation,
-};
-
-export const expectFailedToTransact = async (helper: DevUniqueHelper, messageSent: any) => {
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-};
-export const expectUntrustedReserveLocationFail = async (helper: DevUniqueHelper, messageSent: any) => {
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-};
-
-export const expectDownwardXcmNoPermission = async (helper: DevUniqueHelper) => {
- // The correct messageHash for downward messages can't be reliably obtained
- await helper.wait.expectEvent(maxWaitBlocks, Event.DmpQueue.ExecutedDownward, event => event.outcome.asIncomplete[1].isNoPermission);
-};
-
-export const expectDownwardXcmComplete = async (helper: DevUniqueHelper) => {
- // The correct messageHash for downward messages can't be reliably obtained
- await helper.wait.expectEvent(maxWaitBlocks, Event.DmpQueue.ExecutedDownward, event => event.outcome.isComplete);
-};
-
-export const NETWORKS = {
- acala: usingAcalaPlaygrounds,
- astar: usingAstarPlaygrounds,
- polkadex: usingPolkadexPlaygrounds,
- moonbeam: usingMoonbeamPlaygrounds,
- moonriver: usingMoonriverPlaygrounds,
- karura: usingKaruraPlaygrounds,
- shiden: usingShidenPlaygrounds,
-} as const;
-type NetworkNames = keyof typeof NETWORKS;
-
-type NativeRuntime = 'opal' | 'quartz' | 'unique';
-
-export function mapToChainId(networkName: keyof typeof NETWORKS): number {
- switch (networkName) {
- case 'acala':
- return ACALA_CHAIN;
- case 'astar':
- return ASTAR_CHAIN;
- case 'moonbeam':
- return MOONBEAM_CHAIN;
- case 'polkadex':
- return POLKADEX_CHAIN;
- case 'moonriver':
- return MOONRIVER_CHAIN;
- case 'karura':
- return KARURA_CHAIN;
- case 'shiden':
- return SHIDEN_CHAIN;
- }
-}
-
-export function mapToChainUrl(networkName: NetworkNames): string {
- switch (networkName) {
- case 'acala':
- return acalaUrl;
- case 'astar':
- return astarUrl;
- case 'moonbeam':
- return moonbeamUrl;
- case 'polkadex':
- return polkadexUrl;
- case 'moonriver':
- return moonriverUrl;
- case 'karura':
- return karuraUrl;
- case 'shiden':
- return shidenUrl;
- }
-}
-
-export function getDevPlayground(name: NetworkNames) {
- return NETWORKS[name];
-}
-
-export const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;
-export const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;
-export const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;
-export const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;
-export const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;
-
-export class XcmTestHelper {
- private _balanceUniqueTokenInit: bigint = 0n;
- private _balanceUniqueTokenMiddle: bigint = 0n;
- private _balanceUniqueTokenFinal: bigint = 0n;
- private _unqFees: bigint = 0n;
- private _nativeRuntime: NativeRuntime;
-
- constructor(runtime: NativeRuntime) {
- this._nativeRuntime = runtime;
- }
-
- private _getNativeId() {
- switch (this._nativeRuntime) {
- case 'opal':
- // To-Do
- return 1001;
- case 'quartz':
- return QUARTZ_CHAIN;
- case 'unique':
- return UNIQUE_CHAIN;
- }
- }
-
- private _isAddress20FormatFor(network: NetworkNames) {
- switch (network) {
- case 'moonbeam':
- case 'moonriver':
- return true;
- default:
- return false;
- }
- }
-
- private _runtimeVersionedMultilocation() {
- return {
- V3: {
- parents: 1,
- interior: {
- X1: {
- Parachain: this._getNativeId(),
- },
- },
- },
- };
- }
-
- private _uniqueChainMultilocationForRelay() {
- return {
- V3: {
- parents: 0,
- interior: {
- X1: {Parachain: this._getNativeId()},
- },
- },
- };
- }
-
- async sendUnqTo(
- networkName: keyof typeof NETWORKS,
- randomAccount: IKeyringPair,
- randomAccountOnTargetChain = randomAccount,
- ) {
- const networkUrl = mapToChainUrl(networkName);
- const targetPlayground = getDevPlayground(networkName);
- await usingPlaygrounds(async (helper) => {
- this._balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: mapToChainId(networkName),
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: (
- this._isAddress20FormatFor(networkName) ?
- {
- AccountKey20: {
- network: 'Any',
- key: randomAccountOnTargetChain.address,
- },
- }
- :
- {
- AccountId32: {
- network: 'Any',
- id: randomAccountOnTargetChain.addressRaw,
- },
- }
- ),
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- this._balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
- this._unqFees = this._balanceUniqueTokenInit - this._balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
- console.log('[%s -> %s] transaction fees: %s', this._nativeRuntime, networkName, helper.util.bigIntToDecimals(this._unqFees));
- expect(this._unqFees > 0n, 'Negative fees, looks like nothing was transferred').to.be.true;
-
- await targetPlayground(networkUrl, async (helper) => {
- /*
- Since only the parachain part of the Polkadex
- infrastructure is launched (without their
- solochain validators), processing incoming
- assets will lead to an error.
- This error indicates that the Polkadex chain
- received a message from the Unique network,
- since the hash is being checked to ensure
- it matches what was sent.
- */
- if(networkName == 'polkadex') {
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);
- } else {
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == messageSent.messageHash);
- }
- });
-
- });
- }
-
- async sendUnqBack(
- networkName: keyof typeof NETWORKS,
- sudoer: IKeyringPair,
- randomAccountOnUnq: IKeyringPair,
- ) {
- const networkUrl = mapToChainUrl(networkName);
-
- const targetPlayground = getDevPlayground(networkName);
- await usingPlaygrounds(async (helper) => {
-
- const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- randomAccountOnUnq.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {Parachain: this._getNativeId()},
- },
- },
- },
- SENDBACK_AMOUNT,
- );
-
- let xcmProgramSent: any;
-
-
- await targetPlayground(networkUrl, async (helper) => {
- if('getSudo' in helper) {
- await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), xcmProgram);
- xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- } else if('fastDemocracy' in helper) {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), xcmProgram]);
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
- xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);
-
- this._balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountOnUnq.address);
-
- expect(this._balanceUniqueTokenFinal).to.be.equal(this._balanceUniqueTokenInit - this._unqFees - STAYED_ON_TARGET_CHAIN);
-
- });
- }
-
- async sendOnlyOwnedBalance(
- networkName: keyof typeof NETWORKS,
- sudoer: IKeyringPair,
- ) {
- const networkUrl = mapToChainUrl(networkName);
- const targetPlayground = getDevPlayground(networkName);
-
- const targetChainBalance = 10000n * (10n ** UNQ_DECIMALS);
-
- await usingPlaygrounds(async (helper) => {
- const targetChainSovereignAccount = helper.address.paraSiblingSovereignAccount(mapToChainId(networkName));
- await helper.getSudo().balance.setBalanceSubstrate(sudoer, targetChainSovereignAccount, targetChainBalance);
- const moreThanTargetChainHas = 2n * targetChainBalance;
-
- const targetAccount = helper.arrange.createEmptyAccount();
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanTargetChainHas,
- );
-
- let maliciousXcmProgramSent: any;
-
-
- await targetPlayground(networkUrl, async (helper) => {
- if('getSudo' in helper) {
- await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgram);
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- } else if('fastDemocracy' in helper) {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgram]);
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- });
-
- await expectFailedToTransact(helper, maliciousXcmProgramSent);
-
- const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
- });
- }
-
- async rejectReserveTransferUNQfrom(networkName: keyof typeof NETWORKS, sudoer: IKeyringPair) {
- const networkUrl = mapToChainUrl(networkName);
- const targetPlayground = getDevPlayground(networkName);
-
- await usingPlaygrounds(async (helper) => {
- const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
- const targetAccount = helper.arrange.createEmptyAccount();
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: this._getNativeId(),
- },
- },
- },
- },
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique using full UNQ identification
- await targetPlayground(networkUrl, async (helper) => {
- if('getSudo' in helper) {
- await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId);
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- // Moonbeam case
- else if('fastDemocracy' in helper) {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId]);
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal(`${networkName} try to act like a reserve location for UNQ using path asset identification`,batchCall);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- });
-
-
- await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Unique using shortened UNQ identification
- await targetPlayground(networkUrl, async (helper) => {
- if('getSudo' in helper) {
- await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgramHereId);
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- else if('fastDemocracy' in helper) {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramHereId]);
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal(`${networkName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- });
-
- await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
- }
-
- async rejectNativeTokensFrom(networkName: keyof typeof NETWORKS, sudoerOnTargetChain: IKeyringPair) {
- const networkUrl = mapToChainUrl(networkName);
- const targetPlayground = getDevPlayground(networkName);
- let messageSent: any;
-
- await usingPlaygrounds(async (helper) => {
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- helper.arrange.createEmptyAccount().addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: mapToChainId(networkName),
- },
- },
- },
- },
- TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT,
- );
- await targetPlayground(networkUrl, async (helper) => {
- if('getSudo' in helper) {
- await helper.getSudo().xcm.send(sudoerOnTargetChain, this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId);
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- } else if('fastDemocracy' in helper) {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId]);
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal(`${networkName} sending native tokens to the Unique via fast democracy`, batchCall);
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- }
- });
- await expectFailedToTransact(helper, messageSent);
- });
- }
-
- private async _relayXcmTransactSetStorage(variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch') {
- // eslint-disable-next-line require-await
- return await usingPlaygrounds(async (helper) => {
- const relayForceKV = () => {
- const random = Math.random();
- const key = `relay-forced-key (instance: ${random})`;
- const val = `relay-forced-value (instance: ${random})`;
- const call = helper.constructApiCall('api.tx.system.setStorage', [[[key, val]]]).method.toHex();
-
- return {
- call,
- key,
- val,
- };
- };
-
- if(variant == 'plain') {
- const kv = relayForceKV();
- return {
- program: helper.arrange.makeUnpaidSudoTransactProgram({
- weightMultiplier: 1,
- call: kv.call,
- }),
- kvs: [kv],
- };
- } else {
- const kv0 = relayForceKV();
- const kv1 = relayForceKV();
-
- const batchCall = helper.constructApiCall(`api.tx.utility.${variant}`, [[kv0.call, kv1.call]]).method.toHex();
- return {
- program: helper.arrange.makeUnpaidSudoTransactProgram({
- weightMultiplier: 2,
- call: batchCall,
- }),
- kvs: [kv0, kv1],
- };
- }
- });
- }
-
- async relayIsPermittedToSetStorage(relaySudoer: IKeyringPair, variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch') {
- const {program, kvs} = await this._relayXcmTransactSetStorage(variant);
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- await helper.getSudo().executeExtrinsic(relaySudoer, 'api.tx.xcmPallet.send', [
- this._uniqueChainMultilocationForRelay(),
- program,
- ]);
- });
-
- await usingPlaygrounds(async (helper) => {
- await expectDownwardXcmComplete(helper);
-
- for(const kv of kvs) {
- const forcedValue = await helper.callRpc('api.rpc.state.getStorage', [kv.key]);
- expect(hexToString(forcedValue.toHex())).to.be.equal(kv.val);
- }
- });
- }
-
- private async _relayXcmTransactSetBalance(variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch' | 'dispatchAs') {
- // eslint-disable-next-line require-await
- return await usingPlaygrounds(async (helper) => {
- const emptyAccount = helper.arrange.createEmptyAccount().address;
-
- const forceSetBalanceCall = helper.constructApiCall('api.tx.balances.forceSetBalance', [emptyAccount, 10_000n]).method.toHex();
-
- let call;
-
- if(variant == 'plain') {
- call = forceSetBalanceCall;
-
- } else if(variant == 'dispatchAs') {
- call = helper.constructApiCall('api.tx.utility.dispatchAs', [
- {
- system: 'Root',
- },
- forceSetBalanceCall,
- ]).method.toHex();
- } else {
- call = helper.constructApiCall(`api.tx.utility.${variant}`, [[forceSetBalanceCall]]).method.toHex();
- }
-
- return {
- program: helper.arrange.makeUnpaidSudoTransactProgram({
- weightMultiplier: 1,
- call,
- }),
- emptyAccount,
- };
- });
- }
-
- async relayIsNotPermittedToSetBalance(
- relaySudoer: IKeyringPair,
- variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch' | 'dispatchAs',
- ) {
- const {program, emptyAccount} = await this._relayXcmTransactSetBalance(variant);
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- await helper.getSudo().executeExtrinsic(relaySudoer, 'api.tx.xcmPallet.send', [
- this._uniqueChainMultilocationForRelay(),
- program,
- ]);
- });
-
- await usingPlaygrounds(async (helper) => {
- await expectDownwardXcmNoPermission(helper);
- expect(await helper.balance.getSubstrate(emptyAccount)).to.be.equal(0n);
- });
- }
-}
js-packages/tests/src/xcm/xcmOpal.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/xcm/xcmOpal.test.ts
+++ /dev/null
@@ -1,409 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import config from '../config.js';
-import {itSub, expect, describeXCM, usingPlaygrounds, usingWestmintPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
-
-const STATEMINE_CHAIN = +(process.env.RELAY_WESTMINT_ID || 1000);
-const UNIQUE_CHAIN = +(process.env.RELAY_OPAL_ID || 2095);
-
-const relayUrl = config.relayUrl;
-const westmintUrl = config.westmintUrl;
-
-const STATEMINE_PALLET_INSTANCE = 50;
-const ASSET_ID = 100;
-const ASSET_METADATA_DECIMALS = 18;
-const ASSET_METADATA_NAME = 'USDT';
-const ASSET_METADATA_DESCRIPTION = 'USDT';
-const ASSET_METADATA_MINIMAL_BALANCE = 1n;
-
-const RELAY_DECIMALS = 12;
-const WESTMINT_DECIMALS = 12;
-
-const TRANSFER_AMOUNT = 1_000_000_000_000_000_000n;
-
-// 10,000.00 (ten thousands) USDT
-const ASSET_AMOUNT = 1_000_000_000_000_000_000_000n;
-
-describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- let balanceStmnBefore: bigint;
- let balanceStmnAfter: bigint;
-
- let balanceOpalBefore: bigint;
- let balanceOpalAfter: bigint;
- let balanceOpalFinal: bigint;
-
- let balanceBobBefore: bigint;
- let balanceBobAfter: bigint;
- let balanceBobFinal: bigint;
-
- let balanceBobRelayTokenBefore: bigint;
- let balanceBobRelayTokenAfter: bigint;
-
-
- before(async () => {
- await usingPlaygrounds(async (_helper, privateKey) => {
- alice = await privateKey('//Alice');
- bob = await privateKey('//Bob'); // funds donor
- });
-
- await usingWestmintPlaygrounds(westmintUrl, async (helper) => {
- // 350.00 (three hundred fifty) DOT
- const fundingAmount = 3_500_000_000_000n;
-
- await helper.assets.create(alice, ASSET_ID, alice.address, ASSET_METADATA_MINIMAL_BALANCE);
- await helper.assets.setMetadata(alice, ASSET_ID, ASSET_METADATA_NAME, ASSET_METADATA_DESCRIPTION, ASSET_METADATA_DECIMALS);
- await helper.assets.mint(alice, ASSET_ID, alice.address, ASSET_AMOUNT);
-
- // funding parachain sovereing account (Parachain: 2095)
- const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);
- await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, fundingAmount);
- });
-
-
- await usingPlaygrounds(async (helper) => {
- const location = {
- V2: {
- parents: 1,
- interior: {X3: [
- {
- Parachain: STATEMINE_CHAIN,
- },
- {
- PalletInstance: STATEMINE_PALLET_INSTANCE,
- },
- {
- GeneralIndex: ASSET_ID,
- },
- ]},
- },
- };
-
- const metadata =
- {
- name: ASSET_ID,
- symbol: ASSET_METADATA_NAME,
- decimals: ASSET_METADATA_DECIMALS,
- minimalBalance: ASSET_METADATA_MINIMAL_BALANCE,
- };
- await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
- balanceOpalBefore = await helper.balance.getSubstrate(alice.address);
- });
-
-
- // Providing the relay currency to the unique sender account
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 0,
- interior: {X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: 50_000_000_000_000_000n,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- });
-
- });
-
- itSub('Should connect and send USDT from Westmint to Opal', async ({helper}) => {
- await usingWestmintPlaygrounds(westmintUrl, async (helper) => {
- const dest = {
- V2: {
- parents: 1,
- interior: {X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: {
- X2: [
- {
- PalletInstance: STATEMINE_PALLET_INSTANCE,
- },
- {
- GeneralIndex: ASSET_ID,
- },
- ]},
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
- await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
-
- balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
-
- // common good parachain take commission in it native token
- console.log(
- '[Westmint -> Opal] transaction fees on Westmint: %s WND',
- helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, WESTMINT_DECIMALS),
- );
- expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
-
- });
-
-
- // ensure that asset has been delivered
- await helper.wait.newBlocks(3);
-
- // expext collection id will be with id 1
- const free = await helper.ft.getBalance(1, {Substrate: alice.address});
-
- balanceOpalAfter = await helper.balance.getSubstrate(alice.address);
-
- console.log(
- '[Westmint -> Opal] transaction fees on Opal: %s USDT',
- helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, ASSET_METADATA_DECIMALS),
- );
- console.log(
- '[Westmint -> Opal] transaction fees on Opal: %s OPL',
- helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore),
- );
-
- // commission has not paid in USDT token
- expect(free == TRANSFER_AMOUNT).to.be.true;
- // ... and parachain native token
- expect(balanceOpalAfter == balanceOpalBefore).to.be.true;
- });
-
- itSub('Should connect and send USDT from Unique to Statemine back', async ({helper}) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {X2: [
- {
- Parachain: STATEMINE_CHAIN,
- },
- {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- },
- ]},
- },
- };
-
- const currencies: [any, bigint][] = [
- [
- {
- ForeignAssetId: 0,
- },
- //10_000_000_000_000_000n,
- TRANSFER_AMOUNT,
- ],
- [
- {
- NativeAssetId: 'Parent',
- },
- 400_000_000_000_000n,
- ],
- ];
-
- const feeItem = 1;
-
- await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
-
- // the commission has been paid in parachain native token
- balanceOpalFinal = await helper.balance.getSubstrate(alice.address);
- expect(balanceOpalAfter > balanceOpalFinal).to.be.true;
-
- await usingWestmintPlaygrounds(westmintUrl, async (helper) => {
- await helper.wait.newBlocks(3);
-
- // The USDT token never paid fees. Its amount not changed from begin value.
- // Also check that xcm transfer has been succeeded
- expect((await helper.assets.account(ASSET_ID, alice.address))! == ASSET_AMOUNT).to.be.true;
- });
- });
-
- itSub('Should connect and send Relay token to Unique', async ({helper}) => {
- const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
-
- balanceBobBefore = await helper.balance.getSubstrate(bob.address);
- balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
-
- // Providing the relay currency to the unique sender account
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 0,
- interior: {X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: bob.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT_RELAY,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- });
-
- await helper.wait.newBlocks(3);
-
- balanceBobAfter = await helper.balance.getSubstrate(bob.address);
- balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
-
- const wndFee = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
- console.log(
- 'Relay (Westend) to Opal transaction fees: %s OPL',
- helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
- );
- console.log(
- 'Relay (Westend) to Opal transaction fees: %s WND',
- helper.util.bigIntToDecimals(wndFee, WESTMINT_DECIMALS),
- );
- expect(balanceBobBefore == balanceBobAfter).to.be.true;
- expect(balanceBobRelayTokenBefore < balanceBobRelayTokenAfter).to.be.true;
- });
-
- itSub('Should connect and send Relay token back', async ({helper}) => {
- let relayTokenBalanceBefore: bigint;
- let relayTokenBalanceAfter: bigint;
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
- });
-
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1:{
- AccountId32: {
- network: 'Any',
- id: bob.addressRaw,
- },
- },
- },
- },
- };
-
- const currencies: any = [
- [
- {
- NativeAssetId: 'Parent',
- },
- 50_000_000_000_000_000n,
- ],
- ];
-
- const feeItem = 0;
-
- await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
-
- balanceBobFinal = await helper.balance.getSubstrate(bob.address);
- console.log('[Opal -> Relay (Westend)] transaction fees: %s OPL', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- await helper.wait.newBlocks(10);
- relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
- console.log('[Opal -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
- expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
- });
- });
-});
js-packages/tests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/xcm/xcmQuartz.test.ts
+++ /dev/null
@@ -1,1636 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util/index.js';
-import {DevUniqueHelper, Event} from '@unique/playgrounds/src/unique.dev.js';
-import {STATEMINE_CHAIN, QUARTZ_CHAIN, KARURA_CHAIN, MOONRIVER_CHAIN, SHIDEN_CHAIN, STATEMINE_DECIMALS, KARURA_DECIMALS, QTZ_DECIMALS, RELAY_DECIMALS, SHIDEN_DECIMALS, karuraUrl, moonriverUrl, relayUrl, shidenUrl, statemineUrl} from './xcm.types.js';
-import {hexToString} from '@polkadot/util';
-
-
-
-const STATEMINE_PALLET_INSTANCE = 50;
-
-const TRANSFER_AMOUNT = 2000000000000000000000000n;
-
-const FUNDING_AMOUNT = 3_500_000_0000_000_000n;
-
-const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
-
-const USDT_ASSET_ID = 100;
-const USDT_ASSET_METADATA_DECIMALS = 18;
-const USDT_ASSET_METADATA_NAME = 'USDT';
-const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';
-const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
-const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
-
-const SAFE_XCM_VERSION = 2;
-
-describeXCM('[XCM] Integration test: Exchanging USDT with Statemine', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- let balanceStmnBefore: bigint;
- let balanceStmnAfter: bigint;
-
- let balanceQuartzBefore: bigint;
- let balanceQuartzAfter: bigint;
- let balanceQuartzFinal: bigint;
-
- let balanceBobBefore: bigint;
- let balanceBobAfter: bigint;
- let balanceBobFinal: bigint;
-
- let balanceBobRelayTokenBefore: bigint;
- let balanceBobRelayTokenAfter: bigint;
-
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- bob = await privateKey('//Bob'); // sovereign account on Statemine(t) funds donor
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- // Fund accounts on Statemine(t)
- await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, alice.addressRaw, FUNDING_AMOUNT);
- await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, bob.addressRaw, FUNDING_AMOUNT);
- });
-
- await usingStateminePlaygrounds(statemineUrl, async (helper) => {
- const sovereignFundingAmount = 3_500_000_000n;
-
- await helper.assets.create(
- alice,
- USDT_ASSET_ID,
- alice.address,
- USDT_ASSET_METADATA_MINIMAL_BALANCE,
- );
- await helper.assets.setMetadata(
- alice,
- USDT_ASSET_ID,
- USDT_ASSET_METADATA_NAME,
- USDT_ASSET_METADATA_DESCRIPTION,
- USDT_ASSET_METADATA_DECIMALS,
- );
- await helper.assets.mint(
- alice,
- USDT_ASSET_ID,
- alice.address,
- USDT_ASSET_AMOUNT,
- );
-
- // funding parachain sovereing account on Statemine(t).
- // The sovereign account should be created before any action
- // (the assets pallet on Statemine(t) check if the sovereign account exists)
- const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(QUARTZ_CHAIN);
- await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);
- });
-
-
- await usingPlaygrounds(async (helper) => {
- const location = {
- V2: {
- parents: 1,
- interior: {X3: [
- {
- Parachain: STATEMINE_CHAIN,
- },
- {
- PalletInstance: STATEMINE_PALLET_INSTANCE,
- },
- {
- GeneralIndex: USDT_ASSET_ID,
- },
- ]},
- },
- };
-
- const metadata =
- {
- name: USDT_ASSET_ID,
- symbol: USDT_ASSET_METADATA_NAME,
- decimals: USDT_ASSET_METADATA_DECIMALS,
- minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,
- };
- await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
- balanceQuartzBefore = await helper.balance.getSubstrate(alice.address);
- });
-
-
- // Providing the relay currency to the quartz sender account
- // (fee for USDT XCM are paid in relay tokens)
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 0,
- interior: {X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT_RELAY,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- });
-
- });
-
- itSub('Should connect and send USDT from Statemine to Quartz', async ({helper}) => {
- await usingStateminePlaygrounds(statemineUrl, async (helper) => {
- const dest = {
- V2: {
- parents: 1,
- interior: {X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: {
- X2: [
- {
- PalletInstance: STATEMINE_PALLET_INSTANCE,
- },
- {
- GeneralIndex: USDT_ASSET_ID,
- },
- ]},
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
- await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
-
- balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
-
- // common good parachain take commission in it native token
- console.log(
- '[Statemine -> Quartz] transaction fees on Statemine: %s WND',
- helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINE_DECIMALS),
- );
- expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
-
- });
-
-
- // ensure that asset has been delivered
- await helper.wait.newBlocks(3);
-
- // expext collection id will be with id 1
- const free = await helper.ft.getBalance(1, {Substrate: alice.address});
-
- balanceQuartzAfter = await helper.balance.getSubstrate(alice.address);
-
- console.log(
- '[Statemine -> Quartz] transaction fees on Quartz: %s USDT',
- helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),
- );
- console.log(
- '[Statemine -> Quartz] transaction fees on Quartz: %s QTZ',
- helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzBefore),
- );
- // commission has not paid in USDT token
- expect(free).to.be.equal(TRANSFER_AMOUNT);
- // ... and parachain native token
- expect(balanceQuartzAfter == balanceQuartzBefore).to.be.true;
- });
-
- itSub('Should connect and send USDT from Quartz to Statemine back', async ({helper}) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {X2: [
- {
- Parachain: STATEMINE_CHAIN,
- },
- {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- },
- ]},
- },
- };
-
- const relayFee = 400_000_000_000_000n;
- const currencies: [any, bigint][] = [
- [
- {
- ForeignAssetId: 0,
- },
- TRANSFER_AMOUNT,
- ],
- [
- {
- NativeAssetId: 'Parent',
- },
- relayFee,
- ],
- ];
-
- const feeItem = 1;
-
- await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
-
- // the commission has been paid in parachain native token
- balanceQuartzFinal = await helper.balance.getSubstrate(alice.address);
- console.log('[Quartz -> Statemine] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzFinal));
- expect(balanceQuartzAfter > balanceQuartzFinal).to.be.true;
-
- await usingStateminePlaygrounds(statemineUrl, async (helper) => {
- await helper.wait.newBlocks(3);
-
- // The USDT token never paid fees. Its amount not changed from begin value.
- // Also check that xcm transfer has been succeeded
- expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
- });
- });
-
- itSub('Should connect and send Relay token to Quartz', async ({helper}) => {
- balanceBobBefore = await helper.balance.getSubstrate(bob.address);
- balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 0,
- interior: {X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: bob.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT_RELAY,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- });
-
- await helper.wait.newBlocks(3);
-
- balanceBobAfter = await helper.balance.getSubstrate(bob.address);
- balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
-
- const wndFeeOnQuartz = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
- const wndDiffOnQuartz = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;
- console.log(
- '[Relay (Westend) -> Quartz] transaction fees: %s QTZ',
- helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
- );
- console.log(
- '[Relay (Westend) -> Quartz] transaction fees: %s WND',
- helper.util.bigIntToDecimals(wndFeeOnQuartz, STATEMINE_DECIMALS),
- );
- console.log('[Relay (Westend) -> Quartz] actually delivered: %s WND', wndDiffOnQuartz);
- expect(wndFeeOnQuartz == 0n, 'No incoming WND fees should be taken').to.be.true;
- expect(balanceBobBefore == balanceBobAfter, 'No incoming QTZ fees should be taken').to.be.true;
- });
-
- itSub('Should connect and send Relay token back', async ({helper}) => {
- let relayTokenBalanceBefore: bigint;
- let relayTokenBalanceAfter: bigint;
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
- });
-
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1:{
- AccountId32: {
- network: 'Any',
- id: bob.addressRaw,
- },
- },
- },
- },
- };
-
- const currencies: any = [
- [
- {
- NativeAssetId: 'Parent',
- },
- TRANSFER_AMOUNT_RELAY,
- ],
- ];
-
- const feeItem = 0;
-
- await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
-
- balanceBobFinal = await helper.balance.getSubstrate(bob.address);
- console.log('[Quartz -> Relay (Westend)] transaction fees: %s QTZ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- await helper.wait.newBlocks(10);
- relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
- console.log('[Quartz -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
- expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
- });
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- let balanceQuartzTokenInit: bigint;
- let balanceQuartzTokenMiddle: bigint;
- let balanceQuartzTokenFinal: bigint;
- let balanceKaruraTokenInit: bigint;
- let balanceKaruraTokenMiddle: bigint;
- let balanceKaruraTokenFinal: bigint;
- let balanceQuartzForeignTokenInit: bigint;
- let balanceQuartzForeignTokenMiddle: bigint;
- let balanceQuartzForeignTokenFinal: bigint;
-
- // computed by a test transfer from prod Quartz to prod Karura.
- // 2 QTZ sent https://quartz.subscan.io/xcm_message/kusama-f60d821b049f8835a3005ce7102285006f5b61e9
- // 1.919176000000000000 QTZ received (you can check Karura's chain state in the corresponding block)
- const expectedKaruraIncomeFee = 2000000000000000000n - 1919176000000000000n;
- const karuraEps = 8n * 10n ** 16n;
-
- let karuraBackwardTransferAmount: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccount] = await helper.arrange.createAccounts([0n], alice);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- const metadata = {
- name: 'Quartz',
- symbol: 'QTZ',
- decimals: 18,
- minimalBalance: 1000000000000000000n,
- };
-
- const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>
- hexToString(v.toJSON()['symbol'])) as string[];
-
- if(!assets.includes('QTZ')) {
- await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
- } else {
- console.log('QTZ token already registered on Karura assetRegistry pallet');
- }
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
- balanceKaruraTokenInit = await helper.balance.getSubstrate(randomAccount.address);
- balanceQuartzForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
- balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccount.address);
- });
- });
-
- itSub('Should connect and send QTZ to Karura', async ({helper}) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: KARURA_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
- const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
- expect(qtzFees > 0n, 'Negative fees QTZ, looks like nothing was transferred').to.be.true;
- console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
-
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- await helper.wait.newBlocks(3);
-
- balanceQuartzForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
- balanceKaruraTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
- const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;
- const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;
- karuraBackwardTransferAmount = qtzIncomeTransfer;
-
- const karUnqFees = TRANSFER_AMOUNT - qtzIncomeTransfer;
-
- console.log(
- '[Quartz -> Karura] transaction fees on Karura: %s KAR',
- helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),
- );
- console.log(
- '[Quartz -> Karura] transaction fees on Karura: %s QTZ',
- helper.util.bigIntToDecimals(karUnqFees),
- );
- console.log('[Quartz -> Karura] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));
- expect(karFees == 0n).to.be.true;
-
- const bigintAbs = (n: bigint) => (n < 0n) ? -n : n;
-
- expect(
- bigintAbs(karUnqFees - expectedKaruraIncomeFee) < karuraEps,
- 'Karura took different income fee, check the Karura foreign asset config',
- ).to.be.true;
- });
- });
-
- itSub('Should connect to Karura and send QTZ back', async ({helper}) => {
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X2: [
- {Parachain: QUARTZ_CHAIN},
- {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- ],
- },
- },
- };
-
- const id = {
- ForeignAsset: 0,
- };
-
- await helper.xTokens.transfer(randomAccount, id, karuraBackwardTransferAmount, destination, 'Unlimited');
- balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
- balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);
-
- const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;
- const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;
-
- console.log(
- '[Karura -> Quartz] transaction fees on Karura: %s KAR',
- helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),
- );
- console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));
-
- expect(karFees > 0, 'Negative fees KAR, looks like nothing was transferred').to.be.true;
- expect(qtzOutcomeTransfer == karuraBackwardTransferAmount).to.be.true;
- });
-
- await helper.wait.newBlocks(3);
-
- balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
- const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;
- expect(actuallyDelivered > 0).to.be.true;
-
- console.log('[Karura -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));
-
- const qtzFees = karuraBackwardTransferAmount - actuallyDelivered;
- console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
- expect(qtzFees == 0n).to.be.true;
- });
-
- itSub('Karura can send only up to its balance', async ({helper}) => {
- // set Karura's sovereign account's balance
- const karuraBalance = 10000n * (10n ** QTZ_DECIMALS);
- const karuraSovereignAccount = helper.address.paraSiblingSovereignAccount(KARURA_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, karuraSovereignAccount, karuraBalance);
-
- const moreThanKaruraHas = karuraBalance * 2n;
-
- let targetAccountBalance = 0n;
- const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
-
- const quartzMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {Parachain: QUARTZ_CHAIN},
- },
- },
- };
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanKaruraHas,
- );
-
- let maliciousXcmProgramSent: any;
- const maxWaitBlocks = 5;
-
- // Try to trick Quartz
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
-
- // But Karura still can send the correct amount
- const validTransferAmount = karuraBalance / 2n;
- const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- validTransferAmount,
- );
-
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, validXcmProgram);
- });
-
- await helper.wait.newBlocks(maxWaitBlocks);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(validTransferAmount);
- });
-
- itSub('Should not accept reserve transfer of QTZ from Karura', async ({helper}) => {
- const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
- const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
-
- const quartzMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- },
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Quartz using full QTZ identification
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Quartz using shortened QTZ identification
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
-
-// These tests are relevant only when
-// the the corresponding foreign assets are not registered
-describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => {
- let alice: IKeyringPair;
- let alith: IKeyringPair;
-
- const testAmount = 100_000_000_000n;
- let quartzParachainJunction;
- let quartzAccountJunction;
-
- let quartzParachainMultilocation: any;
- let quartzAccountMultilocation: any;
- let quartzCombinedMultilocation: any;
-
- let messageSent: any;
-
- const maxWaitBlocks = 3;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
-
- quartzParachainJunction = {Parachain: QUARTZ_CHAIN};
- quartzAccountJunction = {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- };
-
- quartzParachainMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: quartzParachainJunction,
- },
- },
- };
-
- quartzAccountMultilocation = {
- V2: {
- parents: 0,
- interior: {
- X1: quartzAccountJunction,
- },
- },
- };
-
- quartzCombinedMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X2: [quartzParachainJunction, quartzAccountJunction],
- },
- },
- };
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- // eslint-disable-next-line require-await
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- alith = helper.account.alithAccount();
- });
- });
-
- const expectFailedToTransact = async (helper: DevUniqueHelper, messageSent: any) => {
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash
- && event.outcome.isFailedToTransactAsset);
- };
-
- itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {
- await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
- const id = {
- Token: 'KAR',
- };
- const destination = quartzCombinedMultilocation;
- await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-
- itSub('Quartz rejects MOVR tokens from Moonriver', async ({helper}) => {
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const id = 'SelfReserve';
- const destination = quartzCombinedMultilocation;
- await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-
- itSub('Quartz rejects SDN tokens from Shiden', async ({helper}) => {
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- const destinationParachain = quartzParachainMultilocation;
- const beneficiary = quartzAccountMultilocation;
- const assets = {
- V2: [{
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: testAmount,
- },
- }],
- };
- const feeAssetItem = 0;
-
- await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [
- destinationParachain,
- beneficiary,
- assets,
- feeAssetItem,
- ]);
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {
- // Quartz constants
- let alice: IKeyringPair;
- let quartzAssetLocation;
-
- let randomAccountQuartz: IKeyringPair;
- let randomAccountMoonriver: IKeyringPair;
-
- // Moonriver constants
- let assetId: string;
-
- const quartzAssetMetadata = {
- name: 'xcQuartz',
- symbol: 'xcQTZ',
- decimals: 18,
- isFrozen: false,
- minimalBalance: 1n,
- };
-
- let balanceQuartzTokenInit: bigint;
- let balanceQuartzTokenMiddle: bigint;
- let balanceQuartzTokenFinal: bigint;
- let balanceForeignQtzTokenInit: bigint;
- let balanceForeignQtzTokenMiddle: bigint;
- let balanceForeignQtzTokenFinal: bigint;
- let balanceMovrTokenInit: bigint;
- let balanceMovrTokenMiddle: bigint;
- let balanceMovrTokenFinal: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);
-
- balanceForeignQtzTokenInit = 0n;
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const alithAccount = helper.account.alithAccount();
- const baltatharAccount = helper.account.baltatharAccount();
- const dorothyAccount = helper.account.dorothyAccount();
-
- randomAccountMoonriver = helper.account.create();
-
- // >>> Sponsoring Dorothy >>>
- console.log('Sponsoring Dorothy.......');
- await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring Dorothy.......DONE');
- // <<< Sponsoring Dorothy <<<
-
- quartzAssetLocation = {
- XCM: {
- parents: 1,
- interior: {X1: {Parachain: QUARTZ_CHAIN}},
- },
- };
- const existentialDeposit = 1n;
- const isSufficient = true;
- const unitsPerSecond = 1n;
- const numAssetsWeightHint = 0;
-
- if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {
- console.log('Quartz asset already registered on Moonriver');
- } else {
- const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
- location: quartzAssetLocation,
- metadata: quartzAssetMetadata,
- existentialDeposit,
- isSufficient,
- unitsPerSecond,
- numAssetsWeightHint,
- });
-
- console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-
- await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
- }
- // >>> Acquire Quartz AssetId Info on Moonriver >>>
- console.log('Acquire Quartz AssetId Info on Moonriver.......');
-
- assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();
-
- console.log('QTZ asset ID is %s', assetId);
- console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');
- // >>> Acquire Quartz AssetId Info on Moonriver >>>
-
- // >>> Sponsoring random Account >>>
- console.log('Sponsoring random Account.......');
- await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring random Account.......DONE');
- // <<< Sponsoring random Account <<<
-
- balanceMovrTokenInit = await helper.balance.getEthereum(randomAccountMoonriver.address);
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
- balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);
- });
- });
-
- itSub('Should connect and send QTZ to Moonriver', async ({helper}) => {
- const currencyId = {
- NativeAssetId: 'Here',
- };
- const dest = {
- V2: {
- parents: 1,
- interior: {
- X2: [
- {Parachain: MOONRIVER_CHAIN},
- {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},
- ],
- },
- },
- };
- const amount = TRANSFER_AMOUNT;
-
- await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, 'Unlimited');
-
- balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address);
- expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;
-
- const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
- console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees));
- expect(transactionFees > 0, 'Negative fees QTZ, looks like nothing was transferred').to.be.true;
-
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- await helper.wait.newBlocks(3);
-
- balanceMovrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonriver.address);
-
- const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;
- console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR',helper.util.bigIntToDecimals(movrFees));
- expect(movrFees == 0n).to.be.true;
-
- balanceForeignQtzTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonriver.address))!; // BigInt(qtzRandomAccountAsset['balance']);
- const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;
- console.log('[Quartz -> Moonriver] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));
- expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
- });
- });
-
- itSub('Should connect to Moonriver and send QTZ back', async ({helper}) => {
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const asset = {
- V2: {
- id: {
- Concrete: {
- parents: 1,
- interior: {
- X1: {Parachain: QUARTZ_CHAIN},
- },
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- };
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X2: [
- {Parachain: QUARTZ_CHAIN},
- {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},
- ],
- },
- },
- };
-
- await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, 'Unlimited');
-
- balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address);
-
- const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;
- console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees));
- expect(movrFees > 0, 'Negative fees MOVR, looks like nothing was transferred').to.be.true;
-
- const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address);
-
- expect(qtzRandomAccountAsset).to.be.null;
-
- balanceForeignQtzTokenFinal = 0n;
-
- const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;
- console.log('[Quartz -> Moonriver] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));
- expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
- });
-
- await helper.wait.newBlocks(3);
-
- balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccountQuartz.address);
- const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;
- expect(actuallyDelivered > 0).to.be.true;
-
- console.log('[Moonriver -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));
-
- const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;
- console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
- expect(qtzFees == 0n).to.be.true;
- });
-
- itSub('Moonriver can send only up to its balance', async ({helper}) => {
- // set Moonriver's sovereign account's balance
- const moonriverBalance = 10000n * (10n ** QTZ_DECIMALS);
- const moonriverSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONRIVER_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, moonriverSovereignAccount, moonriverBalance);
-
- const moreThanMoonriverHas = moonriverBalance * 2n;
-
- let targetAccountBalance = 0n;
- const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
-
- const quartzMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {Parachain: QUARTZ_CHAIN},
- },
- },
- };
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanMoonriverHas,
- );
-
- let maliciousXcmProgramSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Quartz
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgram]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('try to spend more QTZ than Moonriver has', batchCall);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
-
- // But Moonriver still can send the correct amount
- const validTransferAmount = moonriverBalance / 2n;
- const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- validTransferAmount,
- );
-
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, validXcmProgram]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('Spend the correct amount of QTZ', batchCall);
- });
-
- await helper.wait.newBlocks(maxWaitBlocks);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(validTransferAmount);
- });
-
- itSub('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => {
- const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
- const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
-
- const quartzMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- },
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Quartz using full QTZ identification
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramFullId]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using path asset identification', batchCall);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Quartz using shortened QTZ identification
- await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramHereId]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using "here" asset identification', batchCall);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging tokens with Shiden', () => {
- let alice: IKeyringPair;
- let sender: IKeyringPair;
-
- const QTZ_ASSET_ID_ON_SHIDEN = 18_446_744_073_709_551_633n; // The value is taken from the live Shiden
- const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; // The value is taken from the live Shiden
-
- // Quartz -> Shiden
- const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden
- const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden
- const qtzToShidenTransferred = 10n * (10n ** QTZ_DECIMALS); // 10 QTZ
- const qtzToShidenArrived = 7_998_196_000_000_000_000n; // 7.99 ... QTZ, Shiden takes a commision in foreign tokens
-
- // Shiden -> Quartz
- const qtzFromShidenTransfered = 5n * (10n ** QTZ_DECIMALS); // 5 QTZ
- const qtzOnShidenLeft = qtzToShidenArrived - qtzFromShidenTransfered; // 2.99 ... QTZ
-
- let balanceAfterQuartzToShidenXCM: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [sender] = await helper.arrange.createAccounts([100n], alice);
- console.log('sender', sender.address);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
- console.log('1. Create foreign asset and metadata');
- await helper.getSudo().assets.forceCreate(
- alice,
- QTZ_ASSET_ID_ON_SHIDEN,
- alice.address,
- QTZ_MINIMAL_BALANCE_ON_SHIDEN,
- );
-
- await helper.assets.setMetadata(
- alice,
- QTZ_ASSET_ID_ON_SHIDEN,
- 'Quartz',
- 'QTZ',
- Number(QTZ_DECIMALS),
- );
-
- console.log('2. Register asset location on Shiden');
- const assetLocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
-
- console.log('3. Set QTZ payment for XCM execution on Shiden');
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
- } else {
- console.log('QTZ is already registered on Shiden');
- }
- console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');
- await helper.balance.transferToSubstrate(alice, sender.address, shidenInitialBalance);
- });
- });
-
- itSub('Should connect and send QTZ to Shiden', async ({helper}) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: SHIDEN_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: sender.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: qtzToShidenTransferred,
- },
- },
- ],
- };
-
- // Initial balance is 100 QTZ
- const balanceBefore = await helper.balance.getSubstrate(sender.address);
- console.log(`Initial balance is: ${balanceBefore}`);
-
- const feeAssetItem = 0;
- await helper.xcm.limitedReserveTransferAssets(sender, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
-
- // Balance after reserve transfer is less than 90
- balanceAfterQuartzToShidenXCM = await helper.balance.getSubstrate(sender.address);
- console.log(`QTZ Balance on Quartz after XCM is: ${balanceAfterQuartzToShidenXCM}`);
- console.log(`Quartz's QTZ commission is: ${balanceBefore - balanceAfterQuartzToShidenXCM}`);
- expect(balanceBefore - balanceAfterQuartzToShidenXCM > 0).to.be.true;
-
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- await helper.wait.newBlocks(3);
- const xcQTZbalance = await helper.assets.account(QTZ_ASSET_ID_ON_SHIDEN, sender.address);
- const shidenBalance = await helper.balance.getSubstrate(sender.address);
-
- console.log(`xcQTZ balance on Shiden after XCM is: ${xcQTZbalance}`);
- console.log(`Shiden's QTZ commission is: ${qtzToShidenTransferred - xcQTZbalance!}`);
-
- expect(xcQTZbalance).to.eq(qtzToShidenArrived);
- // SHD balance does not changed:
- expect(shidenBalance).to.eq(shidenInitialBalance);
- });
- });
-
- itSub('Should connect to Shiden and send QTZ back', async ({helper}) => {
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: sender.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- },
- fun: {
- Fungible: qtzFromShidenTransfered,
- },
- },
- ],
- };
-
- // Initial balance is 1 SDN
- const balanceSDNbefore = await helper.balance.getSubstrate(sender.address);
- console.log(`SDN balance is: ${balanceSDNbefore}, it does not changed`);
- expect(balanceSDNbefore).to.eq(shidenInitialBalance);
-
- const feeAssetItem = 0;
- // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw
- await helper.executeExtrinsic(sender, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);
-
- // Balance after reserve transfer is less than 1 SDN
- const xcQTZbalance = await helper.assets.account(QTZ_ASSET_ID_ON_SHIDEN, sender.address);
- const balanceSDN = await helper.balance.getSubstrate(sender.address);
- console.log(`xcQTZ balance on Shiden after XCM is: ${xcQTZbalance}`);
-
- // Assert: xcQTZ balance correctly decreased
- expect(xcQTZbalance).to.eq(qtzOnShidenLeft);
- // Assert: SDN balance is 0.996...
- expect(balanceSDN / (10n ** (SHIDEN_DECIMALS - 3n))).to.eq(996n);
- });
-
- await helper.wait.newBlocks(3);
- const balanceQTZ = await helper.balance.getSubstrate(sender.address);
- console.log(`QTZ Balance on Quartz after XCM is: ${balanceQTZ}`);
- expect(balanceQTZ).to.eq(balanceAfterQuartzToShidenXCM + qtzFromShidenTransfered);
- });
-
- itSub('Shiden can send only up to its balance', async ({helper}) => {
- // set Shiden's sovereign account's balance
- const shidenBalance = 10000n * (10n ** QTZ_DECIMALS);
- const shidenSovereignAccount = helper.address.paraSiblingSovereignAccount(SHIDEN_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, shidenSovereignAccount, shidenBalance);
-
- const moreThanShidenHas = shidenBalance * 2n;
-
- let targetAccountBalance = 0n;
- const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
-
- const quartzMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {Parachain: QUARTZ_CHAIN},
- },
- },
- };
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanShidenHas,
- );
-
- let maliciousXcmProgramSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Quartz
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
-
- // But Shiden still can send the correct amount
- const validTransferAmount = shidenBalance / 2n;
- const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- validTransferAmount,
- );
-
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, validXcmProgram);
- });
-
- await helper.wait.newBlocks(maxWaitBlocks);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(validTransferAmount);
- });
-
- itSub('Should not accept reserve transfer of QTZ from Shiden', async ({helper}) => {
- const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
- const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
-
- const quartzMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- };
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: QUARTZ_CHAIN,
- },
- },
- },
- },
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Quartz using full QTZ identification
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Quartz using shortened QTZ identification
- await usingShidenPlaygrounds(shidenUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
js-packages/tests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth--- a/js-packages/tests/src/xcm/xcmUnique.test.ts
+++ /dev/null
@@ -1,1834 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import config from '../config.js';
-import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds} from '../util/index.js';
-import {Event} from '@unique/playgrounds/src/unique.dev.js';
-import {hexToString, nToBigInt} from '@polkadot/util';
-import {ACALA_CHAIN, ASTAR_CHAIN, MOONBEAM_CHAIN, POLKADEX_CHAIN, SAFE_XCM_VERSION, STATEMINT_CHAIN, UNIQUE_CHAIN, expectFailedToTransact, expectUntrustedReserveLocationFail, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types.js';
-
-
-const STATEMINT_PALLET_INSTANCE = 50;
-
-const relayUrl = config.relayUrl;
-const statemintUrl = config.statemintUrl;
-const acalaUrl = config.acalaUrl;
-const moonbeamUrl = config.moonbeamUrl;
-const astarUrl = config.astarUrl;
-const polkadexUrl = config.polkadexUrl;
-
-const RELAY_DECIMALS = 12;
-const STATEMINT_DECIMALS = 12;
-const ACALA_DECIMALS = 12;
-const ASTAR_DECIMALS = 18n;
-const UNQ_DECIMALS = 18n;
-
-const TRANSFER_AMOUNT = 2000000000000000000000000n;
-
-const FUNDING_AMOUNT = 3_500_000_0000_000_000n;
-
-const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
-
-const USDT_ASSET_ID = 100;
-const USDT_ASSET_METADATA_DECIMALS = 18;
-const USDT_ASSET_METADATA_NAME = 'USDT';
-const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';
-const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
-const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
-
-describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- let balanceStmnBefore: bigint;
- let balanceStmnAfter: bigint;
-
- let balanceUniqueBefore: bigint;
- let balanceUniqueAfter: bigint;
- let balanceUniqueFinal: bigint;
-
- let balanceBobBefore: bigint;
- let balanceBobAfter: bigint;
- let balanceBobFinal: bigint;
-
- let balanceBobRelayTokenBefore: bigint;
- let balanceBobRelayTokenAfter: bigint;
-
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- // Fund accounts on Statemint
- await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);
- await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);
- });
-
- await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
- const sovereignFundingAmount = 3_500_000_000n;
-
- await helper.assets.create(
- alice,
- USDT_ASSET_ID,
- alice.address,
- USDT_ASSET_METADATA_MINIMAL_BALANCE,
- );
- await helper.assets.setMetadata(
- alice,
- USDT_ASSET_ID,
- USDT_ASSET_METADATA_NAME,
- USDT_ASSET_METADATA_DESCRIPTION,
- USDT_ASSET_METADATA_DECIMALS,
- );
- await helper.assets.mint(
- alice,
- USDT_ASSET_ID,
- alice.address,
- USDT_ASSET_AMOUNT,
- );
-
- // funding parachain sovereing account on Statemint.
- // The sovereign account should be created before any action
- // (the assets pallet on Statemint check if the sovereign account exists)
- const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);
- await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);
- });
-
-
- await usingPlaygrounds(async (helper) => {
- const location = {
- V2: {
- parents: 1,
- interior: {X3: [
- {
- Parachain: STATEMINT_CHAIN,
- },
- {
- PalletInstance: STATEMINT_PALLET_INSTANCE,
- },
- {
- GeneralIndex: USDT_ASSET_ID,
- },
- ]},
- },
- };
-
- const metadata =
- {
- name: USDT_ASSET_ID,
- symbol: USDT_ASSET_METADATA_NAME,
- decimals: USDT_ASSET_METADATA_DECIMALS,
- minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,
- };
- await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
- balanceUniqueBefore = await helper.balance.getSubstrate(alice.address);
- });
-
-
- // Providing the relay currency to the unique sender account
- // (fee for USDT XCM are paid in relay tokens)
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 0,
- interior: {X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT_RELAY,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- });
-
- });
-
- itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {
- await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
- const dest = {
- V2: {
- parents: 1,
- interior: {X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: {
- X2: [
- {
- PalletInstance: STATEMINT_PALLET_INSTANCE,
- },
- {
- GeneralIndex: USDT_ASSET_ID,
- },
- ]},
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
- await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
-
- balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
-
- // common good parachain take commission in it native token
- console.log(
- '[Statemint -> Unique] transaction fees on Statemint: %s WND',
- helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS),
- );
- expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
-
- });
-
-
- // ensure that asset has been delivered
- await helper.wait.newBlocks(3);
-
- // expext collection id will be with id 1
- const free = await helper.ft.getBalance(1, {Substrate: alice.address});
-
- balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);
-
- console.log(
- '[Statemint -> Unique] transaction fees on Unique: %s USDT',
- helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),
- );
- console.log(
- '[Statemint -> Unique] transaction fees on Unique: %s UNQ',
- helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore),
- );
- // commission has not paid in USDT token
- expect(free).to.be.equal(TRANSFER_AMOUNT);
- // ... and parachain native token
- expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;
- });
-
- itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {X2: [
- {
- Parachain: STATEMINT_CHAIN,
- },
- {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- },
- ]},
- },
- };
-
- const relayFee = 400_000_000_000_000n;
- const currencies: [any, bigint][] = [
- [
- {
- ForeignAssetId: 0,
- },
- TRANSFER_AMOUNT,
- ],
- [
- {
- NativeAssetId: 'Parent',
- },
- relayFee,
- ],
- ];
-
- const feeItem = 1;
-
- await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
-
- // the commission has been paid in parachain native token
- balanceUniqueFinal = await helper.balance.getSubstrate(alice.address);
- console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueFinal));
- expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true;
-
- await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
- await helper.wait.newBlocks(3);
-
- // The USDT token never paid fees. Its amount not changed from begin value.
- // Also check that xcm transfer has been succeeded
- expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
- });
- });
-
- itSub('Should connect and send Relay token to Unique', async ({helper}) => {
- balanceBobBefore = await helper.balance.getSubstrate(bob.address);
- balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 0,
- interior: {X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- }};
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {X1: {
- AccountId32: {
- network: 'Any',
- id: bob.addressRaw,
- },
- }},
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT_RELAY,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- });
-
- await helper.wait.newBlocks(3);
-
- balanceBobAfter = await helper.balance.getSubstrate(bob.address);
- balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
-
- const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
- const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;
- console.log(
- '[Relay (Westend) -> Unique] transaction fees: %s UNQ',
- helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
- );
- console.log(
- '[Relay (Westend) -> Unique] transaction fees: %s WND',
- helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS),
- );
- console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique);
- expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true;
- expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true;
- });
-
- itSub('Should connect and send Relay token back', async ({helper}) => {
- let relayTokenBalanceBefore: bigint;
- let relayTokenBalanceAfter: bigint;
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
- });
-
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1:{
- AccountId32: {
- network: 'Any',
- id: bob.addressRaw,
- },
- },
- },
- },
- };
-
- const currencies: any = [
- [
- {
- NativeAssetId: 'Parent',
- },
- TRANSFER_AMOUNT_RELAY,
- ],
- ];
-
- const feeItem = 0;
-
- await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
-
- balanceBobFinal = await helper.balance.getSubstrate(bob.address);
- console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
-
- await usingRelayPlaygrounds(relayUrl, async (helper) => {
- await helper.wait.newBlocks(10);
- relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
- const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
- console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
- expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
- });
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- let balanceUniqueTokenInit: bigint;
- let balanceUniqueTokenMiddle: bigint;
- let balanceUniqueTokenFinal: bigint;
- let balanceAcalaTokenInit: bigint;
- let balanceAcalaTokenMiddle: bigint;
- let balanceAcalaTokenFinal: bigint;
- let balanceUniqueForeignTokenInit: bigint;
- let balanceUniqueForeignTokenMiddle: bigint;
- let balanceUniqueForeignTokenFinal: bigint;
-
- // computed by a test transfer from prod Unique to prod Acala.
- // 2 UNQ sent https://unique.subscan.io/xcm_message/polkadot-bad0b68847e2398af25d482e9ee6f9c1f9ec2a48
- // 1.898970000000000000 UNQ received (you can check Acala's chain state in the corresponding block)
- const expectedAcalaIncomeFee = 2000000000000000000n - 1898970000000000000n;
- const acalaEps = 8n * 10n ** 16n;
-
- let acalaBackwardTransferAmount: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccount] = await helper.arrange.createAccounts([0n], alice);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- const metadata = {
- name: 'Unique Network',
- symbol: 'UNQ',
- decimals: 18,
- minimalBalance: 1250000000000000000n,
- };
- const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>
- hexToString(v.toJSON()['symbol'])) as string[];
-
- if(!assets.includes('UNQ')) {
- await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
- } else {
- console.log('UNQ token already registered on Acala assetRegistry pallet');
- }
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
- balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);
- balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
- balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
- });
- });
-
- itSub('Should connect and send UNQ to Acala', async ({helper}) => {
-
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: ACALA_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
- const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
- console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
- expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
-
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- await helper.wait.newBlocks(3);
-
- balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
- balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
- const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;
- const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;
- acalaBackwardTransferAmount = unqIncomeTransfer;
-
- const acaUnqFees = TRANSFER_AMOUNT - unqIncomeTransfer;
-
- console.log(
- '[Unique -> Acala] transaction fees on Acala: %s ACA',
- helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),
- );
- console.log(
- '[Unique -> Acala] transaction fees on Acala: %s UNQ',
- helper.util.bigIntToDecimals(acaUnqFees),
- );
- console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));
- expect(acaFees == 0n).to.be.true;
-
- const bigintAbs = (n: bigint) => (n < 0n) ? -n : n;
-
- expect(
- bigintAbs(acaUnqFees - expectedAcalaIncomeFee) < acalaEps,
- 'Acala took different income fee, check the Acala foreign asset config',
- ).to.be.true;
- });
- });
-
- itSub('Should connect to Acala and send UNQ back', async ({helper}) => {
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X2: [
- {Parachain: UNIQUE_CHAIN},
- {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- ],
- },
- },
- };
-
- const id = {
- ForeignAsset: 0,
- };
-
- await helper.xTokens.transfer(randomAccount, id, acalaBackwardTransferAmount, destination, 'Unlimited');
- balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
- balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);
-
- const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;
- const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;
-
- console.log(
- '[Acala -> Unique] transaction fees on Acala: %s ACA',
- helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),
- );
- console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));
-
- expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;
- expect(unqOutcomeTransfer == acalaBackwardTransferAmount).to.be.true;
- });
-
- await helper.wait.newBlocks(3);
-
- balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
- const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
- expect(actuallyDelivered > 0).to.be.true;
-
- console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));
-
- const unqFees = acalaBackwardTransferAmount - actuallyDelivered;
- console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
- expect(unqFees == 0n).to.be.true;
- });
-
- itSub('Acala can send only up to its balance', async ({helper}) => {
- // set Acala's sovereign account's balance
- const acalaBalance = 10000n * (10n ** UNQ_DECIMALS);
- const acalaSovereignAccount = helper.address.paraSiblingSovereignAccount(ACALA_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, acalaSovereignAccount, acalaBalance);
-
- const moreThanAcalaHas = acalaBalance * 2n;
-
- let targetAccountBalance = 0n;
- const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanAcalaHas,
- );
-
- let maliciousXcmProgramSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
-
- // But Acala still can send the correct amount
- const validTransferAmount = acalaBalance / 2n;
- const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- validTransferAmount,
- );
-
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);
- });
-
- await helper.wait.newBlocks(maxWaitBlocks);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(validTransferAmount);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Acala', async ({helper}) => {
- const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
- const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
-
- const uniqueMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- uniqueAssetId,
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique using full UNQ identification
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Unique using shortened UNQ identification
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging tokens with Polkadex', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
- let unqFees: bigint;
- let balanceUniqueTokenInit: bigint;
- let balanceUniqueTokenMiddle: bigint;
- let balanceUniqueTokenFinal: bigint;
- const maxWaitBlocks = 6;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccount] = await helper.arrange.createAccounts([0n], alice);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))
- .toJSON() as [])
- .map(nToBigInt).length != 0;
- /*
- Check whether the Unique token has been added
- to the whitelist, since an error will occur
- if it is added again. Needed for debugging
- when this test is run multiple times.
- */
- if(isWhitelisted) {
- console.log('UNQ token is already whitelisted on Polkadex');
- } else {
- await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);
- }
-
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
- balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
- });
- });
-
- itSub('Should connect and send UNQ to Polkadex', async ({helper}) => {
-
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: POLKADEX_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- ],
- };
-
- const feeAssetItem = 0;
-
- await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
- const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
- unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
- console.log('[Unique -> Polkadex] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
- expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
-
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- /*
- Since only the parachain part of the Polkadex
- infrastructure is launched (without their
- solochain validators), processing incoming
- assets will lead to an error.
- This error indicates that the Polkadex chain
- received a message from the Unique network,
- since the hash is being checked to ensure
- it matches what was sent.
- */
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);
- });
- });
-
-
- itSub('Should connect to Polkadex and send UNQ back', async ({helper}) => {
-
- const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- randomAccount.addressRaw,
- uniqueAssetId,
- TRANSFER_AMOUNT,
- );
-
- let xcmProgramSent: any;
-
-
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, xcmProgram);
-
- xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);
-
- balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
-
- expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees);
- });
-
- itSub('Polkadex can send only up to its balance', async ({helper}) => {
- const polkadexBalance = 10000n * (10n ** UNQ_DECIMALS);
- const polkadexSovereignAccount = helper.address.paraSiblingSovereignAccount(POLKADEX_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, polkadexSovereignAccount, polkadexBalance);
- const moreThanPolkadexHas = 2n * polkadexBalance;
-
- const targetAccount = helper.arrange.createEmptyAccount();
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanPolkadexHas,
- );
-
- let maliciousXcmProgramSent: any;
-
-
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, maliciousXcmProgramSent);
-
- const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Polkadex', async ({helper}) => {
- const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
- const targetAccount = helper.arrange.createEmptyAccount();
-
- const uniqueMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- uniqueAssetId,
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique using full UNQ identification
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Unique using shortened UNQ identification
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
-
-// These tests are relevant only when
-// the the corresponding foreign assets are not registered
-describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {
- let alice: IKeyringPair;
- let alith: IKeyringPair;
-
- const testAmount = 100_000_000_000n;
- let uniqueParachainJunction;
- let uniqueAccountJunction;
-
- let uniqueParachainMultilocation: any;
- let uniqueAccountMultilocation: any;
- let uniqueCombinedMultilocation: any;
- let uniqueCombinedMultilocationAcala: any; // TODO remove when Acala goes V2
-
- let messageSent: any;
-
- const maxWaitBlocks = 3;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
-
- uniqueParachainJunction = {Parachain: UNIQUE_CHAIN};
- uniqueAccountJunction = {
- AccountId32: {
- network: 'Any',
- id: alice.addressRaw,
- },
- };
-
- uniqueParachainMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X1: uniqueParachainJunction,
- },
- },
- };
-
- uniqueAccountMultilocation = {
- V2: {
- parents: 0,
- interior: {
- X1: uniqueAccountJunction,
- },
- },
- };
-
- uniqueCombinedMultilocation = {
- V2: {
- parents: 1,
- interior: {
- X2: [uniqueParachainJunction, uniqueAccountJunction],
- },
- },
- };
-
- uniqueCombinedMultilocationAcala = {
- V2: {
- parents: 1,
- interior: {
- X2: [uniqueParachainJunction, uniqueAccountJunction],
- },
- },
- };
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- // eslint-disable-next-line require-await
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- alith = helper.account.alithAccount();
- });
- });
-
-
-
- itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {
- await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
- const id = {
- Token: 'ACA',
- };
- const destination = uniqueCombinedMultilocationAcala;
- await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-
- itSub('Unique rejects GLMR tokens from Moonbeam', async ({helper}) => {
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const id = 'SelfReserve';
- const destination = uniqueCombinedMultilocation;
- await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-
- itSub('Unique rejects ASTR tokens from Astar', async ({helper}) => {
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- const destinationParachain = uniqueParachainMultilocation;
- const beneficiary = uniqueAccountMultilocation;
- const assets = {
- V2: [{
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: testAmount,
- },
- }],
- };
- const feeAssetItem = 0;
-
- await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [
- destinationParachain,
- beneficiary,
- assets,
- feeAssetItem,
- ]);
-
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-
- itSub('Unique rejects PDX tokens from Polkadex', async ({helper}) => {
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- helper.arrange.createEmptyAccount().addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: POLKADEX_CHAIN,
- },
- },
- },
- },
- testAmount,
- );
-
- await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueParachainMultilocation, maliciousXcmProgramFullId);
- messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await expectFailedToTransact(helper, messageSent);
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {
- // Unique constants
- let alice: IKeyringPair;
- let uniqueAssetLocation;
-
- let randomAccountUnique: IKeyringPair;
- let randomAccountMoonbeam: IKeyringPair;
-
- // Moonbeam constants
- let assetId: string;
-
- const uniqueAssetMetadata = {
- name: 'xcUnique',
- symbol: 'xcUNQ',
- decimals: 18,
- isFrozen: false,
- minimalBalance: 1n,
- };
-
- let balanceUniqueTokenInit: bigint;
- let balanceUniqueTokenMiddle: bigint;
- let balanceUniqueTokenFinal: bigint;
- let balanceForeignUnqTokenInit: bigint;
- let balanceForeignUnqTokenMiddle: bigint;
- let balanceForeignUnqTokenFinal: bigint;
- let balanceGlmrTokenInit: bigint;
- let balanceGlmrTokenMiddle: bigint;
- let balanceGlmrTokenFinal: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);
-
- balanceForeignUnqTokenInit = 0n;
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const alithAccount = helper.account.alithAccount();
- const baltatharAccount = helper.account.baltatharAccount();
- const dorothyAccount = helper.account.dorothyAccount();
-
- randomAccountMoonbeam = helper.account.create();
-
- // >>> Sponsoring Dorothy >>>
- console.log('Sponsoring Dorothy.......');
- await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring Dorothy.......DONE');
- // <<< Sponsoring Dorothy <<<
-
- uniqueAssetLocation = {
- XCM: {
- parents: 1,
- interior: {X1: {Parachain: UNIQUE_CHAIN}},
- },
- };
- const existentialDeposit = 1n;
- const isSufficient = true;
- const unitsPerSecond = 1n;
- const numAssetsWeightHint = 0;
-
- if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {
- console.log('Unique asset is already registered on MoonBeam');
- } else {
- const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
- location: uniqueAssetLocation,
- metadata: uniqueAssetMetadata,
- existentialDeposit,
- isSufficient,
- unitsPerSecond,
- numAssetsWeightHint,
- });
-
- console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-
- await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);
- }
-
- // >>> Acquire Unique AssetId Info on Moonbeam >>>
- console.log('Acquire Unique AssetId Info on Moonbeam.......');
-
- assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();
- console.log('UNQ asset ID is %s', assetId);
- console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');
- // >>> Acquire Unique AssetId Info on Moonbeam >>>
-
- // >>> Sponsoring random Account >>>
- console.log('Sponsoring random Account.......');
- await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);
- console.log('Sponsoring random Account.......DONE');
- // <<< Sponsoring random Account <<<
-
- balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);
- });
-
- await usingPlaygrounds(async (helper) => {
- await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);
- balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);
- });
- });
-
- itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {
- const currencyId = {
- NativeAssetId: 'Here',
- };
- const dest = {
- V2: {
- parents: 1,
- interior: {
- X2: [
- {Parachain: MOONBEAM_CHAIN},
- {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},
- ],
- },
- },
- };
- const amount = TRANSFER_AMOUNT;
-
- await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited');
-
- balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);
- expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;
-
- const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
- console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));
- expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
-
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- await helper.wait.newBlocks(3);
- balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);
-
- const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;
- console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));
- expect(glmrFees == 0n).to.be.true;
-
- balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;
-
- const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;
- console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));
- expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
- });
- });
-
- itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const asset = {
- V2: {
- id: {
- Concrete: {
- parents: 1,
- interior: {
- X1: {Parachain: UNIQUE_CHAIN},
- },
- },
- },
- fun: {
- Fungible: TRANSFER_AMOUNT,
- },
- },
- };
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X2: [
- {Parachain: UNIQUE_CHAIN},
- {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},
- ],
- },
- },
- };
-
- await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, 'Unlimited');
-
- balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);
-
- const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;
- console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));
- expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;
-
- const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);
-
- expect(unqRandomAccountAsset).to.be.null;
-
- balanceForeignUnqTokenFinal = 0n;
-
- const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;
- console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));
- expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
- });
-
- await helper.wait.newBlocks(3);
-
- balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);
- const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
- expect(actuallyDelivered > 0).to.be.true;
-
- console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));
-
- const unqFees = TRANSFER_AMOUNT - actuallyDelivered;
- console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
- expect(unqFees == 0n).to.be.true;
- });
-
- itSub('Moonbeam can send only up to its balance', async ({helper}) => {
- // set Moonbeam's sovereign account's balance
- const moonbeamBalance = 10000n * (10n ** UNQ_DECIMALS);
- const moonbeamSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONBEAM_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, moonbeamSovereignAccount, moonbeamBalance);
-
- const moreThanMoonbeamHas = moonbeamBalance * 2n;
-
- let targetAccountBalance = 0n;
- const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanMoonbeamHas,
- );
-
- let maliciousXcmProgramSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('try to spend more UNQ than Moonbeam has', batchCall);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
-
- // But Moonbeam still can send the correct amount
- const validTransferAmount = moonbeamBalance / 2n;
- const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- validTransferAmount,
- );
-
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, validXcmProgram]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('Spend the correct amount of UNQ', batchCall);
- });
-
- await helper.wait.newBlocks(maxWaitBlocks);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(validTransferAmount);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => {
- const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
- const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- uniqueAssetId,
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique using full UNQ identification
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using path asset identification', batchCall);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Unique using shortened UNQ identification
- await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
- const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);
-
- // Needed to bypass the call filter.
- const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
- await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using "here" asset identification', batchCall);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
-
-describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => {
- let alice: IKeyringPair;
- let randomAccount: IKeyringPair;
-
- const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; // The value is taken from the live Astar
- const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; // The value is taken from the live Astar
-
- // Unique -> Astar
- const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.
- const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar
- const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ
- const unqToAstarArrived = 9_962_196_000_000_000_000n; // 9.962 ... UNQ, Astar takes a commision in foreign tokens
-
- // Astar -> Unique
- const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ
- const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.962_219_600_000_000_000n UNQ
-
- let balanceAfterUniqueToAstarXCM: bigint;
-
- before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- alice = await privateKey('//Alice');
- [randomAccount] = await helper.arrange.createAccounts([100n], alice);
- console.log('randomAccount', randomAccount.address);
-
- // Set the default version to wrap the first message to other chains.
- await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
- });
-
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {
- console.log('1. Create foreign asset and metadata');
- await helper.getSudo().assets.forceCreate(
- alice,
- UNQ_ASSET_ID_ON_ASTAR,
- alice.address,
- UNQ_MINIMAL_BALANCE_ON_ASTAR,
- );
-
- await helper.assets.setMetadata(
- alice,
- UNQ_ASSET_ID_ON_ASTAR,
- 'Unique Network',
- 'UNQ',
- Number(UNQ_DECIMALS),
- );
-
- console.log('2. Register asset location on Astar');
- const assetLocation = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);
-
- console.log('3. Set UNQ payment for XCM execution on Astar');
- await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
- } else {
- console.log('UNQ is already registered on Astar');
- }
- console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');
- await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);
- });
- });
-
- itSub('Should connect and send UNQ to Astar', async ({helper}) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: ASTAR_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- fun: {
- Fungible: unqToAstarTransferred,
- },
- },
- ],
- };
-
- // Initial balance is 100 UNQ
- const balanceBefore = await helper.balance.getSubstrate(randomAccount.address);
- console.log(`Initial balance is: ${balanceBefore}`);
-
- const feeAssetItem = 0;
- await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
-
- // Balance after reserve transfer is less than 90
- balanceAfterUniqueToAstarXCM = await helper.balance.getSubstrate(randomAccount.address);
- console.log(`UNQ Balance on Unique after XCM is: ${balanceAfterUniqueToAstarXCM}`);
- console.log(`Unique's UNQ commission is: ${balanceBefore - balanceAfterUniqueToAstarXCM}`);
- expect(balanceBefore - balanceAfterUniqueToAstarXCM > 0).to.be.true;
-
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- await helper.wait.newBlocks(3);
- const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);
- const astarBalance = await helper.balance.getSubstrate(randomAccount.address);
-
- console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);
- console.log(`Astar's UNQ commission is: ${unqToAstarTransferred - xcUNQbalance!}`);
-
- expect(xcUNQbalance).to.eq(unqToAstarArrived);
- // Astar balance does not changed
- expect(astarBalance).to.eq(astarInitialBalance);
- });
- });
-
- itSub('Should connect to Astar and send UNQ back', async ({helper}) => {
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- const destination = {
- V2: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- };
-
- const beneficiary = {
- V2: {
- parents: 0,
- interior: {
- X1: {
- AccountId32: {
- network: 'Any',
- id: randomAccount.addressRaw,
- },
- },
- },
- },
- };
-
- const assets = {
- V2: [
- {
- id: {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- },
- fun: {
- Fungible: unqFromAstarTransfered,
- },
- },
- ],
- };
-
- // Initial balance is 1 ASTR
- const balanceASTRbefore = await helper.balance.getSubstrate(randomAccount.address);
- console.log(`ASTR balance is: ${balanceASTRbefore}, it does not changed`);
- expect(balanceASTRbefore).to.eq(astarInitialBalance);
-
- const feeAssetItem = 0;
- // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw
- await helper.executeExtrinsic(randomAccount, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);
-
- const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);
- const balanceAstar = await helper.balance.getSubstrate(randomAccount.address);
- console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);
-
- // Assert: xcUNQ balance correctly decreased
- expect(xcUNQbalance).to.eq(unqOnAstarLeft);
- // Assert: ASTR balance is 0.996...
- expect(balanceAstar / (10n ** (ASTAR_DECIMALS - 3n))).to.eq(996n);
- });
-
- await helper.wait.newBlocks(3);
- const balanceUNQ = await helper.balance.getSubstrate(randomAccount.address);
- console.log(`UNQ Balance on Unique after XCM is: ${balanceUNQ}`);
- expect(balanceUNQ).to.eq(balanceAfterUniqueToAstarXCM + unqFromAstarTransfered);
- });
-
- itSub('Astar can send only up to its balance', async ({helper}) => {
- // set Astar's sovereign account's balance
- const astarBalance = 10000n * (10n ** UNQ_DECIMALS);
- const astarSovereignAccount = helper.address.paraSiblingSovereignAccount(ASTAR_CHAIN);
- await helper.getSudo().balance.setBalanceSubstrate(alice, astarSovereignAccount, astarBalance);
-
- const moreThanAstarHas = astarBalance * 2n;
-
- let targetAccountBalance = 0n;
- const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
-
- const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- moreThanAstarHas,
- );
-
- let maliciousXcmProgramSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);
-
- maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
- && event.outcome.isFailedToTransactAsset);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(0n);
-
- // But Astar still can send the correct amount
- const validTransferAmount = astarBalance / 2n;
- const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- validTransferAmount,
- );
-
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);
- });
-
- await helper.wait.newBlocks(maxWaitBlocks);
-
- targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(targetAccountBalance).to.be.equal(validTransferAmount);
- });
-
- itSub('Should not accept reserve transfer of UNQ from Astar', async ({helper}) => {
- const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
- const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
-
- const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- uniqueAssetId,
- testAmount,
- );
-
- const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
- targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: 'Here',
- },
- },
- testAmount,
- );
-
- let maliciousXcmProgramFullIdSent: any;
- let maliciousXcmProgramHereIdSent: any;
- const maxWaitBlocks = 3;
-
- // Try to trick Unique using full UNQ identification
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramFullId);
-
- maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
-
- // Try to trick Unique using shortened UNQ identification
- await usingAstarPlaygrounds(astarUrl, async (helper) => {
- await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramHereId);
-
- maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
- });
-
- await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
- && event.outcome.isUntrustedReserveLocation);
-
- accountBalance = await helper.balance.getSubstrate(targetAccount.address);
- expect(accountBalance).to.be.equal(0n);
- });
-});
js-packages/tests/sub/appPromotion/appPromotion.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/appPromotion/appPromotion.seqtest.ts
@@ -0,0 +1,82 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '../../util/index.js';
+import {expect} from '../../eth/util/index.js';
+
+let superuser: IKeyringPair;
+let donor: IKeyringPair;
+let palletAdmin: IKeyringPair;
+
+describe('App promotion', () => {
+ before(async function () {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]);
+ superuser = await privateKey('//Alice');
+ donor = await privateKey({url: import.meta.url});
+ palletAdmin = await privateKey('//PromotionAdmin');
+ const api = helper.getApi();
+ await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
+ });
+ });
+
+ after(async function () {
+ await usingPlaygrounds(async (helper) => {
+ if(helper.fetchMissingPalletNames([Pallets.AppPromotion]).length != 0) return;
+ const api = helper.getApi();
+ await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
+ });
+ });
+
+ describe('admin adress', () => {
+ itSub('can be set by sudo only', async ({helper}) => {
+ const api = helper.getApi();
+ const [nonAdmin] = await helper.arrange.createAccounts([10n], donor);
+ // nonAdmin can not set admin not from himself nor as a sudo
+ await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected;
+ await expect(helper.signTransaction(nonAdmin, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected;
+ });
+
+ itSub('can be any valid CrossAccountId', async ({helper}) => {
+ // We are not going to set an eth address as a sponsor,
+ // but we do want to check, it doesn't break anything;
+ const api = helper.getApi();
+ const [account] = await helper.arrange.createAccounts([10n], donor);
+ const ethAccount = helper.address.substrateToEth(account.address);
+ // Alice sets Ethereum address as a sudo. Then Substrate address back...
+ await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled;
+ await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled;
+
+ // ...It doesn't break anything;
+ const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ await expect(helper.signTransaction(account, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
+ });
+
+ itSub('can be reassigned', async ({helper}) => {
+ const api = helper.getApi();
+ const [oldAdmin, newAdmin, collectionOwner] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: oldAdmin.address})))).to.be.fulfilled;
+ await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: newAdmin.address})))).to.be.fulfilled;
+ await expect(helper.signTransaction(oldAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
+
+ await expect(helper.signTransaction(newAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
+ });
+ });
+});
+
js-packages/tests/sub/appPromotion/appPromotion.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/appPromotion/appPromotion.test.ts
@@ -0,0 +1,1008 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {
+ itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip, LOCKING_PERIOD, UNLOCKING_PERIOD,
+} from '../../util/index.js';
+import {DevUniqueHelper} from '@unique/playgrounds/unique.dev.js';
+import {itEth, expect, SponsoringMode} from '../../eth/util/index.js';
+
+let donor: IKeyringPair;
+let palletAdmin: IKeyringPair;
+let nominal: bigint;
+let palletAddress: string;
+let accounts: IKeyringPair[];
+let usedAccounts: IKeyringPair[] = [];
+
+async function getAccounts(accountsNumber: number, balance?: bigint) {
+ let accs: IKeyringPair[] = [];
+ if(balance) {
+ await usingPlaygrounds(async (helper) => {
+ accs = await helper.arrange.createAccounts(new Array(accountsNumber).fill(balance), donor);
+ });
+ } else {
+ accs = accounts.splice(0, accountsNumber);
+ }
+ usedAccounts.push(...accs);
+ return accs;
+}
+// App promotion periods:
+// LOCKING_PERIOD = 12 blocks of relay
+// UNLOCKING_PERIOD = 6 blocks of parachain
+
+describe('App promotion', () => {
+ before(async function () {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]);
+ donor = await privateKey({url: import.meta.url});
+ palletAddress = helper.arrange.calculatePalletAddress('appstake');
+ palletAdmin = await privateKey('//PromotionAdmin');
+
+ nominal = helper.balance.getOneTokenNominal();
+
+ const accountBalances = new Array(200).fill(1000n);
+ accounts = await helper.arrange.createAccounts(accountBalances, donor); // create accounts-pool to speed up tests
+ });
+ });
+
+ afterEach(async () => {
+ await usingPlaygrounds(async (helper) => {
+ let unstakeTxs = [];
+ for(const account of usedAccounts) {
+ if(unstakeTxs.length === 3) {
+ await Promise.all(unstakeTxs);
+ unstakeTxs = [];
+ }
+ unstakeTxs.push(helper.staking.unstakeAll(account));
+ }
+ await Promise.all(unstakeTxs);
+ usedAccounts = [];
+ expect(await helper.staking.getTotalStaked()).to.eq(0n); // there are no active stakes after each test
+ // Make sure previousCalculatedRecord is None to avoid problem with payout stakers;
+ await helper.admin.payoutStakers(palletAdmin, 100);
+ expect((await helper.getApi().query.appPromotion.previousCalculatedRecord() as any).isNone).to.be.true;
+ });
+ });
+
+ describe('stake extrinsic', () => {
+ itSub('should "freeze" staking balance, add it to "staked" map, and increase "totalStaked" amount', async ({helper}) => {
+ const [staker, recepient] = await getAccounts(2);
+ const totalStakedBefore = await helper.staking.getTotalStaked();
+
+ // Minimum stake amount is 100:
+ await expect(helper.staking.stake(staker, 100n * nominal - 1n)).to.be.rejected;
+ await helper.staking.stake(staker, 100n * nominal);
+
+ // Staker balance is: frozen: 100, reserved: 0n...
+ // ...so he can not transfer 900
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.contain({frozen: 100n * nominal, reserved: 0n});
+ expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: 100n * nominal}]);
+ await expect(helper.balance.transferToSubstrate(staker, recepient.address, 900n * nominal)).to.be.rejectedWith(/^Token: Frozen$/);
+
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+ // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo?
+ expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 100n * nominal); // total tokens amount staked in app-promotion increased
+
+ await helper.staking.stake(staker, 200n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal);
+ const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(totalStakedPerBlock[0].amount).to.equal(100n * nominal);
+ expect(totalStakedPerBlock[1].amount).to.equal(200n * nominal);
+ });
+
+ [
+ {unstake: 'unstakeAll' as const},
+ {unstake: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.unstake}] should allow to create maximum 10 stakes for account`, async ({helper}) => {
+ const [staker] = await getAccounts(1, 2000n);
+ const ONE_STAKE = 100n * nominal;
+ for(let i = 0; i < 10; i++) {
+ await helper.staking.stake(staker, ONE_STAKE);
+ }
+
+ // can have 10 stakes
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(1000n * nominal);
+ expect(await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).to.have.length(10);
+
+ await expect(helper.staking.stake(staker, ONE_STAKE)).to.be.rejectedWith('appPromotion.NoPermission');
+
+ // After unstake can stake again
+
+ // CASE 1: unstakeAll
+ if(testCase.unstake === 'unstakeAll') {
+ await helper.staking.unstakeAll(staker);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
+ await helper.staking.stake(staker, 100n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.equal(100n * nominal);
+ }
+ // CASE 2: unstakePartial
+ else {
+ await helper.staking.unstakePartial(staker, ONE_STAKE);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(9);
+ await helper.staking.stake(staker, 100n * nominal);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(10);
+ await expect(helper.staking.stake(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.NoPermission');
+ await helper.staking.unstakePartial(staker, 150n * nominal);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(9);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.equal(850n * nominal);
+ }
+ });
+ });
+ // TODO: Now AppPromo makes freezes. Probably this test should be changed\removed.
+ itSub.skip('should allow to stake() if balance is locked with different id', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+
+ // staker has tokens locked with vesting id:
+ await helper.balance.vestedTransfer(donor, staker.address, {start: 0n, period: 1n, periodCount: 1n, perPeriod: 200n * nominal});
+ expect(await helper.balance.getSubstrateFull(staker.address))
+ .to.deep.contain({free: 1200n * nominal, frozen: 200n * nominal, reserved: 0n});
+
+ // Locked balance can be staked. staker can stake 1200 tokens (minus fee):
+ await helper.staking.stake(staker, 1000n * nominal);
+ await helper.staking.stake(staker, 199n * nominal);
+ // check balances
+ expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'ormlvest', amount: 200n * nominal, reasons: 'All'}]);
+ expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: 1199n * nominal}]);
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 1199n * nominal});
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(1199n);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(1199n * nominal);
+
+ // staker can unstake
+ await helper.staking.unstakeAll(staker);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(1199n * nominal);
+ const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+ await helper.wait.forParachainBlockNumber(pendingUnstake.block);
+
+ // check balances
+ expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'ormlvest', amount: 200n * nominal, reasons: 'All'}]);
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 200n * nominal});
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(1199n);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
+
+ // staker can transfer balances now
+ await helper.balance.transferToSubstrate(staker, donor.address, 900n * nominal);
+ });
+
+ itSub('should not allow to stake(), if stake amount is more than total free balance minus locked by staking', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+
+ // Can't stake full balance because Alice needs to pay some fee
+ await expect(helper.staking.stake(staker, 1000n * nominal)).to.be.rejected; // With('Arithmetic')
+ await helper.staking.stake(staker, 500n * nominal);
+
+ // Can't stake 500 tkn because Alice has Less than 500 transferable;
+ await expect(helper.staking.stake(staker, 500n * nominal)).to.be.rejected; // With('Arithmetic');
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(500n * nominal);
+ });
+
+ itSub('for different accounts in one block is possible', async ({helper}) => {
+ const crowd = await getAccounts(4);
+
+ const crowdStartsToStake = crowd.map(user => helper.staking.stake(user, 100n * nominal));
+ await expect(Promise.all(crowdStartsToStake)).to.be.fulfilled;
+
+ const crowdStakes = await Promise.all(crowd.map(address => helper.staking.getTotalStaked({Substrate: address.address})));
+ expect(crowdStakes).to.deep.equal([100n * nominal, 100n * nominal, 100n * nominal, 100n * nominal]);
+ });
+ });
+
+ describe('Unstaking', () => {
+ [
+ {method: 'unstakeAll' as const},
+ {method: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.method}] should move tokens to "pendingUnstake" and subtract it from totalStaked`, async ({helper}) => {
+ const [staker, recepient] = await getAccounts(2);
+ const totalStakedBefore = await helper.staking.getTotalStaked();
+ const STAKE_AMOUNT = 900n * nominal;
+
+ await helper.staking.stake(staker, STAKE_AMOUNT);
+ testCase.method === 'unstakeAll'
+ ? await helper.staking.unstakeAll(staker)
+ : await helper.staking.unstakePartial(staker, STAKE_AMOUNT);
+
+ // Right after unstake tokens are still locked
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
+ expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: STAKE_AMOUNT}]);
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: STAKE_AMOUNT});
+ // Staker can not transfer
+ await expect(helper.balance.transferToSubstrate(staker, recepient.address, 100n * nominal)).to.be.rejectedWith(/^Token: Frozen$/);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(STAKE_AMOUNT);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
+ expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore);
+ });
+ });
+
+ [
+ {method: 'unstakeAll' as const},
+ {method: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.method}] should unlock balance after unlocking period ends and remove it from "pendingUnstake"`, async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ testCase.method === 'unstakeAll'
+ ? await helper.staking.unstakeAll(staker)
+ : await helper.staking.unstakePartial(staker, 100n * nominal);
+ const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+
+ // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n
+ await helper.wait.forParachainBlockNumber(pendingUnstake.block);
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+
+ // staker can transfer:
+ await helper.balance.transferToSubstrate(staker, donor.address, 998n * nominal);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(1n);
+ });
+ });
+
+ [
+ {method: 'unstakeAll' as const},
+ {method: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.method}] should successfully unstake multiple stakes`, async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+ await helper.staking.stake(staker, 300n * nominal);
+
+ // staked: [100, 200, 300]; unstaked: 0
+ let totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
+ let pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+ let stakes = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(totalPendingUnstake).to.be.deep.equal(0n);
+ expect(pendingUnstake).to.be.deep.equal([]);
+ expect(stakes[0].amount).to.equal(100n * nominal);
+ expect(stakes[1].amount).to.equal(200n * nominal);
+ expect(stakes[2].amount).to.equal(300n * nominal);
+
+ // Can unstake multiple stakes
+ testCase.method === 'unstakeAll'
+ ? await helper.staking.unstakeAll(staker)
+ : await helper.staking.unstakePartial(staker, 600n * nominal);
+
+ pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+ totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
+ stakes = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(totalPendingUnstake).to.be.equal(600n * nominal);
+ expect(stakes).to.be.deep.equal([]);
+ expect(pendingUnstake[0].amount).to.equal(600n * nominal);
+
+ expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 600n * nominal});
+ expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+ await helper.wait.forParachainBlockNumber(pendingUnstake[0].block);
+ expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
+ expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+ });
+ });
+
+ [
+ {method: 'unstakeAll' as const},
+ {method: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.method}] should not have any effects if no active stakes`, async ({helper}) => {
+ const [staker] = await getAccounts(1);
+
+ // unstake has no effect if no stakes at all
+ testCase.method === 'unstakeAll'
+ ? await helper.staking.unstakeAll(staker)
+ : await expect(helper.staking.unstakePartial(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
+
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(0n);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); // TODO bigint closeTo helper
+
+ // TODO stake() unstake() waitUnstaked() unstake();
+
+ // can't unstake if there are only pendingUnstakes
+ await helper.staking.stake(staker, 100n * nominal);
+
+ if(testCase.method === 'unstakeAll') {
+ await helper.staking.unstakeAll(staker);
+ await helper.staking.unstakeAll(staker);
+ } else {
+ await helper.staking.unstakePartial(staker, 100n * nominal);
+ await expect(helper.staking.unstakePartial(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
+ }
+
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
+ });
+ });
+
+ [
+ {method: 'unstakeAll' as const},
+ {method: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.method}] should create different pending-unlock for each unlocking stake`, async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ testCase.method === 'unstakeAll'
+ ? await helper.staking.unstakeAll(staker)
+ : await helper.staking.unstakePartial(staker, 100n * nominal);
+ await helper.staking.stake(staker, 120n * nominal);
+ testCase.method === 'unstakeAll'
+ ? await helper.staking.unstakeAll(staker)
+ : await helper.staking.unstakePartial(staker, 120n * nominal);
+
+ const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+ expect(unstakingPerBlock).has.length(2);
+ expect(unstakingPerBlock[0].amount).to.equal(100n * nominal);
+ expect(unstakingPerBlock[1].amount).to.equal(120n * nominal);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.equal(0);
+ });
+ });
+
+ [
+ {method: 'unstakeAll' as const},
+ {method: 'unstakePartial' as const},
+ ].map(testCase => {
+ itSub(`[${testCase.method}] should be possible for 3 accounts in one block`, async ({helper}) => {
+ const stakers = await getAccounts(3);
+
+ await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
+ await Promise.all(stakers.map(staker => testCase.method === 'unstakeAll'
+ ? helper.staking.unstakeAll(staker)
+ : helper.staking.unstakePartial(staker, 100n * nominal)));
+
+ await Promise.all(stakers.map(async (staker) => {
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
+ }));
+ });
+ });
+
+ itSub('should not be possible for more than 3 accounts in one block', async ({helper}) => {
+ if(!await helper.arrange.isDevNode()) {
+ const stakers = await getAccounts(10);
+
+ await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
+ const unstakingResults = await Promise.allSettled(stakers.map((staker, i) => i % 2 === 0
+ ? helper.staking.unstakeAll(staker)
+ : helper.staking.unstakePartial(staker, 100n * nominal)));
+
+ const successfulUnstakes = unstakingResults.filter(result => result.status === 'fulfilled');
+ expect(successfulUnstakes).to.have.length(3);
+ }
+ });
+
+ itSub('Cannot partially unstake more than staked', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ // Staker stakes 300:
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+
+ // cannot usntake 300.00000...1
+ await expect(helper.staking.unstakePartial(staker, 300n * nominal + 1n)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(2);
+
+ await helper.staking.unstakePartial(staker, 150n * nominal);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(1);
+ await expect(helper.staking.unstakePartial(staker, 150n * nominal + 1n)).to.be.rejectedWith('appPromotion.InsufficientStakedBalance');
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(1);
+
+ // nothing broken, can unstake full amount:
+ await helper.staking.unstakePartial(staker, 150n * nominal);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).eq(0);
+ });
+
+ itSub('Can partially unstake arbitrary amount', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+
+ // 0. Staker cannot unstake negative amount
+ await expect(helper.staking.unstakePartial(staker, -1n)).to.be.rejected;
+
+ // 1. Staker can unstake 0 wei
+ await helper.staking.unstakePartial(staker, 0n);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(2);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(300n * nominal);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(0n);
+
+ // 2. Staker can unstake 1 wei
+ await helper.staking.unstakePartial(staker, 1n);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(2);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(300n * nominal - 1n);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(1n);
+ // 2.1 The oldest stake decreased:
+ let [stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(stake1.amount).to.eq(100n * nominal - 1n);
+ expect(stake2.amount).to.eq(200n * nominal);
+
+ // 3. Staker can unstake all but 1 wei
+ await helper.staking.unstakePartial(staker, 100n * nominal - 2n);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(2);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(200n * nominal + 1n);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(100n * nominal - 1n);
+ [stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(stake1.amount).to.eq(1n);
+ expect(stake2.amount).to.eq(200n * nominal);
+ });
+
+ itSub('can mix different type of unstakes', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+
+ await helper.staking.unstakePartial(staker, 50n * nominal);
+ await helper.staking.unstakeAll(staker);
+ expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(300n * nominal);
+
+ const [_unstake1, unstake2] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+ await helper.wait.forParachainBlockNumber(unstake2.block);
+
+ expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([]);
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(999n);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.eq(0n);
+ expect(await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).to.deep.eq([]);
+ });
+ });
+
+ describe('collection sponsoring', () => {
+ itSub('should actually sponsor transactions', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner, tokenSender, receiver] = await getAccounts(3);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'Name', description: 'Description', tokenPrefix: 'Prefix', limits: {sponsorTransferTimeout: 0}});
+ const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address});
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
+ const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);
+
+ await token.transfer(tokenSender, {Substrate: receiver.address});
+ expect (await token.getOwner()).to.be.deep.equal({Substrate: receiver.address});
+ const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress);
+
+ // senders balance the same, transaction has sponsored
+ expect (await helper.balance.getSubstrate(tokenSender.address)).to.be.equal(1000n * nominal);
+ expect (palletBalanceBefore > palletBalanceAfter).to.be.true;
+ });
+
+ itSub('can not be set by non admin', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner, nonAdmin] = await getAccounts(2);
+
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
+ expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled');
+ });
+
+ itSub('should set pallet address as confirmed admin', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner, oldSponsor] = await getAccounts(2);
+
+ // Can set sponsoring for collection without sponsor
+ const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.fulfilled;
+ expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+
+ // Can set sponsoring for collection with unconfirmed sponsor
+ const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: {Substrate: oldSponsor.address}});
+ expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address});
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.fulfilled;
+ expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+
+ // Can set sponsoring for collection with confirmed sponsor
+ const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: {Substrate: oldSponsor.address}});
+ await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor);
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.fulfilled;
+ expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+ });
+
+ itSub('can be overwritten by collection owner', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner, newSponsor] = await getAccounts(2);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ const collectionId = collection.collectionId;
+
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionId))).to.be.fulfilled;
+
+ // Collection limits still can be changed by the owner
+ expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true;
+ expect((await collection.getData())?.raw.limits.sponsorTransferTimeout).to.be.equal(0);
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+
+ // Collection sponsor can be changed too
+ expect((await collection.setSponsor(collectionOwner, newSponsor.address))).to.be.true;
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: newSponsor.address});
+ });
+
+ itSub('should not overwrite collection limits set by the owner earlier', async ({helper}) => {
+ const [owner] = await getAccounts(1);
+ const api = helper.getApi();
+ const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};
+ const collectionWithLimits = await helper.nft.mintCollection(owner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
+
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.fulfilled;
+ expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);
+ });
+
+ itSub('should reject transaction if collection doesn\'t exist', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner] = await getAccounts(1);
+
+ // collection has never existed
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(999999999))).to.be.rejected;
+ // collection has been burned
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ await collection.burn(collectionOwner);
+
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
+ });
+ });
+
+ describe('stopSponsoringCollection', () => {
+ itSub('can not be called by non-admin', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner, nonAdmin] = await getAccounts(2);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
+
+ await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+ });
+
+ itSub('should set sponsoring as disabled', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner, recepient] = await getAccounts(2);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}});
+ const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address});
+
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId));
+
+ expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');
+
+ // Transactions are not sponsored anymore:
+ const ownerBalanceBefore = await helper.balance.getSubstrate(collectionOwner.address);
+ await token.transfer(collectionOwner, {Substrate: recepient.address});
+ const ownerBalanceAfter = await helper.balance.getSubstrate(collectionOwner.address);
+ expect(ownerBalanceAfter < ownerBalanceBefore).to.be.equal(true);
+ });
+
+ itSub('should not affect collection which is not sponsored by pallete', async ({helper}) => {
+ const api = helper.getApi();
+ const [collectionOwner] = await getAccounts(1);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: {Substrate: collectionOwner.address}});
+ await collection.confirmSponsorship(collectionOwner);
+
+ await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address});
+ });
+
+ itSub('should reject transaction if collection does not exist', async ({helper}) => {
+ const [collectionOwner] = await getAccounts(1);
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await collection.burn(collectionOwner);
+ await expect(helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringCollection', [collection.collectionId], true)).to.be.rejectedWith('common.CollectionNotFound');
+ await expect(helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringCollection', [999_999_999], true)).to.be.rejectedWith('common.CollectionNotFound');
+ });
+ });
+
+ describe('contract sponsoring', () => {
+ itEth('should set palletes address as a sponsor', async ({helper}) => {
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]);
+
+ expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
+ expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
+ confirmed: {
+ substrate: palletAddress,
+ },
+ });
+ });
+
+ itEth('should overwrite sponsoring mode and existed sponsor', async ({helper}) => {
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+
+ await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
+
+ // Contract is self sponsored
+ expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.be.deep.equal({
+ confirmed: {
+ ethereum: flipper.options.address.toLowerCase(),
+ },
+ });
+
+ // set promotion sponsoring
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
+
+ // new sponsor is pallet address
+ expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
+ expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
+ confirmed: {
+ substrate: palletAddress,
+ },
+ });
+ });
+
+ itEth('can be overwritten by contract owner', async ({helper}) => {
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+
+ // contract sponsored by pallet
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
+
+ // owner sets self sponsoring
+ await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
+
+ expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
+ expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
+ confirmed: {
+ ethereum: flipper.options.address.toLowerCase(),
+ },
+ });
+ });
+
+ itEth('can not be set by non admin', async ({helper}) => {
+ const [nonAdmin] = await getAccounts(1);
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+
+ await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
+
+ // nonAdmin calls sponsorContract
+ await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission');
+
+ // contract still self-sponsored
+ expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
+ confirmed: {
+ ethereum: flipper.options.address.toLowerCase(),
+ },
+ });
+ });
+
+ itEth('should actually sponsor transactions', async ({helper}) => {
+ // Contract caller
+ const caller = await helper.eth.createAccountWithBalance(donor, 1000n);
+ const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);
+
+ // Deploy flipper
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+
+ // Owner sets to sponsor every tx
+ await contractHelper.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: contractOwner});
+ await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner});
+ await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address, 1000n); // transferBalanceToEth(api, alice, flipper.options.address, 1000n);
+
+ // Set promotion to the Flipper
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
+
+ // Caller calls Flipper
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ // The contracts and caller balances have not changed
+ const callerBalance = await helper.balance.getEthereum(caller);
+ const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address);
+ expect(callerBalance).to.be.equal(1000n * nominal);
+ expect(1000n * nominal === contractBalanceAfter).to.be.true;
+
+ // The pallet balance has decreased
+ const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress);
+ expect(palletBalanceAfter < palletBalanceBefore).to.be.true;
+ });
+ });
+
+ describe('stopSponsoringContract', () => {
+ itEth('should remove pallet address from contract sponsors', async ({helper}) => {
+ const caller = await helper.eth.createAccountWithBalance(donor, 1000n);
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner);
+ await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+
+ await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner});
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true);
+
+ expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
+ expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
+ disabled: null,
+ });
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ const callerBalance = await helper.balance.getEthereum(caller);
+ const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address);
+
+ // caller payed for call
+ expect(1000n * nominal > callerBalance).to.be.true;
+ expect(contractBalanceAfter).to.be.equal(100n * nominal);
+ });
+
+ itEth('can not be called by non-admin', async ({helper}) => {
+ const [nonAdmin] = await getAccounts(1);
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner);
+
+ await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]);
+ await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address]))
+ .to.be.rejectedWith(/appPromotion\.NoPermission/);
+ });
+
+ itEth('should not affect a contract which is not sponsored by pallete', async ({helper}) => {
+ const [nonAdmin] = await getAccounts(1);
+ const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
+ const flipper = await helper.eth.deployFlipper(contractOwner);
+ const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
+ await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
+
+ await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission');
+ });
+ });
+
+ describe('payoutStakers', () => {
+ itSub('can not be called by non admin', async ({helper}) => {
+ const [nonAdmin] = await getAccounts(1);
+ await expect(helper.admin.payoutStakers(nonAdmin, 100)).to.be.rejectedWith('appPromotion.NoPermission');
+ });
+
+ itSub('should increase total staked', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ const totalStakedBefore = await helper.staking.getTotalStaked();
+ await helper.staking.stake(staker, 100n * nominal);
+
+ // Wait for rewards and pay
+ const [stakedInBlock] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock.block));
+
+ const payout = await helper.admin.payoutStakers(palletAdmin, 100);
+ const totalPayout = payout.reduce((prev, payout) => prev + payout.payout, 0n);
+ const stakerReward = payout.find(p => p.staker === staker.address);
+
+ expect(stakerReward?.payout).to.eq(calculateIncome(100n * nominal) - (100n * nominal));
+
+ const totalStakedAfter = await helper.staking.getTotalStaked();
+ expect(totalStakedAfter).to.equal(totalStakedBefore + (100n * nominal) + totalPayout);
+ // staker can unstake
+ await helper.staking.unstakeAll(staker);
+ expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedAfter - calculateIncome(100n * nominal));
+ });
+
+ itSub('should credit 0.05% for staking period', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+
+ await waitPromotionPeriodDoesntEnd(helper);
+
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+
+ // wait rewards are available:
+ const [_stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
+
+ const payoutToStaker = (await helper.admin.payoutStakers(palletAdmin, 100)).find((payout) => payout.staker === staker.address)!.payout;
+ expect(payoutToStaker + 300n * nominal).to.equal(calculateIncome(300n * nominal));
+
+ const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ const income1 = calculateIncome(100n * nominal);
+ const income2 = calculateIncome(200n * nominal);
+ expect(totalStakedPerBlock[0].amount).to.equal(income1);
+ expect(totalStakedPerBlock[1].amount).to.equal(income2);
+
+ const stakerBalance = await helper.balance.getSubstrateFull(staker.address);
+ expect(stakerBalance).to.contain({frozen: income1 + income2, reserved: 0n});
+ expect(stakerBalance.free / nominal).to.eq(999n);
+ });
+
+ itSub('shoud be paid for more than one period if payments was missed', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+
+ await helper.staking.stake(staker, 100n * nominal);
+ // wait for two rewards are available:
+ let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
+
+ await helper.admin.payoutStakers(palletAdmin, 100);
+ [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ const frozenBalanceShouldBe = calculateIncome(100n * nominal, 2);
+ expect(stake.amount).to.be.equal(frozenBalanceShouldBe);
+
+ const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);
+
+ expect(stakerFullBalance).to.contain({reserved: 0n, frozen: frozenBalanceShouldBe});
+ });
+
+ itSub('should not be credited for pending-unstaked tokens', async ({helper}) => {
+ // staker unstakes before rewards been payed
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
+ await helper.staking.unstakeAll(staker);
+
+ // so he did not receive any rewards
+ const totalBalanceBefore = await helper.balance.getSubstrate(staker.address);
+ await helper.admin.payoutStakers(palletAdmin, 100);
+ const totalBalanceAfter = await helper.balance.getSubstrate(staker.address);
+
+ expect(totalBalanceBefore).to.be.equal(totalBalanceAfter);
+ });
+
+ itSub('should bring compound interest', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+
+ await helper.staking.stake(staker, 100n * nominal);
+
+ let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block));
+
+ await helper.admin.payoutStakers(palletAdmin, 100);
+ [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(stake.amount).to.equal(calculateIncome(100n * nominal));
+
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
+ await helper.admin.payoutStakers(palletAdmin, 100);
+ [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(stake.amount).to.equal(calculateIncome(100n * nominal, 2));
+ });
+
+ itSub('can calculate reward for tiny stake', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.unstakePartial(staker, 100n * nominal - 1n);
+
+ const [_stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
+
+ const stakerPayout = await payUntilRewardFor(staker.address, helper);
+ expect(stakerPayout.stake).to.eq(100n * nominal + 1n);
+ });
+
+ itSub('can eventually pay all rewards', async ({helper}) => {
+ const stakers = await getAccounts(30);
+ // Create 30 stakes:
+ await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
+
+ let unstakingTxs = [];
+ for(const staker of stakers) {
+ if(unstakingTxs.length == 3) {
+ await Promise.all(unstakingTxs);
+ unstakingTxs = [];
+ }
+ unstakingTxs.push(helper.staking.unstakePartial(staker, 100n * nominal - 1n));
+ }
+
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block));
+
+ let payouts;
+ do {
+ payouts = await helper.admin.payoutStakers(palletAdmin, 20);
+ } while(payouts.length !== 0);
+ });
+ });
+
+ describe('events', () => {
+ [
+ {method: 'unstakePartial' as const},
+ {method: 'unstakeAll' as const},
+ ].map(testCase => {
+ itSub(testCase.method, async ({helper}) => {
+ const unstakeParams: [] | [bigint] = testCase.method === 'unstakePartial'
+ ? [100n * nominal - 1n]
+ : [];
+ const [staker] = await getAccounts(1);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+ const {result} = await helper.executeExtrinsic(staker, `api.tx.appPromotion.${testCase.method}`, unstakeParams);
+
+ const event = result.events.find(e => e.event.section === 'appPromotion' && e.event.method === 'Unstake');
+ const unstakerEvents = event?.event.data[0].toString();
+ const unstakedEvents = BigInt(event?.event.data[1].toString());
+ expect(unstakerEvents).to.eq(staker.address);
+ expect(unstakedEvents).to.eq(testCase.method === 'unstakeAll' ? 300n * nominal : 100n * nominal - 1n);
+ });
+ });
+
+ itSub('stake', async ({helper}) => {
+ const [staker] = await getAccounts(1);
+ const {result} = await helper.executeExtrinsic(staker, 'api.tx.appPromotion.stake', [100n * nominal]);
+
+ const event = result.events.find(e => e.event.section === 'appPromotion' && e.event.method === 'Stake');
+ const stakerEvents = event?.event.data[0].toString();
+ const stakedEvents = BigInt(event?.event.data[1].toString());
+ expect(stakerEvents).to.eq(staker.address);
+ expect(stakedEvents).to.eq(100n * nominal);
+ });
+
+ // Flaky
+ itSub.skip('payoutStakers', async ({helper}) => {
+ const [staker1, staker2] = await getAccounts(2);
+ const STAKE1 = 100n * nominal;
+ const STAKE2 = 200n * nominal;
+ await helper.staking.stake(staker1, STAKE1);
+ await helper.staking.stake(staker2, STAKE2);
+
+ const [stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker2.address});
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
+
+ const results = await helper.admin.payoutStakers(palletAdmin, 100);
+ const stakersEvents = results.filter(ev => ev.staker === staker1.address || ev.staker === staker2.address);
+ expect(stakersEvents).has.length(2);
+ expect(stakersEvents).has.not.ordered.members([
+ {staker: staker1.address, stake: STAKE1, payout: calculateIncome(STAKE1) - STAKE1},
+ {staker: staker2.address, stake: STAKE2, payout: calculateIncome(STAKE2) - STAKE2},
+ ]);
+ });
+ });
+});
+
+
+// Sometimes is is required to make a cycle in order for the payment to be calculated for a specific account
+async function payUntilRewardFor(account: string, helper: DevUniqueHelper) {
+ for(let i = 0; i < 3; i++) {
+ const payouts = await helper.admin.payoutStakers(palletAdmin, 100);
+ const accountPayout = payouts.find(p => p.staker === account);
+ if(accountPayout) return accountPayout;
+ }
+ throw Error(`Cannot find payout for ${account}`);
+}
+
+function calculateIncome(base: bigint, iter = 0, calcPeriod: bigint = UNLOCKING_PERIOD): bigint {
+ const DAY = 7200n;
+ const ACCURACY = 1_000_000_000n;
+ // 5n / 10_000n = 0.05% p/day
+ const income = base + base * (ACCURACY * (calcPeriod * 5n) / (10_000n * DAY)) / ACCURACY ;
+
+ if(iter > 1) {
+ return calculateIncome(income, iter - 1, calcPeriod);
+ } else return income;
+}
+
+function rewardAvailableInBlock(stakedInBlock: bigint) {
+ if(stakedInBlock % LOCKING_PERIOD === 0n) return stakedInBlock + LOCKING_PERIOD;
+ return (stakedInBlock - stakedInBlock % LOCKING_PERIOD) + (LOCKING_PERIOD * 2n);
+}
+
+// Wait while promotion period less than specified block, to avoid boundary cases
+// 0 if this should be the beginning of the period.
+async function waitPromotionPeriodDoesntEnd(helper: DevUniqueHelper, waitBlockLessThan = LOCKING_PERIOD / 3n) {
+ const relayBlockNumber = (await helper.callRpc('api.query.parachainSystem.validationData', [])).value.relayParentNumber.toNumber(); // await helper.chain.getLatestBlockNumber();
+ const currentPeriodBlock = BigInt(relayBlockNumber) % LOCKING_PERIOD;
+
+ if(currentPeriodBlock > waitBlockLessThan) {
+ await helper.wait.forRelayBlockNumber(BigInt(relayBlockNumber) + LOCKING_PERIOD - currentPeriodBlock);
+ }
+}
js-packages/tests/sub/nesting/admin.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/nesting/admin.test.ts
@@ -0,0 +1,87 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
+import {CrossAccountId} from '@unique/playgrounds/unique.js';
+
+describe('Nesting by collection admin', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 10n, 10n], donor);
+ });
+ });
+
+ [
+ {restricted: true},
+ {restricted: false},
+ ].map(testCase => {
+ itSub(`can nest tokens if "collectionAdmin" permission set ${testCase.restricted ? ', in restricted mode' : ''}`, async ({helper}) => {
+ const collectionA = await helper.nft.mintCollection(alice);
+ await collectionA.addAdmin(alice, {Substrate: bob.address});
+ const collectionB = await helper.nft.mintCollection(alice);
+ await collectionB.addAdmin(alice, {Substrate: bob.address});
+ // Collection has permission for collectionAdmin to nest:
+ await collectionA.setPermissions(alice, {nesting:
+ {collectionAdmin: true, restricted: testCase.restricted ? [collectionA.collectionId, collectionB.collectionId] : null},
+ });
+ // Token for nesting in from collectionA:
+ const targetTokenA = await collectionA.mintToken(alice, {Substrate: charlie.address});
+
+ // 1. Create an immediately nested tokens:
+ // 1.1 From own collection:
+ const nestedTokenA = await collectionA.mintToken(bob, targetTokenA.nestingAccount());
+ // 1.2 From different collection:
+ const nestedTokenB = await collectionB.mintToken(bob, targetTokenA.nestingAccount());
+ expect(await nestedTokenA.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
+ expect(await nestedTokenA.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenA.nestingAccount()));
+ expect(await nestedTokenB.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
+ expect(await nestedTokenB.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenA.nestingAccount()));
+
+ // 2. Create a token to be nested and nest:
+ const newNestedTokenA = await collectionA.mintToken(bob);
+ const newNestedTokenB = await collectionB.mintToken(bob);
+ // 2.1 From own collection:
+ await newNestedTokenA.nest(bob, targetTokenA);
+ // 2.2 From different collection:
+ await newNestedTokenB.nest(bob, targetTokenA);
+ expect(await newNestedTokenB.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
+ expect(await newNestedTokenB.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenA.nestingAccount()));
+ });
+ });
+
+ itSub('can operate together with token owner if "collectionAdmin" and "tokenOwner" permissions set', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {collectionAdmin: true, tokenOwner: true}}});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ const targetToken = await collection.mintToken(alice, {Substrate: charlie.address});
+
+ // Admin can create an immediately nested token:
+ const nestedToken = await collection.mintToken(bob, targetToken.nestingAccount());
+ expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
+ expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+
+ // Owner can create and and nest:
+ const newToken = await collection.mintToken(alice, {Substrate: charlie.address});
+ await newToken.nest(charlie, targetToken);
+ expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
+ expect(await newToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+ });
+});
js-packages/tests/sub/nesting/common.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/nesting/common.test.ts
@@ -0,0 +1,164 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
+import {CrossAccountId, UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/unique.js';
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
+
+describe('Common nesting tests', () => {
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
+ {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
+ {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase => {
+ itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
+ // Only NFT can be target for nesting in
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+
+ const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ });
+
+ // 1. Bob can immediately create nested token:
+ const nestedToken1 = testCase.mode === 'nft'
+ ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
+ : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
+ expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await nestedToken1.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenBob.nestingAccount()));
+
+ // 2. Bob can mint and nest token:
+ const nestedToken2 = await collectionForNesting.mintToken(bob);
+ await nestedToken2.nest(bob, targetTokenBob);
+ expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await nestedToken2.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetTokenBob.nestingAccount()));
+ });
+ });
+
+
+ [
+ {restrictedMode: true},
+ {restrictedMode: false},
+ ].map(testCase => {
+ itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
+ // Only NFT allows nesting, permissions should be set:
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+
+ const collectionForNesting = await helper.ft.mintCollection(bob);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ });
+
+ // 1. Alice can immediately create nested tokens:
+ await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
+ expect(await collectionForNesting.getTop10Owners()).deep.eq([CrossAccountId.toLowerCase(targetTokenBob.nestingAccount())]);
+ expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
+
+ // 2. Alice can mint and nest token:
+ await collectionForNesting.mint(bob, 100n);
+ await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
+ expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
+ expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);
+ });
+ });
+
+ [
+ {restrictedMode: true},
+ {restrictedMode: false},
+ ].map(testCase => {
+ itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
+ // Only NFT allows nesting, permissions should be set:
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+ expect(await targetTokenBob.getChildren()).to.be.empty;
+
+ const collectionForNesting = helper.ft.getCollectionObject(0);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ });
+
+ // Bob can nest Native FT into their NFT:
+ await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
+ expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
+ // Native FT should't be visible in NFT children:
+ expect(await targetTokenBob.getChildren()).to.be.deep.equal([]);
+ });
+ });
+
+
+ itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
+ const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const tokenA = await collectionToNest.mintToken(alice);
+ const tokenB = await collectionToNest.mintToken(alice);
+
+ // Create a nested token
+ const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
+
+ const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
+ const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
+ await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
+ await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
+ expect(await nestedNFT.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(tokenA.nestingAccount()));
+ expect(await nestedRFT.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(tokenA.nestingAccount()));
+ expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
+ expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
+
+ expect(await tokenA.getChildren()).to.be.length(3);
+ expect(await tokenB.getChildren()).to.be.length(0);
+
+ // Transfer the nested token to another token
+ await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
+ await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+ await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+ await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+
+ expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
+ expect(await nestedNFT.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(tokenB.nestingAccount()));
+
+ expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);
+ expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);
+
+ expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
+ expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
+
+ expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
+ expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
+
+ // RFT, FT, and without native FT
+ expect(await tokenA.getChildren()).to.be.length(2);
+ // NFT, RFT, FT, and without native FT
+ expect(await tokenB.getChildren()).to.be.length(3);
+ });
+});
js-packages/tests/sub/nesting/e2e.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/nesting/e2e.test.ts
@@ -0,0 +1,145 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
+import {CrossAccountId} from '@unique/playgrounds/unique.js';
+
+describe('Composite nesting tests', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+ });
+ });
+
+ itSub('Checks token children e2e', async ({helper}) => {
+ const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const collectionB = await helper.ft.mintCollection(alice);
+ const collectionC = await helper.rft.mintCollection(alice);
+ const collectionNative = helper.ft.getCollectionObject(0);
+
+ const targetToken = await collectionA.mintToken(alice);
+ expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation');
+
+ // Create a nested NFT token
+ const tokenA = await collectionA.mintToken(alice, targetToken.nestingAccount());
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ ]).and.has.length(1);
+
+ // Create then nest
+ const tokenB = await collectionA.mintToken(alice);
+ await tokenB.nest(alice, targetToken);
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ {tokenId: tokenB.tokenId, collectionId: collectionA.collectionId},
+ ]).and.has.length(2);
+
+ // Move token B to a different user outside the nesting tree
+ await tokenB.unnest(alice, targetToken, {Substrate: bob.address});
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ ]).and.has.length(1);
+
+ // Create a fungible token in another collection and then nest
+ await collectionB.mint(alice, 10n);
+ await collectionB.transfer(alice, targetToken.nestingAccount(), 2n);
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ ]).and.has.length(2);
+
+ // Create a refungible token in another collection and then nest
+ const tokenC = await collectionC.mintToken(alice, 10n);
+ await tokenC.transfer(alice, targetToken.nestingAccount(), 2n);
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
+ ]).and.has.length(3);
+
+ // Nest native fungible token into another collection
+ await collectionNative.transfer(alice, targetToken.nestingAccount(), 2n);
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
+ ]).and.has.length(3);
+
+ // Burn all nested pieces
+ await tokenC.burnFrom(alice, targetToken.nestingAccount(), 2n);
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ ])
+ .and.has.length(2);
+
+ // Move part of the fungible token inside token A deeper in the nesting tree
+ await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
+ expect(await targetToken.getChildren()).to.be.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ ]).and.has.length(2);
+ // Nested token also has children now:
+ expect(await tokenA.getChildren()).to.have.deep.members([
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ ]).and.has.length(1);
+
+ // Move the remaining part of the fungible token inside token A deeper in the nesting tree
+ await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
+ expect(await targetToken.getChildren()).to.have.deep.members([
+ {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
+ ]).and.has.length(1);
+ expect(await tokenA.getChildren()).to.have.deep.members([
+ {tokenId: 0, collectionId: collectionB.collectionId},
+ ]).and.has.length(1);
+ });
+
+ /// TODO review this test
+ itSub('Performs the full suite: bundles a token, transfers, and unnests', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ // Create an immediately nested token
+ const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+ expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
+ expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+
+ // Create a token to be nested
+ const newToken = await collection.mintToken(alice);
+
+ // Nest
+ await newToken.nest(alice, targetToken);
+ expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
+ expect(await newToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+
+ // Move bundle to different user
+ await targetToken.transfer(alice, {Substrate: bob.address});
+ expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+ expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await newToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+
+ // Unnest
+ await newToken.unnest(bob, targetToken, {Substrate: bob.address});
+ expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await newToken.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ });
+});
js-packages/tests/sub/nesting/nesting.negative.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/nesting/nesting.negative.test.ts
@@ -0,0 +1,294 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
+import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '@unique/playgrounds/unique.js';
+import {itEth} from '../../eth/util/index.js';
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
+let charlie: IKeyringPair;
+
+describe('Negative Test: Nesting', () => {
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ [
+ {mode: 'nft' as const, requiredPallets: []},
+ {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase => {
+ itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {
+ // Create default collection, permissions are not set:
+ const aliceNFTCollection = await helper.nft.mintCollection(alice);
+ const targetToken = await aliceNFTCollection.mintToken(alice);
+
+ const collectionForNesting = await helper[testCase.mode].mintCollection(alice);
+
+ // 1. Alice cannot create immediately nested tokens:
+ const nestingTx = testCase.mode === 'nft'
+ ? (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())
+ : (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());
+ await expect(nestingTx).to.be.rejectedWith('common.UserIsNotAllowedToNest');
+
+ // 2. Alice cannot mint and nest token:
+ const nestedToken2 = await collectionForNesting.mintToken(alice);
+ await expect(nestedToken2.nest(alice, targetToken)).to.be.rejectedWith('common.UserIsNotAllowedToNest');
+ });
+ });
+
+ [
+ {mode: 'ft'},
+ {mode: 'nativeFt'},
+ ].map(testCase => {
+ itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled (except for native fungible collection)`, async ({helper}) => {
+ // Create default collection, permissions are not set:
+ const aliceNFTCollection = await helper.nft.mintCollection(alice);
+ const targetToken = await aliceNFTCollection.mintToken(alice);
+
+ const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);
+
+ // Alice cannot create immediately nested tokens:
+ if(testCase.mode === 'ft') {
+ await expect(collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest');
+ } else {
+ await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.not.rejected;
+ }
+
+ // Alice can't mint and nest tokens:
+ if(testCase.mode === 'ft') {
+ await collectionForNesting.mint(alice, 100n);
+ }
+
+ if(testCase.mode === 'ft') {
+ await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');
+ } else {
+ await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.not.rejected;
+ }
+ });
+ });
+
+ [
+ {mode: 'nft' as const},
+ {mode: 'rft' as const},
+ {mode: 'ft' as const},
+ {mode: 'native ft' as const},
+ ].map(testCase => {
+ itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens (except for native fungible collection)`, async ({helper}) => {
+ const targetCollection = await helper.nft.mintCollection(alice, {permissions:
+ {nesting: {tokenOwner: true, collectionAdmin: true}},
+ });
+ const targetToken = await targetCollection.mintToken(alice);
+
+ const nestedCollectionBob = await (
+ testCase.mode === 'native ft'
+ ? helper.ft.getCollectionObject(0)
+ : helper[testCase.mode].mintCollection(bob)
+ );
+
+ let nestedTokenBob: UniqueNFToken | UniqueRFToken;
+ switch (testCase.mode) {
+ case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;
+ case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;
+ case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;
+ case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;
+ }
+
+ // Bob non-owner of targetToken and non admin of targetCollection, so
+ // 1. cannot mint nested token:
+ switch (testCase.mode) {
+ case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
+ case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
+ case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
+ case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;
+ }
+
+ // 2. cannot nest existing token:
+ switch (testCase.mode) {
+ case 'nft':
+ case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
+ case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
+ case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.not.rejected; break;
+ }
+ });
+ });
+
+ [
+ {mode: 'nft' as const, nesting: {tokenOwner: true, collectionAdmin: false}},
+ {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},
+ ].map(testCase => {
+ itSub(`${testCase.nesting.tokenOwner ? 'Admin' : 'Token owner'} cannot nest when only ${testCase.nesting.tokenOwner ? 'tokenOwner' : 'collectionAdmin'} is allowed`, async ({helper}) => {
+ // Create collection with tokenOwner or create collection with collectionAdmin permission:
+ const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});
+ const targetTokenCharlie = await targetCollection.mintToken(alice, {Substrate: charlie.address});
+ await targetCollection.addAdmin(alice, {Substrate: bob.address});
+
+ const nestedCollectionCharlie = await helper[testCase.mode].mintCollection(charlie);
+ const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);
+ // if nesting permissions restricted for token owner – minter is bob (admin),
+ // if collectionAdmin – charlie (owner)
+ testCase.nesting.tokenOwner
+ ? await expect(nestedCollectionBob.mintToken(bob, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)
+ : await expect(nestedCollectionCharlie.mintToken(charlie, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);
+ });
+ });
+
+ itSub.ifWithPallets('Cannot nest in non existing token (except for native fungible collection)', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice);
+ // To avoid UserIsNotAllowedToNest error
+ await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});
+
+ // The list of non-existing tokens:
+ const tokenFromNonExistingCollection = helper.nft.getTokenObject(9999999, 1);
+ const tokenBurnt = await collection.mintToken(alice);
+ await tokenBurnt.burn(alice);
+ const tokenNotMintedYet = helper.nft.getTokenObject(collection.collectionId, 2);
+
+ // The list of collections to nest tokens from:
+ const nftCollectionForNesting = await helper.nft.mintCollection(alice);
+ const rftCollectionForNesting = await helper.rft.mintCollection(alice);
+ const ftCollectionForNesting = await helper.ft.mintCollection(alice);
+ const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);
+
+ const testCases = [
+ {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},
+ {token: tokenBurnt, error: 'TokenNotFound'},
+ {token: tokenNotMintedYet, error: 'TokenNotFound'},
+ ];
+
+ for(const testCase of testCases) {
+ // 1. Alice cannot create nested token to non-existing token
+ await expect(nftCollectionForNesting.mintToken(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
+ await expect(rftCollectionForNesting.mintToken(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
+ await expect(ftCollectionForNesting.mint(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
+
+ // 2. Alice cannot mint and nest token:
+ const nft = await nftCollectionForNesting.mintToken(alice);
+ const rft = await rftCollectionForNesting.mintToken(alice, 100n);
+ await ftCollectionForNesting.mint(alice, 100n);
+ await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
+ await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
+ await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);
+ await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.not.rejected;
+ }
+ });
+
+ itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {
+ const existingCollection = await helper.nft.mintCollection(alice);
+ const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);
+ const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);
+
+ const nftCollectionForNesting = await helper.nft.mintCollection(alice);
+
+ // 1. Alice cannot create nested token to collection address
+ await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
+ await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
+
+ // 2. Alice cannot mint and nest token to collection address:
+ const nft = await nftCollectionForNesting.mintToken(alice);
+ await expect(nft.transfer(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
+ await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
+ });
+
+ itEth.ifWithPallets('Cannot nest in RFT or FT (except for native fungible collection)', [Pallets.ReFungible], async ({helper}) => {
+ // Create default collection, permissions are not set:
+ const rftCollection = await helper.rft.mintCollection(alice);
+ const ftCollection = await helper.ft.mintCollection(alice);
+ const nativeFtCollection = helper.ft.getCollectionObject(0);
+
+ const rftToken = await rftCollection.mintToken(alice);
+ await ftCollection.mint(alice, 100n);
+
+ const collectionForNesting = await helper.nft.mintCollection(alice);
+
+ // 1. Alice cannot create immediately nested tokens:
+ await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');
+ await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');
+ await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');
+
+ // 2. Alice cannot mint and nest token:
+ const nestedToken2 = await collectionForNesting.mintToken(alice);
+ await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');
+ await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');
+ await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.not.rejected;
+ });
+
+ itSub('Cannot nest in restricted collection if collection is not in the list (except native fungible collection)', async ({helper}) => {
+ const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);
+ const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);
+ const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);
+ const notAllowedCollectionFT = await helper.ft.mintCollection(alice);
+ const allowedCollectionNativeFT = helper.ft.getCollectionObject(0);
+
+ // Collection restricted to allowedCollectionId
+ const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:
+ {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},
+ });
+ // Create collection with restricted nesting -- even self is not allowed
+ const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:
+ {nesting: {tokenOwner: true, restricted: []}},
+ });
+
+ const targetTokenA = await restrictedCollectionA.mintToken(alice);
+ const targetTokenB = await restrictedCollectionB.mintToken(alice);
+
+ // 1. Cannot mint in own collection after allowlisting the accounts:
+ await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+
+ // 2. Cannot mint from notAllowedCollection:
+ await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
+ await expect(allowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.not.rejected;
+ await expect(allowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.not.rejected;
+ });
+
+ itSub('Cannot create nesting chains greater than 5', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ let token = await collection.mintToken(alice);
+
+ const maxNestingLevel = 5;
+
+ // Create a nested-token matryoshka
+ for(let i = 0; i < maxNestingLevel; i++) {
+ token = await collection.mintToken(alice, token.nestingAccount());
+ }
+
+ // The nesting depth is limited by `maxNestingLevel`
+ // 1. Cannot mint:
+ await expect(collection.mintToken(alice, token.nestingAccount()))
+ .to.be.rejectedWith(/structure\.DepthLimit/);
+ // 2. Cannot transfer:
+ const anotherToken = await collection.mintToken(alice);
+ await expect(anotherToken.transfer(alice, token.nestingAccount()))
+ .to.be.rejectedWith(/structure\.DepthLimit/);
+ // 3. Cannot nest FT pieces:
+ const ftCollection = await helper.ft.mintCollection(alice);
+ await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))
+ .to.be.rejectedWith(/structure\.DepthLimit/);
+
+ expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
+ expect(await token.getChildren()).to.has.length(0);
+ });
+});
js-packages/tests/sub/nesting/refungible.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/nesting/refungible.test.ts
@@ -0,0 +1,61 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
+
+describe('ReFungible-specific nesting tests', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([200n], donor);
+ });
+ });
+
+ itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice, {
+ permissions: {
+ nesting: {
+ tokenOwner: true,
+ },
+ },
+ });
+ const collectionRFT = await helper.rft.mintCollection(alice);
+
+ const nft = await collectionNFT.mintToken(alice, {Substrate: alice.address});
+ const rft = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
+
+ expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+
+ await rft.transfer(alice, nft.nestingAccount(), 40n);
+
+ expect(await rft.getTopmostOwner()).deep.equal(null);
+
+ await rft.transfer(alice, nft.nestingAccount(), 60n);
+
+ expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+
+ await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 30n);
+
+ expect(await rft.getTopmostOwner()).deep.equal(null);
+
+ await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 70n);
+
+ expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+ });
+});
js-packages/tests/sub/nesting/unnesting.negative.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/nesting/unnesting.negative.test.ts
@@ -0,0 +1,88 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
+import {CrossAccountId} from '@unique/playgrounds/unique.js';
+
+describe('Negative Test: Unnesting', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 50n], donor);
+ });
+ });
+
+ // TODO: make this test a bit more generic
+ itSub('Admin (NFT): disallows an Admin to unnest someone else\'s token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {limits: {ownerCanTransfer: true}, permissions: {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true}}});
+ //await collection.addAdmin(alice, {Substrate: bob.address});
+ const targetToken = await collection.mintToken(alice, {Substrate: bob.address});
+ await collection.addToAllowList(alice, {Substrate: bob.address});
+ await collection.addToAllowList(alice, targetToken.nestingAccount());
+
+ // Try to nest somebody else's token
+ const newToken = await collection.mintToken(bob);
+ await expect(newToken.nest(alice, targetToken))
+ .to.be.rejectedWith(/common\.NoPermission/);
+
+ // Try to unnest a token belonging to someone else as collection admin
+ const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+ await expect(nestedToken.unnest(alice, targetToken, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.AddressNotInAllowlist/);
+
+ expect(await targetToken.getChildren()).to.be.length(1);
+ expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+ });
+
+ [
+ {mode: 'ft' as const},
+ {mode: 'native ft' as const},
+ ].map(md => [
+ {mode: md.mode, restrictedMode: true},
+ {mode: md.mode, restrictedMode: false},
+ ].map(testCase => {
+ itSub(`Fungible: disallows a non-Owner to unnest someone else's token [${testCase.mode}${testCase.restrictedMode ? ' (Restricted nesting)' : ''}]`, async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice);
+ const collectionFT = await (
+ testCase.mode === 'ft'
+ ? helper.ft.mintCollection(alice)
+ : helper.ft.getCollectionObject(0)
+ );
+ const targetToken = await collectionNFT.mintToken(alice, {Substrate: bob.address});
+
+ await collectionNFT.setPermissions(alice, {nesting: {
+ collectionAdmin: true, tokenOwner: true, restricted: testCase.restrictedMode ? [collectionFT.collectionId] : null,
+ }});
+
+ // Nest some tokens as Alice into Bob's token
+ await (
+ testCase.mode === 'ft'
+ ? collectionFT.mint(alice, 5n, targetToken.nestingAccount())
+ : collectionFT.transfer(alice, targetToken.nestingAccount(), 5n)
+ );
+
+ // Try to pull it out as Alice still
+ await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: bob.address}, 1n))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);
+ });
+ }));
+});
js-packages/tests/sub/refungible/burn.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/refungible/burn.test.ts
@@ -0,0 +1,127 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../../util/index.js';
+
+describe('Refungible: burn', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+ });
+ });
+
+ itSub('can burn some pieces', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n);
+ await token.burn(alice, 99n);
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(1n);
+ });
+
+ itSub('can burn all pieces', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n);
+
+ await token.burn(alice, 100n);
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.false;
+ });
+
+ itSub('burn pieces for multiple users', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+
+ await token.transfer(alice, {Substrate: bob.address}, 60n);
+
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(40n);
+ expect(await token.getBalance({Substrate: bob.address})).to.be.equal(60n);
+
+ await token.burn(alice, 40n);
+
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(0n);
+
+ await token.burn(bob, 59n);
+
+ expect(await token.getBalance({Substrate: bob.address})).to.be.equal(1n);
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.true;
+
+ await token.burn(bob, 1n);
+
+ expect(await collection.doesTokenExist(token.tokenId)).to.be.false;
+ });
+
+ itSub('burn pieces by admin', async function({helper}) {
+ const collection = await helper.rft.mintCollection(alice);
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+ const token = await collection.mintToken(alice, 100n);
+
+ await token.burnFrom(bob, {Substrate: alice.address}, 100n);
+ expect(await token.doesExist()).to.be.false;
+ });
+});
+
+describe('Refungible: burn negative tests', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
+ });
+
+ itSub('cannot burn non-owned token pieces', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice);
+ const aliceToken = await collection.mintToken(alice, 10n, {Substrate: alice.address});
+ const bobToken = await collection.mintToken(alice, 10n, {Substrate: bob.address});
+
+ // 1. Cannot burn non-owned token:
+ await expect(bobToken.burn(alice, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
+ await expect(bobToken.burn(alice, 5n)).to.be.rejectedWith('common.TokenValueTooLow');
+ // 2. Cannot burn non-existing token:
+ await expect(helper.rft.burnToken(alice, 99999, 10)).to.be.rejectedWith('common.CollectionNotFound');
+ await expect(helper.rft.burnToken(alice, collection.collectionId, 99999)).to.be.rejectedWith('common.TokenValueTooLow');
+ // 3. Can burn zero amount of owned tokens (EIP-20)
+ await aliceToken.burn(alice, 0n);
+
+ // 4. Storage is not corrupted:
+ expect(await aliceToken.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
+ expect(await bobToken.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
+
+ // 4.1 Tokens can be transfered:
+ await aliceToken.transfer(alice, {Substrate: bob.address}, 10n);
+ await bobToken.transfer(bob, {Substrate: alice.address}, 10n);
+ expect(await aliceToken.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
+ expect(await bobToken.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
+ });
+});
js-packages/tests/sub/refungible/nesting.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/refungible/nesting.test.ts
@@ -0,0 +1,148 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../../util/index.js';
+
+describe('Refungible nesting', () => {
+ let alice: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ const donor = await privateKey({url: import.meta.url});
+ [alice, charlie] = await helper.arrange.createAccounts([50n, 10n], donor);
+ });
+ });
+
+ [
+ {restrictedMode: true},
+ {restrictedMode: false},
+ ].map(testCase => {
+ itSub(`Owner can nest their token${testCase.restrictedMode ? ': Restricted mode' : ''}`, async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice, {permissions: {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true}}});
+ const collectionRFT = await helper.rft.mintCollection(alice);
+ const targetToken = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
+
+ await collectionNFT.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionRFT.collectionId] : null}});
+ await collectionNFT.addToAllowList(alice, {Substrate: charlie.address});
+ await collectionNFT.addToAllowList(alice, targetToken.nestingAccount());
+
+ await collectionRFT.setPermissions(alice, {access: 'AllowList', mintMode: true});
+ await collectionRFT.addToAllowList(alice, {Substrate: charlie.address});
+ await collectionRFT.addToAllowList(alice, targetToken.nestingAccount());
+
+ // Create an immediately nested token
+ const nestedToken = await collectionRFT.mintToken(charlie, 5n, targetToken.nestingAccount());
+ expect(await nestedToken.getBalance(targetToken.nestingAccount())).to.be.equal(5n);
+
+ // Create a token to be nested and nest
+ const newToken = await collectionRFT.mintToken(charlie, 5n);
+ await newToken.transfer(charlie, targetToken.nestingAccount(), 2n);
+ expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);
+ expect(await newToken.getBalance({Substrate: charlie.address})).to.be.equal(3n);
+ });
+ });
+
+ itSub('Owner can unnest nested token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ // Owner mints nested RFT token:
+ const collectionRFT = await helper.rft.mintCollection(alice);
+ const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());
+
+ // 1.1 Owner can partially unnest token pieces with transferFrom:
+ await token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n);
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);
+ expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+
+ // 1.2 Owner can unnest all pieces:
+ await token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 1n);
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(10n);
+ expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
+ });
+
+ itSub('Owner can burn nested token pieces', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const targetToken = await collection.mintToken(alice);
+
+ // Owner mints nested RFT token:
+ const collectionRFT = await helper.rft.mintCollection(alice);
+ const token = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
+ await token.transfer(alice, targetToken.nestingAccount(), 30n);
+
+ // 1.1 Owner can partially burnFrom nested pieces:
+ await token.burnFrom(alice, targetToken.nestingAccount(), 10n);
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(70n);
+ expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(20n);
+ expect(await targetToken.getChildren()).to.has.length(1);
+
+ // 1.1 Owner can burnFrom all nested pieces:
+ await token.burnFrom(alice, targetToken.nestingAccount(), 20n);
+ expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
+ expect(await targetToken.getChildren()).to.has.length(0);
+ expect(await token.doesExist()).to.be.true;
+
+ // 2. Target token does not contain any pieces and can be burnt:
+ await targetToken.burn(alice);
+ expect(await targetToken.doesExist()).to.be.false;
+ });
+});
+
+describe('Refungible nesting negative tests', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 50n], donor);
+ });
+ });
+
+ [
+ {restrictedMode: true},
+ {restrictedMode: false},
+ ].map(testCase => {
+ itSub(`non-Owner cannot nest someone else's token${testCase.restrictedMode ? ': Restricted mode' : ''}`, async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice);
+ const collectionRFT = await helper.rft.mintCollection(alice);
+ const targetToken = await collectionNFT.mintToken(alice);
+
+ await collectionNFT.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionRFT.collectionId] : null}});
+ await collectionNFT.addToAllowList(alice, {Substrate: bob.address});
+ await collectionNFT.addToAllowList(alice, targetToken.nestingAccount());
+
+ // Try to create a token to be nested and nest
+ const newToken = await collectionRFT.mintToken(alice);
+ await expect(newToken.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.TokenValueTooLow/);
+
+ expect(await targetToken.getChildren()).to.be.length(0);
+ expect(await newToken.getBalance({Substrate: alice.address})).to.be.equal(1n);
+
+ // Nest some tokens as Alice into Bob's token
+ await newToken.transfer(alice, targetToken.nestingAccount());
+
+ // Try to pull it out
+ await expect(newToken.transferFrom(bob, targetToken.nestingAccount(), {Substrate: alice.address}, 1n))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+ });
+ });
+});
js-packages/tests/sub/refungible/repartition.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/refungible/repartition.test.ts
@@ -0,0 +1,96 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../../util/index.js';
+
+describe('integration test: Refungible functionality:', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+ });
+ });
+
+ itSub('Repartition', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+
+ expect(await token.repartition(alice, 200n)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(200n);
+ expect(await token.getTotalPieces()).to.be.equal(200n);
+
+ expect(await token.transfer(alice, {Substrate: bob.address}, 110n)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(90n);
+ expect(await token.getBalance({Substrate: bob.address})).to.be.equal(110n);
+
+ await expect(token.repartition(alice, 80n))
+ .to.eventually.be.rejectedWith(/refungible\.RepartitionWhileNotOwningAllPieces/);
+
+ expect(await token.transfer(alice, {Substrate: bob.address}, 90n)).to.be.true;
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(0n);
+ expect(await token.getBalance({Substrate: bob.address})).to.be.equal(200n);
+
+ expect(await token.repartition(bob, 150n)).to.be.true;
+ await expect(token.transfer(bob, {Substrate: alice.address}, 160n))
+ .to.eventually.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub('Repartition with increased amount', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+ await token.repartition(alice, 200n);
+ const chainEvents = helper.chainLog.slice(-1)[0].events;
+ const event = chainEvents.find((event: any) => event.section === 'common' && event.method === 'ItemCreated');
+ expect(event).to.deep.include({
+ section: 'common',
+ method: 'ItemCreated',
+ index: [66, 2],
+ data: [
+ collection.collectionId,
+ token.tokenId,
+ {substrate: alice.address},
+ 100n,
+ ],
+ });
+ });
+
+ itSub('Repartition with decreased amount', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+ await token.repartition(alice, 50n);
+ const chainEvents = helper.chainLog.slice(-1)[0].events;
+ const event = chainEvents.find((event: any) => event.section === 'common' && event.method === 'ItemDestroyed');
+ expect(event).to.deep.include({
+ section: 'common',
+ method: 'ItemDestroyed',
+ index: [66, 3],
+ data: [
+ collection.collectionId,
+ token.tokenId,
+ {substrate: alice.address},
+ 50n,
+ ],
+ });
+ });
+});
+
js-packages/tests/sub/refungible/transfer.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/refungible/transfer.test.ts
@@ -0,0 +1,73 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../../util/index.js';
+
+describe('Refungible transfer tests', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+ });
+ });
+
+ itSub('Can transfer token pieces', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const token = await collection.mintToken(alice, 100n);
+
+ expect(await token.transfer(alice, {Substrate: bob.address}, 60n)).to.be.true;
+ // 1. Can transfer less or equal than have:
+ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(40n);
+ expect(await token.getBalance({Substrate: bob.address})).to.be.equal(60n);
+ });
+
+ itSub('Cannot transfer incorrect amount of token pieces', async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+ const tokenAlice = await collection.mintToken(alice, 10n, {Substrate: alice.address});
+ const tokenBob = await collection.mintToken(alice, 10n, {Substrate: bob.address});
+
+ // 1. Alice cannot transfer Bob's token:
+ await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
+ await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
+ await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 10n)).to.be.rejectedWith('common.TokenValueTooLow');
+ await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow');
+
+ // 2. Alice cannot transfer non-existing token:
+ await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
+ await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
+
+ // 3. Cannot transfer more than have:
+ await expect(tokenAlice.transfer(alice, {Substrate: bob.address}, 11n))
+ .to.eventually.be.rejectedWith(/common\.TokenValueTooLow/);
+
+ // 4. Zero transfer allowed (EIP-20):
+ await tokenAlice.transfer(alice, {Substrate: charlie.address}, 0n);
+
+ expect(await tokenAlice.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
+ expect(await tokenBob.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
+ expect(await tokenAlice.getBalance({Substrate: alice.address})).to.eq(10n);
+ expect(await tokenBob.getBalance({Substrate: bob.address})).to.eq(10n);
+ expect(await tokenBob.getBalance({Substrate: charlie.address})).to.eq(0n);
+ });
+});
js-packages/tests/transfer.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/transfer.test.ts
@@ -0,0 +1,345 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds} from './eth/util/index.js';
+import {itSub, Pallets, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
+ let donor: IKeyringPair;
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+ });
+ });
+
+ itSub('Balance transfers and check balance', async ({helper}) => {
+ const alicesBalanceBefore = await helper.balance.getSubstrate(alice.address);
+ const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+ expect(await helper.balance.transferToSubstrate(alice, bob.address, 1n)).to.be.true;
+
+ const alicesBalanceAfter = await helper.balance.getSubstrate(alice.address);
+ const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
+ expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;
+ });
+
+ itSub('Inability to pay fees error message is correct', async ({helper}) => {
+ const [zero] = await helper.arrange.createAccounts([0n], donor);
+
+ // console.error = () => {};
+ // The following operation throws an error into the console and the logs. Pay it no heed as long as the test succeeds.
+ await expect(helper.balance.transferToSubstrate(zero, donor.address, 1n))
+ .to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');
+ });
+
+ itSub('[nft] User can transfer owned token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-1-NFT', description: '', tokenPrefix: 'T'});
+ const nft = await collection.mintToken(alice);
+
+ await nft.transfer(alice, {Substrate: bob.address});
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: bob.address});
+ });
+
+ itSub('[fungible] User can transfer owned token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-1-FT', description: '', tokenPrefix: 'T'});
+ await collection.mint(alice, 10n);
+
+ await collection.transfer(alice, {Substrate: bob.address}, 9n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('[refungible] User can transfer owned token', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await rft.transfer(alice, {Substrate: bob.address}, 9n);
+ expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);
+ });
+
+ itSub('[nft] Collection admin can transfer owned token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-2-NFT', description: '', tokenPrefix: 'T'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ const nft = await collection.mintToken(bob, {Substrate: bob.address});
+ await nft.transfer(bob, {Substrate: alice.address});
+
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('[fungible] Collection admin can transfer owned token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-2-FT', description: '', tokenPrefix: 'T'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ await collection.mint(bob, 10n, {Substrate: bob.address});
+ await collection.transfer(bob, {Substrate: alice.address}, 1n);
+
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('[refungible] Collection admin can transfer owned token', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-2-RFT', description: '', tokenPrefix: 'T'});
+ await collection.addAdmin(alice, {Substrate: bob.address});
+
+ const rft = await collection.mintToken(bob, 10n, {Substrate: bob.address});
+ await rft.transfer(bob, {Substrate: alice.address}, 1n);
+
+ expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);
+ });
+});
+
+describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+ });
+ });
+
+
+ itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {
+ await expect(helper.nft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {
+ await expect(helper.ft.transfer(alice, NON_EXISTENT_COLLECTION_ID, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {
+ await expect(helper.rft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('[nft] Transfer with deleted collection_id', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-1-NFT', description: '', tokenPrefix: 'T'});
+ const nft = await collection.mintToken(alice);
+
+ await nft.burn(alice);
+ await collection.burn(alice);
+
+ await expect(nft.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('[fungible] Transfer with deleted collection_id', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-1-FT', description: '', tokenPrefix: 'T'});
+ await collection.mint(alice, 10n);
+
+ await collection.burnTokens(alice, 10n);
+ await collection.burn(alice);
+
+ await expect(collection.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub.ifWithPallets('[refungible] Transfer with deleted collection_id', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-1-RFT', description: '', tokenPrefix: 'T'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await rft.burn(alice, 10n);
+ await collection.burn(alice);
+
+ await expect(rft.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ itSub('[nft] Transfer with not existed item_id', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-2-NFT', description: '', tokenPrefix: 'T'});
+ await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.TokenNotFound/);
+ });
+
+ itSub('[fungible] Transfer with not existed item_id', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-2-FT', description: '', tokenPrefix: 'T'});
+ await expect(collection.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub.ifWithPallets('[refungible] Transfer with not existed item_id', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-2-RFT', description: '', tokenPrefix: 'T'});
+ await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub('Zero transfer NFT', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});
+ const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});
+ const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});
+ // 1. Zero transfer of own tokens allowed:
+ await helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: bob.address}, collection.collectionId, tokenAlice.tokenId, 0]);
+ // 2. Zero transfer of non-owned tokens not allowed:
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');
+ // 3. Zero transfer of non-existing tokens not allowed:
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, 10, 0])).to.be.rejectedWith('common.TokenNotFound');
+ expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});
+ expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});
+ // 4. Storage is not corrupted:
+ await tokenAlice.transfer(alice, {Substrate: bob.address});
+ await tokenBob.transfer(bob, {Substrate: alice.address});
+ expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});
+ expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});
+ });
+
+ itSub('[nft] Transfer with deleted item_id', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});
+ const nft = await collection.mintToken(alice);
+
+ await nft.burn(alice);
+
+ await expect(nft.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.TokenNotFound/);
+ });
+
+ itSub('[fungible] Transfer with deleted item_id', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-3-FT', description: '', tokenPrefix: 'T'});
+ await collection.mint(alice, 10n);
+
+ await collection.burnTokens(alice, 10n);
+
+ await expect(collection.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub.ifWithPallets('[refungible] Transfer with deleted item_id', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-3-RFT', description: '', tokenPrefix: 'T'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await rft.burn(alice, 10n);
+
+ await expect(rft.transfer(alice, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub('[nft] Transfer with recipient that is not owner', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-4-NFT', description: '', tokenPrefix: 'T'});
+ const nft = await collection.mintToken(alice);
+
+ await expect(nft.transfer(bob, {Substrate: bob.address}))
+ .to.be.rejectedWith(/common\.NoPermission/);
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('[fungible] Transfer with recipient that is not owner', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-4-FT', description: '', tokenPrefix: 'T'});
+ await collection.mint(alice, 10n);
+
+ await expect(collection.transfer(bob, {Substrate: bob.address}, 9n))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(10n);
+ });
+
+ itSub.ifWithPallets('[refungible] Transfer with recipient that is not owner', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await expect(rft.transfer(bob, {Substrate: bob.address}, 9n))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(0n);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(10n);
+ });
+});
+
+describe('Transfers to self (potentially over substrate-evm boundary)', () => {
+ let donor: IKeyringPair;
+
+ before(async function() {
+ await usingEthPlaygrounds(async (_, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ itEth('Transfers to self. In case of same frontend', async ({helper}) => {
+ const [owner] = await helper.arrange.createAccounts([10n], donor);
+ const collection = await helper.ft.mintCollection(owner, {});
+ await collection.mint(owner, 100n);
+
+ const ownerProxy = helper.address.substrateToEth(owner.address);
+
+ // transfer to own proxy
+ await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);
+ expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);
+
+ // transfer-from own proxy to own proxy again
+ await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Ethereum: ownerProxy}, 5n);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);
+ expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);
+ });
+
+ itEth('Transfers to self. In case of substrate-evm boundary', async ({helper}) => {
+ const [owner] = await helper.arrange.createAccounts([10n], donor);
+ const collection = await helper.ft.mintCollection(owner, {});
+ await collection.mint(owner, 100n);
+
+ const ownerProxy = helper.address.substrateToEth(owner.address);
+
+ // transfer to own proxy
+ await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);
+ expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);
+
+ // transfer-from own proxy to self
+ await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Substrate: owner.address}, 5n);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(95n);
+ expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(5n);
+ });
+
+ itEth('Transfers to self. In case of inside substrate-evm', async ({helper}) => {
+ const [owner] = await helper.arrange.createAccounts([10n], donor);
+ const collection = await helper.ft.mintCollection(owner, {});
+ await collection.mint(owner, 100n);
+
+ // transfer to self again
+ await collection.transfer(owner, {Substrate: owner.address}, 10n);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);
+
+ // transfer-from self to self again
+ await collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 5n);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);
+ });
+
+ itEth('Transfers to self. In case of inside substrate-evm when not enought "Fungibles"', async ({helper}) => {
+ const [owner] = await helper.arrange.createAccounts([10n], donor);
+ const collection = await helper.ft.mintCollection(owner, {});
+ await collection.mint(owner, 10n);
+
+ // transfer to self again
+ await expect(collection.transfer(owner, {Substrate: owner.address}, 11n))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+
+ // transfer-from self to self again
+ await expect(collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 12n))
+ .to.be.rejectedWith(/common\.TokenValueTooLow/);
+ expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(10n);
+ });
+});
js-packages/tests/transferFrom.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/transferFrom.test.ts
@@ -0,0 +1,375 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect} from './util/index.js';
+import {NON_EXISTENT_COLLECTION_ID} from '@unique/playgrounds/types.js';
+
+describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('[nft] Execute the extrinsic and check nftItemList - owner of token', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-1', description: '', tokenPrefix: 'TF'});
+ const nft = await collection.mintToken(alice);
+ await nft.approve(alice, {Substrate: bob.address});
+ expect(await nft.isApproved({Substrate: bob.address})).to.be.true;
+
+ await nft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address});
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: charlie.address});
+ });
+
+ itSub('[fungible] Execute the extrinsic and check nftItemList - owner of token', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-2', description: '', tokenPrefix: 'TF'});
+ await collection.mint(alice, 10n);
+ await collection.approveTokens(alice, {Substrate: bob.address}, 7n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(7n);
+
+ await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 6n);
+ expect(await collection.getBalance({Substrate: charlie.address})).to.be.equal(6n);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(4n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(1n);
+ });
+
+ itSub.ifWithPallets('[refungible] Execute the extrinsic and check nftItemList - owner of token', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-3', description: '', tokenPrefix: 'TF'});
+ const rft = await collection.mintToken(alice, 10n);
+ await rft.approve(alice, {Substrate: bob.address}, 7n);
+ expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(7n);
+
+ await rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 6n);
+ expect(await rft.getBalance({Substrate: charlie.address})).to.be.equal(6n);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(4n);
+ expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(1n);
+ });
+
+ itSub('Should reduce allowance if value is big', async ({helper}) => {
+ // fungible
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-4', description: '', tokenPrefix: 'TF'});
+ await collection.mint(alice, 500000n);
+
+ await collection.approveTokens(alice, {Substrate: bob.address}, 500000n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(500000n);
+ await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 500000n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(0n);
+ });
+
+ itSub('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-5', description: '', tokenPrefix: 'TF'});
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+
+ const nft = await collection.mintToken(alice, {Substrate: bob.address});
+ await nft.transferFrom(alice, {Substrate: bob.address}, {Substrate: charlie.address});
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: charlie.address});
+ });
+});
+
+describe('Negative Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob, charlie] = await helper.arrange.createAccounts([50n, 10n, 10n], donor);
+ });
+ });
+
+ itSub('transferFrom for a collection that does not exist', async ({helper}) => {
+ await expect(helper.collection.approveToken(alice, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: bob.address}, 1n))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ await expect(helper.collection.transferTokenFrom(bob, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))
+ .to.be.rejectedWith(/common\.CollectionNotFound/);
+ });
+
+ /* itSub('transferFrom for a collection that was destroyed', async ({helper}) => {
+ this test copies approve negative test
+ }); */
+
+ /* itSub('transferFrom a token that does not exist', async ({helper}) => {
+ this test copies approve negative test
+ }); */
+
+ /* itSub('transferFrom a token that was deleted', async ({helper}) => {
+ this test copies approve negative test
+ }); */
+
+ itSub('[nft] transferFrom for not approved address', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-1', description: '', tokenPrefix: 'TF'});
+ const nft = await collection.mintToken(alice);
+
+ await expect(nft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('[fungible] transferFrom for not approved address', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-1', description: '', tokenPrefix: 'TF'});
+ await collection.mint(alice, 10n);
+
+ await expect(collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 5n))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
+ expect(await collection.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
+ });
+
+ itSub.ifWithPallets('[refungible] transferFrom for not approved address', [Pallets.ReFungible], async({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-3', description: '', tokenPrefix: 'TF'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await expect(rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
+ expect(await rft.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
+ expect(await rft.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
+ });
+
+ itSub('[nft] transferFrom incorrect token count', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-4', description: '', tokenPrefix: 'TF'});
+ const nft = await collection.mintToken(alice);
+
+ await nft.approve(alice, {Substrate: bob.address});
+ expect(await nft.isApproved({Substrate: bob.address})).to.be.true;
+
+ await expect(helper.collection.transferTokenFrom(
+ bob,
+ collection.collectionId,
+ nft.tokenId,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ 2n,
+ )).to.be.rejectedWith(/nonfungible\.NonfungibleItemsHaveNoAmount/);
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('[fungible] transferFrom incorrect token count', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-5', description: '', tokenPrefix: 'TF'});
+ await collection.mint(alice, 10n);
+
+ await collection.approveTokens(alice, {Substrate: bob.address}, 2n);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(2n);
+
+ await expect(collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 5n))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
+ expect(await collection.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
+ });
+
+ itSub.ifWithPallets('[refungible] transferFrom incorrect token count', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-6', description: '', tokenPrefix: 'TF'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await rft.approve(alice, {Substrate: bob.address}, 5n);
+ expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(5n);
+
+ await expect(rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 7n))
+ .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10n);
+ expect(await rft.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
+ expect(await rft.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
+ });
+
+ itSub('[nft] execute transferFrom from account that is not owner of collection', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-7', description: '', tokenPrefix: 'TF'});
+ const nft = await collection.mintToken(alice);
+
+ await expect(nft.approve(charlie, {Substrate: bob.address})).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
+ expect(await nft.isApproved({Substrate: bob.address})).to.be.false;
+
+ await expect(nft.transferFrom(
+ charlie,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});
+ });
+
+ itSub('[fungible] execute transferFrom from account that is not owner of collection', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-8', description: '', tokenPrefix: 'TF'});
+ await collection.mint(alice, 10000n);
+
+ await expect(collection.approveTokens(charlie, {Substrate: bob.address}, 1n)).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(0n);
+ expect(await collection.getApprovedTokens({Substrate: charlie.address}, {Substrate: bob.address})).to.be.eq(0n);
+
+ await expect(collection.transferFrom(
+ charlie,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10000n);
+ expect(await collection.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
+ expect(await collection.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
+ });
+
+ itSub.ifWithPallets('[refungible] execute transferFrom from account that is not owner of collection', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-9', description: '', tokenPrefix: 'TF'});
+ const rft = await collection.mintToken(alice, 10000n);
+
+ await expect(rft.approve(charlie, {Substrate: bob.address}, 1n)).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
+ expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(0n);
+ expect(await rft.getApprovedPieces({Substrate: charlie.address}, {Substrate: bob.address})).to.be.eq(0n);
+
+ await expect(rft.transferFrom(
+ charlie,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10000n);
+ expect(await rft.getBalance({Substrate: bob.address})).to.be.deep.equal(0n);
+ expect(await rft.getBalance({Substrate: charlie.address})).to.be.deep.equal(0n);
+ });
+
+ itSub('transferFrom burnt token before approve NFT', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-10', description: '', tokenPrefix: 'TF'});
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ const nft = await collection.mintToken(alice);
+
+ await nft.burn(alice);
+ await expect(nft.approve(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.TokenNotFound/);
+
+ await expect(nft.transferFrom(
+ bob,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ });
+
+ itSub('transferFrom burnt token before approve Fungible', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-11', description: '', tokenPrefix: 'TF'});
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ await collection.mint(alice, 10n);
+
+ await collection.burnTokens(alice, 10n);
+ await expect(collection.approveTokens(alice, {Substrate: bob.address})).to.be.not.rejected;
+
+ await expect(collection.transferFrom(
+ alice,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub.ifWithPallets('transferFrom burnt token before approve ReFungible', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-12', description: '', tokenPrefix: 'TF'});
+ await collection.setLimits(alice, {ownerCanTransfer: true});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await rft.burn(alice, 10n);
+ await expect(rft.approve(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.CantApproveMoreThanOwned/);
+
+ await expect(rft.transferFrom(
+ alice,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub('transferFrom burnt token after approve NFT', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-13', description: '', tokenPrefix: 'TF'});
+ const nft = await collection.mintToken(alice);
+
+ await nft.approve(alice, {Substrate: bob.address});
+ expect(await nft.isApproved({Substrate: bob.address})).to.be.true;
+
+ await nft.burn(alice);
+
+ await expect(nft.transferFrom(
+ bob,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ });
+
+ itSub('transferFrom burnt token after approve Fungible', async ({helper}) => {
+ const collection = await helper.ft.mintCollection(alice, {name: 'TransferFrom-Neg-14', description: '', tokenPrefix: 'TF'});
+ await collection.mint(alice, 10n);
+
+ await collection.approveTokens(alice, {Substrate: bob.address});
+ expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(1n);
+
+ await collection.burnTokens(alice, 10n);
+
+ await expect(collection.transferFrom(
+ bob,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.TokenValueTooLow/);
+ });
+
+ itSub.ifWithPallets('transferFrom burnt token after approve ReFungible', [Pallets.ReFungible], async ({helper}) => {
+ const collection = await helper.rft.mintCollection(alice, {name: 'TransferFrom-Neg-15', description: '', tokenPrefix: 'TF'});
+ const rft = await collection.mintToken(alice, 10n);
+
+ await rft.approve(alice, {Substrate: bob.address}, 10n);
+ expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.eq(10n);
+
+ await rft.burn(alice, 10n);
+
+ await expect(rft.transferFrom(
+ bob,
+ {Substrate: alice.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ });
+
+ itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'TransferFrom-Neg-16', description: '', tokenPrefix: 'TF'});
+ const nft = await collection.mintToken(alice, {Substrate: bob.address});
+
+ await collection.setLimits(alice, {ownerCanTransfer: false});
+
+ await expect(nft.transferFrom(
+ alice,
+ {Substrate: bob.address},
+ {Substrate: charlie.address},
+ )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+ });
+
+ itSub('zero transfer NFT', async ({helper}) => {
+ const collection = await helper.nft.mintCollection(alice, {name: 'Zero', description: 'Zero transfer', tokenPrefix: 'TF'});
+ const notApprovedNft = await collection.mintToken(alice, {Substrate: bob.address});
+ const approvedNft = await collection.mintToken(alice, {Substrate: bob.address});
+ await approvedNft.approve(bob, {Substrate: alice.address});
+
+ // 1. Cannot zero transferFrom (non-existing token)
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, 9999, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+ // 2. Cannot zero transferFrom (not approved token)
+ await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, notApprovedNft.tokenId, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+ // 3. Can zero transferFrom (approved token):
+ await helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, approvedNft.tokenId, 0]);
+
+ // 4.1 approvedNft still approved:
+ expect(await approvedNft.isApproved({Substrate: alice.address})).to.be.true;
+ // 4.2 bob is still the owner:
+ expect(await approvedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+ expect(await notApprovedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+ // 4.3 Alice can transfer approved nft:
+ await approvedNft.transferFrom(alice, {Substrate: bob.address}, {Substrate: alice.address});
+ expect(await approvedNft.getOwner()).to.deep.eq({Substrate: alice.address});
+ });
+});
js-packages/tests/tsconfig.jsondiffbeforeafterboth--- a/js-packages/tests/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../tsconfig.packages.json",
- "compilerOptions": {
- "rootDir": "./src",
- "outDir": "dist",
- "allowSyntheticDefaultImports": true,
- "resolveJsonModule": true,
- },
- "include": ["./src/**/*.json", "./src/**/*.ts"],
- "references": [
- { "path": "../playgrounds/tsconfig.json" }
- ]
-}
\ No newline at end of file
js-packages/tests/tx-version-presence.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/tx-version-presence.test.ts
@@ -0,0 +1,32 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {Metadata} from '@polkadot/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+
+let metadata: Metadata;
+
+describe('TxVersion is present', () => {
+ before(async () => {
+ await usingPlaygrounds(async helper => {
+ metadata = await helper.callRpc('api.rpc.state.getMetadata', []);
+ });
+ });
+
+ itSub('Signed extension CheckTxVersion is present', () => {
+ expect(metadata.asLatest.extrinsic.signedExtensions.map(se => se.identifier.toString())).to.include('CheckTxVersion');
+ });
+});
js-packages/tests/util/authorizeEnactUpgrade.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/authorizeEnactUpgrade.ts
@@ -0,0 +1,19 @@
+import {readFile} from 'fs/promises';
+import {u8aToHex} from '@polkadot/util';
+import {usingPlaygrounds} from './index.js';
+import {blake2AsHex} from '@polkadot/util-crypto';
+
+
+const codePath = process.argv[2];
+if(!codePath) throw new Error('missing code path argument');
+
+const code = await readFile(codePath);
+
+await usingPlaygrounds(async (helper, privateKey) => {
+ const alice = await privateKey('//Alice');
+ const hex = blake2AsHex(code);
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.parachainSystem.authorizeUpgrade', [hex, true]);
+ await helper.getSudo().executeExtrinsicUncheckedWeight(alice, 'api.tx.parachainSystem.enactAuthorizedUpgrade', [u8aToHex(code)]);
+});
+// We miss disconnect/unref somewhere.
+process.exit(0);
js-packages/tests/util/createHrmp.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/createHrmp.ts
@@ -0,0 +1,36 @@
+import {usingPlaygrounds} from './index.js';
+import config from '../config.js';
+
+const profile = process.argv[2];
+if(!profile) throw new Error('missing profile/relay argument');
+
+await usingPlaygrounds(async (helper, privateKey) => {
+ const bidirOpen = async (a: number, b: number) => {
+ console.log(`Opening ${a} <=> ${b}`);
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.hrmp.forceOpenHrmpChannel', [a, b, 8, 512]);
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.hrmp.forceOpenHrmpChannel', [b, a, 8, 512]);
+ };
+ const alice = await privateKey('//Alice');
+ switch (profile) {
+ case 'opal':
+ await bidirOpen(1001, 1002);
+ break;
+ case 'quartz':
+ await bidirOpen(1001, 1002);
+ await bidirOpen(1001, 1003);
+ await bidirOpen(1001, 1004);
+ await bidirOpen(1001, 1005);
+ break;
+ case 'unique':
+ await bidirOpen(1001, 1002);
+ await bidirOpen(1001, 1003);
+ await bidirOpen(1001, 1004);
+ await bidirOpen(1001, 1005);
+ await bidirOpen(1001, 1006);
+ break;
+ default:
+ throw new Error(`unknown hrmp config profile: ${profile}`);
+ }
+}, config.relayUrl);
+// We miss disconnect/unref somewhere.
+process.exit(0);
js-packages/tests/util/frankensteinMigrate.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/frankensteinMigrate.ts
@@ -0,0 +1,9 @@
+import {migration as locksToFreezesMigration} from '../migrations/942057-appPromotion/index.js';
+export interface Migration {
+ before: () => Promise<void>,
+ after: () => Promise<void>,
+}
+
+export const migrations: {[key: string]: Migration} = {
+ 'v942057': locksToFreezesMigration,
+};
js-packages/tests/util/globalSetup.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/globalSetup.ts
@@ -0,0 +1,119 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import {
+ usingPlaygrounds, Pallets, DONOR_FUNDING, MINIMUM_DONOR_FUND, LOCKING_PERIOD, UNLOCKING_PERIOD, makeNames,
+} from './index.js';
+import * as path from 'path';
+import {promises as fs} from 'fs';
+
+const {dirname} = makeNames(import.meta.url);
+
+// This function should be called before running test suites.
+const globalSetup = async (): Promise<void> => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ try {
+ // 1. Wait node producing blocks
+ await helper.wait.newBlocks(1, 600_000);
+
+ // 2. Create donors for test files
+ await fundFilenamesWithRetries(3)
+ .then((result) => {
+ if(!result) throw Error('Some problems with fundFilenamesWithRetries');
+ });
+
+ // 3. Configure App Promotion
+ const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]);
+ if(missingPallets.length === 0) {
+ const superuser = await privateKey('//Alice');
+ const palletAddress = helper.arrange.calculatePalletAddress('appstake');
+ const palletAdmin = await privateKey('//PromotionAdmin');
+ const api = helper.getApi();
+ await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
+ const nominal = helper.balance.getOneTokenNominal();
+ await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 10000n * nominal);
+ await helper.balance.transferToSubstrate(superuser, palletAddress, 10000n * nominal);
+ await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.configuration
+ .setAppPromotionConfigurationOverride({
+ recalculationInterval: LOCKING_PERIOD,
+ pendingInterval: UNLOCKING_PERIOD})], true);
+ }
+ } catch (error) {
+ console.error(error);
+ throw Error('Error during globalSetup');
+ }
+ });
+};
+
+async function getFiles(rootPath: string): Promise<string[]> {
+ const files = await fs.readdir(rootPath, {withFileTypes: true});
+ const filenames: string[] = [];
+ for(const entry of files) {
+ const res = path.resolve(rootPath, entry.name);
+ if(entry.isDirectory()) {
+ filenames.push(...await getFiles(res));
+ } else {
+ filenames.push(res);
+ }
+ }
+ return filenames;
+}
+
+const fundFilenames = async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const oneToken = helper.balance.getOneTokenNominal();
+ const alice = await privateKey('//Alice');
+ const nonce = await helper.chain.getNonce(alice.address);
+ const filenames = await getFiles(path.resolve(dirname, '..'));
+
+ // batching is actually undesireable, it takes away the time while all the transactions actually succeed
+ const batchSize = 300;
+ let balanceGrantedCounter = 0;
+ for(let b = 0; b < filenames.length; b += batchSize) {
+ const tx: Promise<boolean>[] = [];
+ let batchBalanceGrantedCounter = 0;
+ for(let i = 0; batchBalanceGrantedCounter < batchSize && b + i < filenames.length; i++) {
+ const f = filenames[b + i];
+ if(!f.endsWith('.test.ts') && !f.endsWith('seqtest.ts') || f.includes('.outdated')) continue;
+ const account = await privateKey({filename: f, ignoreFundsPresence: true});
+ const aliceBalance = await helper.balance.getSubstrate(account.address);
+
+ if(aliceBalance < MINIMUM_DONOR_FUND * oneToken) {
+ tx.push(helper.executeExtrinsic(
+ alice,
+ 'api.tx.balances.transfer',
+ [account.address, DONOR_FUNDING * oneToken],
+ true,
+ {nonce: nonce + balanceGrantedCounter++},
+ ).then(() => true).catch(() => {console.error(`Transaction to ${path.basename(f)} registered as failed. Strange.`); return false;}));
+ batchBalanceGrantedCounter++;
+ }
+ }
+
+ if(tx.length > 0) {
+ console.log(`Granting funds to ${batchBalanceGrantedCounter} filename accounts.`);
+ const result = await Promise.all(tx);
+ if(result && result.lastIndexOf(false) > -1) throw new Error('The transactions actually probably succeeded, should check the balances.');
+ }
+ }
+
+ if(balanceGrantedCounter == 0) console.log('No account needs additional funding.');
+ });
+};
+
+const fundFilenamesWithRetries = (retriesLeft: number): Promise<boolean> => {
+ if(retriesLeft <= 0) return Promise.resolve(false);
+ return fundFilenames()
+ .then(() => Promise.resolve(true))
+ .catch(e => {
+ console.error(e);
+ console.error(`Some transactions might have failed. ${retriesLeft > 1 ? 'Retrying...' : 'Something is wrong.'}\n`);
+ return fundFilenamesWithRetries(--retriesLeft);
+ });
+};
+
+globalSetup().catch(e => {
+ console.error('Setup error');
+ console.error(e);
+ process.exit(1);
+});
js-packages/tests/util/identitySetter.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/identitySetter.ts
@@ -0,0 +1,229 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Pulls identities and sub-identities from a chain and then makes a preimage to later force upload them into another.
+// Only changed or previously non-existent data are inserted.
+//
+// Usage: `yarn setIdentities [relay WS URL] [parachain WS URL] [user key]
+// Example: `yarn setIdentities wss://polkadot-rpc.dwellir.com ws://localhost:9944 escape pattern miracle train sudden cart adapt embark wedding alien lamp mesh`
+
+import {encodeAddress} from '@polkadot/keyring';
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, Pallets} from './index.js';
+import {ChainHelperBase} from '@unique/playgrounds/unique.js';
+
+const relayUrl = process.argv[2] ?? 'ws://localhost:9844';
+const paraUrl = process.argv[3] ?? 'ws://localhost:9944';
+const key = process.argv.length > 4 ? process.argv.slice(4).join(' ') : '//Alice';
+
+export function extractAccountId(key: any): string {
+ return (key as any).toHuman()[0];
+}
+
+export function extractIdentityInfo(value: any): object {
+ const heart = (value as any).unwrap();
+ const identity = heart.toJSON();
+ identity.judgements = heart.judgements.toHuman();
+ return identity;
+}
+
+export function extractIdentity(key: any, value: any): [string, any] {
+ return [extractAccountId(key), extractIdentityInfo(value)];
+}
+
+export async function getIdentities(helper: ChainHelperBase, noneCasePredicate?: (key: any, value: any) => void) {
+ const identities: [string, any][] = [];
+ for(const [key, v] of await helper.getApi().query.identity.identityOf.entries()) {
+ const value = v as any;
+ if(value.isNone) {
+ if(noneCasePredicate) noneCasePredicate(key, value);
+ continue;
+ }
+ identities.push(extractIdentity(key, value));
+ }
+ return identities;
+}
+
+// whether the existing chain data is more important than the coming
+function isCurrentChainDataPriority(helper: ChainHelperBase, currentChainId: number | undefined, relayChainId: number) {
+ if(!currentChainId) return false;
+ // information has come from local chain, and is automatically superior
+ if(currentChainId == helper.chain.getChainProperties().ss58Format) return true;
+ // the lower the id, the more important it is (Polkadot has ss58 prefix = 0, Kusama has ss58 prefix = 2)
+ return currentChainId < relayChainId;
+}
+
+// construct an object with all data necessary for insertion from storage query results
+export function constructSubInfo(identityAccount: string, subQuery: any, supers: any[], ss58?: number): [string, any] {
+ const deposit = subQuery.toJSON()[0];
+ const subIdentities = subQuery.toHuman()[1];
+ subIdentities.map((sub: string) => supers.find((sup: any) => sup[0] === sub));
+
+ return [
+ encodeAddress(identityAccount, ss58), [
+ deposit,
+ subIdentities.map((sub: string): [string, object] | null => {
+ const sup = supers.find((sup: any) => sup[0] === sub);
+ if(!sup) {
+ console.error(`Error: Could not find info on super for \nsub-identity account\t${sub} of \nsuper account \t\t${identityAccount}, skipping.`);
+ return null;
+ }
+ return [encodeAddress(sub, ss58), sup[1].toJSON()[1]];
+ }).filter((x: any) => x),
+ ],
+ ];
+}
+
+export async function getSubs(helper: ChainHelperBase) {
+ return (await helper.getApi().query.identity.subsOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);
+}
+
+export async function getSupers(helper: ChainHelperBase) {
+ return (await helper.getApi().query.identity.superOf.entries()).map(([key, value]) => [extractAccountId(key), value as any]);
+}
+
+async function uploadPreimage(helper: ChainHelperBase, preimageMaker: IKeyringPair, preimage: string) {
+ try {
+ await helper.executeExtrinsic(preimageMaker, 'api.tx.preimage.notePreimage', [preimage]);
+ } catch (e: any) {
+ if(e.message.includes('AlreadyNoted')) {
+ console.warn('Warning: The same preimage already exists on the chain. Nothing was uploaded.');
+ } else {
+ console.error(e);
+ }
+ }
+}
+
+// The utility for pulling identity and sub-identity data
+const forceInsertIdentities = async (): Promise<void> => {
+ let relaySS58Prefix = 0;
+ const identitiesOnRelay: any[] = [];
+ const subsOnRelay: any[] = [];
+ const identitiesToRemove: string[] = [];
+ await usingPlaygrounds(async helper => {
+ try {
+ relaySS58Prefix = helper.chain.getChainProperties().ss58Format;
+ // iterate over every identity
+ for(const [key, value] of await getIdentities(helper, (key, _value) => identitiesToRemove.push((key as any).toHuman()[0]))) {
+ // if any of the judgements resulted in a good confirmed outcome, keep this identity
+ let knownGood = false, reasonable = false;
+ for(const [_id, judgement] of value.judgements) {
+ if(judgement == 'KnownGood') knownGood = true;
+ if(judgement == 'Reasonable') reasonable = true;
+ }
+ if(!(reasonable || knownGood)) continue;
+ // replace the registrator id with the relay chain's ss58 format
+ value.judgements = [[helper.chain.getChainProperties().ss58Format, knownGood ? 'KnownGood' : 'Reasonable']];
+ identitiesOnRelay.push([key, value]);
+ }
+
+ const sublessIdentities = [...identitiesOnRelay];
+ const supersOfSubs = await getSupers(helper);
+
+ // iterate over every sub-identity
+ for(const [key, value] of await getSubs(helper)) {
+ // only get subs of the identities interesting to us
+ const identityIndex = sublessIdentities.findIndex((x: any) => x[0] == key);
+ if(identityIndex == -1) continue;
+ sublessIdentities.splice(identityIndex, 1);
+ subsOnRelay.push(constructSubInfo(key, value, supersOfSubs));
+ }
+
+ // mark the rest of sub-identities for deletion with empty arrays
+ /*for(const [account, _identity] of sublessIdentities) {
+ subsOnRelay.push([account, ['0', []]]);
+ }*/
+ } catch (error) {
+ console.error(error);
+ throw Error('Error during fetching identities');
+ }
+ }, relayUrl);
+
+ await usingPlaygrounds(async (helper, privateKey) => {
+ if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) console.error('pallet-identity is not included in parachain.');
+ if(helper.fetchMissingPalletNames([Pallets.Preimage]).length != 0) console.error('pallet-preimage is not included in parachain.');
+
+ try {
+ const preimageMaker = await privateKey(key);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const paraIdentities = await getIdentities(helper);
+ const identitiesToAdd: any[] = [];
+ const paraAccountsRegistrators: {[name: string]: number} = {};
+
+ // cross-reference every account for changes
+ for(const [key, value] of identitiesOnRelay) {
+ const encodedKey = encodeAddress(key, ss58Format);
+
+ // only update if the identity info does not exist or is changed
+ const identity = paraIdentities.find(i => i[0] === encodedKey);
+ if(identity) {
+ const registratorId = identity[1].judgements[0][0];
+ paraAccountsRegistrators[encodedKey] = registratorId;
+ if(isCurrentChainDataPriority(helper, registratorId, value.judgements[0][0])
+ || JSON.stringify(value.info) === JSON.stringify(identity[1].info)) {
+ continue;
+ }
+ }
+
+ identitiesToAdd.push([key, value]);
+ // exercise caution - in case we have an identity and the realy doesn't, it might mean one of two things:
+ // 1) it was deleted on the relay;
+ // 2) it is our own identity, we don't want to delete it.
+ // identitiesToRemove.push((key as any).toHuman()[0]);
+ }
+
+ if(identitiesToRemove.length != 0)
+ await uploadPreimage(
+ helper,
+ preimageMaker,
+ helper.constructApiCall('api.tx.identity.forceRemoveIdentities', [identitiesToRemove]).method.toHex(),
+ );
+ if(identitiesToAdd.length != 0)
+ await uploadPreimage(
+ helper,
+ preimageMaker,
+ helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex(),
+ );
+
+ console.log(`Tried to push ${identitiesToAdd.length} identities`
+ + ` and found ${identitiesToRemove.length} identities for potential removal.`
+ + ` Currently there are ${(await helper.getApi().query.identity.identityOf.keys()).length} identities on the chain.`);
+
+ // fill sub-identities
+ const paraSubs = await getSubs(helper);
+ const supersOfSubs = await getSupers(helper);
+ const subsToUpdate: any[] = [];
+
+ for(const [key, value] of subsOnRelay) {
+ const encodedKey = encodeAddress(key, ss58Format);
+ const sub = paraSubs.find(i => i[0] === encodedKey);
+ if(sub) {
+ // only update if the sub-identity info does not exist or is changed
+ if(isCurrentChainDataPriority(helper, paraAccountsRegistrators[encodedKey], relaySS58Prefix)
+ || JSON.stringify(value) === JSON.stringify(constructSubInfo(sub[0], sub[1], supersOfSubs)[1])) {
+ continue;
+ }
+ } else if(value[1].length == 0)
+ continue;
+
+ subsToUpdate.push([key, value]);
+ }
+
+ if(subsToUpdate.length != 0)
+ await uploadPreimage(
+ helper,
+ preimageMaker,
+ helper.constructApiCall('api.tx.identity.forceSetSubs', [subsToUpdate]).method.toHex(),
+ );
+
+ console.log(`Also tried to push ${subsToUpdate.length} identities with their sub-identities.`
+ + ` Currently there are ${(await helper.getApi().query.identity.subsOf.keys()).length} identities with subs.`);
+ } catch (error) {
+ console.error(error);
+ throw Error('Error during setting identities');
+ }
+ }, paraUrl);
+};
+
+if(process.argv[1] === module.filename)
+ forceInsertIdentities().catch(() => process.exit(1));
js-packages/tests/util/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/index.ts
@@ -0,0 +1,221 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import * as path from 'path';
+import * as crypto from 'crypto';
+import type {IKeyringPair} from '@polkadot/types/types/interfaces';
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import chaiSubset from 'chai-subset';
+import {Context} from 'mocha';
+import config from '../config.js';
+import {ChainHelperBase} from '@unique/playgrounds/unique.js';
+import type {ILogger} from '@unique/playgrounds/types.js';
+import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper, DevAstarHelper, DevShidenHelper, DevPolkadexHelper} from '@unique/playgrounds/unique.dev.js';
+import {dirname} from 'path';
+import {fileURLToPath} from 'url';
+
+chai.config.truncateThreshold = 0;
+chai.use(chaiAsPromised);
+chai.use(chaiSubset);
+export const expect = chai.expect;
+
+const getTestHash = (filename: string) => crypto.createHash('md5').update(filename).digest('hex');
+
+export const getTestSeed = (filename: string) => `//Alice+${getTestHash(filename)}`;
+
+async function usingPlaygroundsGeneral<T extends ChainHelperBase, R = void>(
+ helperType: new (logger: ILogger) => T,
+ url: string,
+ code: (helper: T, privateKey: (seed: string | { filename?: string, url?: string, ignoreFundsPresence?: boolean }) => Promise<IKeyringPair>) => Promise<R>,
+): Promise<R> {
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
+
+ const helper = new helperType(new SilentLogger());
+ let result;
+ try {
+ await helper.connect(url);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const privateKey = async (seed: string | {filename?: string, url?: string, ignoreFundsPresence?: boolean}) => {
+ if(typeof seed === 'string') {
+ return helper.util.fromSeed(seed, ss58Format);
+ }
+ if(seed.url) {
+ const {filename} = makeNames(seed.url);
+ seed.filename = filename;
+ } else if(seed.filename) {
+ // Pass
+ } else {
+ throw new Error('no url nor filename set');
+ }
+ const actualSeed = getTestSeed(seed.filename);
+ let account = helper.util.fromSeed(actualSeed, ss58Format);
+ // here's to hoping that no
+ if(!seed.ignoreFundsPresence && ((helper as any)['balance'] == undefined || await (helper as any).balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND)) {
+ console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
+ account = helper.util.fromSeed('//Alice', ss58Format);
+ }
+ return account;
+ };
+ result = await code(helper, privateKey);
+ }
+ finally {
+ await helper.disconnect();
+ silentConsole.disable();
+ }
+ return result as any as R;
+}
+
+export const usingPlaygrounds = <R = void>(code: (helper: DevUniqueHelper, privateKey: (seed: string | {filename?: string, url?: string, ignoreFundsPresence?: boolean}) => Promise<IKeyringPair>) => Promise<R>, url: string = config.substrateUrl) => usingPlaygroundsGeneral<DevUniqueHelper, R>(DevUniqueHelper, url, code);
+
+export const usingWestmintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevWestmintHelper>(DevWestmintHelper, url, code);
+
+export const usingStateminePlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevStatemineHelper>(DevWestmintHelper, url, code);
+
+export const usingStatemintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevStatemintHelper>(DevWestmintHelper, url, code);
+
+export const usingRelayPlaygrounds = (url: string, code: (helper: DevRelayHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevRelayHelper>(DevRelayHelper, url, code);
+
+export const usingAcalaPlaygrounds = (url: string, code: (helper: DevAcalaHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevAcalaHelper>(DevAcalaHelper, url, code);
+
+export const usingKaruraPlaygrounds = (url: string, code: (helper: DevKaruraHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevKaruraHelper>(DevAcalaHelper, url, code);
+
+export const usingMoonbeamPlaygrounds = (url: string, code: (helper: DevMoonbeamHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevMoonbeamHelper>(DevMoonbeamHelper, url, code);
+
+export const usingMoonriverPlaygrounds = (url: string, code: (helper: DevMoonbeamHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevMoonriverHelper>(DevMoonriverHelper, url, code);
+
+export const usingAstarPlaygrounds = (url: string, code: (helper: DevAstarHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevAstarHelper>(DevAstarHelper, url, code);
+
+export const usingShidenPlaygrounds = (url: string, code: (helper: DevShidenHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevShidenHelper>(DevShidenHelper, url, code);
+
+export const usingPolkadexPlaygrounds = (url: string, code: (helper: DevPolkadexHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => usingPlaygroundsGeneral<DevPolkadexHelper>(DevPolkadexHelper, url, code);
+
+export const MINIMUM_DONOR_FUND = 4_000_000n;
+export const DONOR_FUNDING = 4_000_000n;
+
+// App-promotion periods:
+export const LOCKING_PERIOD = 12n; // 12 blocks of relay
+export const UNLOCKING_PERIOD = 6n; // 6 blocks of parachain
+
+// Native contracts
+export const COLLECTION_HELPER = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f';
+export const CONTRACT_HELPER = '0x842899ECF380553E8a4de75bF534cdf6fBF64049';
+
+export enum Pallets {
+ Inflation = 'inflation',
+ ReFungible = 'refungible',
+ Fungible = 'fungible',
+ NFT = 'nonfungible',
+ Scheduler = 'scheduler',
+ UniqueScheduler = 'uniqueScheduler',
+ AppPromotion = 'apppromotion',
+ CollatorSelection = 'collatorselection',
+ Session = 'session',
+ Identity = 'identity',
+ Democracy = 'democracy',
+ Council = 'council',
+ //CouncilMembership = 'councilmembership',
+ TechnicalCommittee = 'technicalcommittee',
+ Fellowship = 'fellowshipcollective',
+ Preimage = 'preimage',
+ Maintenance = 'maintenance',
+ TestUtils = 'testutils',
+}
+
+export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: readonly string[]) {
+ const missingPallets = helper.fetchMissingPalletNames(requiredPallets);
+
+ if(missingPallets.length > 0) {
+ const skipMsg = `\tSkipping test '${test.test?.title}'.\n\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
+ console.warn('\x1b[38:5:208m%s\x1b[0m', skipMsg);
+ test.skip();
+ }
+}
+
+export function itSub(name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: readonly string[] } = {}) {
+ (opts.only ? it.only :
+ opts.skip ? it.skip : it)(name, async function () {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ if(opts.requiredPallets) {
+ requirePalletsOrSkip(this, helper, opts.requiredPallets);
+ }
+
+ await cb({helper, privateKey});
+ });
+ });
+}
+export function itSubIfWithPallet(name: string, required: readonly string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: readonly string[] } = {}) {
+ return itSub(name, cb, {requiredPallets: required, ...opts});
+}
+itSub.only = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSub(name, cb, {only: true});
+itSub.skip = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSub(name, cb, {skip: true});
+
+itSubIfWithPallet.only = (name: string, required: readonly string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSubIfWithPallet(name, required, cb, {only: true});
+itSubIfWithPallet.skip = (name: string, required: readonly string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSubIfWithPallet(name, required, cb, {skip: true});
+itSub.ifWithPallets = itSubIfWithPallet;
+
+export type SchedKind = 'anon' | 'named';
+
+export function itSched(
+ name: string,
+ cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any,
+ opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},
+) {
+ itSub(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);
+ itSub(name + ' (named scheduling)', (apis) => cb('named', apis), opts);
+}
+itSched.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSched(name, cb, {only: true});
+itSched.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSched(name, cb, {skip: true});
+itSched.ifWithPallets = itSchedIfWithPallets;
+
+function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+ return itSched(name, cb, {requiredPallets: required, ...opts});
+}
+
+export function describeXCM(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) {
+ (process.env.RUN_XCM_TESTS && !opts.skip
+ ? describe
+ : describe.skip)(title, fn);
+}
+
+describeXCM.skip = (name: string, fn: (this: Mocha.Suite) => void) => describeXCM(name, fn, {skip: true});
+
+export function describeGov(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) {
+ (process.env.RUN_GOV_TESTS && !opts.skip
+ ? describe
+ : describe.skip)(title, fn);
+}
+
+describeGov.skip = (name: string, fn: (this: Mocha.Suite) => void) => describeGov(name, fn, {skip: true});
+
+export function sizeOfInt(i: number) {
+ if(i < 0 || i > 0xffffffff) throw new Error('out of range');
+ if(i < 0b11_1111) {
+ return 1;
+ } else if(i < 0b11_1111_1111_1111) {
+ return 2;
+ } else if(i < 0b11_1111_1111_1111_1111_1111_1111_1111) {
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+const UTF8_ENCODER = new TextEncoder();
+export function sizeOfEncodedStr(v: string) {
+ const encoded = UTF8_ENCODER.encode(v);
+ return sizeOfInt(encoded.length) + encoded.length;
+}
+
+export function sizeOfProperty(prop: {key: string, value: string}) {
+ return sizeOfEncodedStr(prop.key) + sizeOfEncodedStr(prop.value);
+}
+
+export function makeNames(url: string) {
+ const filename = fileURLToPath(url);
+ return {
+ filename,
+ dirname: dirname(filename),
+ };
+}
js-packages/tests/util/relayIdentitiesChecker.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/relayIdentitiesChecker.ts
@@ -0,0 +1,114 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Checks and reports the differences between identities and sub-identities on two chains.
+//
+// Usage: `yarn checkRelayIdentities [relay-1 WS URL] [relay-2 WS URL]`
+// Example: `yarn checkRelayIdentities wss://polkadot-rpc.dwellir.com wss://kusama-rpc.dwellir.com`
+
+import {encodeAddress} from '@polkadot/keyring';
+import {usingPlaygrounds} from './index.js';
+import {getIdentities, getSubs, getSupers, constructSubInfo} from './identitySetter.js';
+
+const relay1Url = process.argv[2] ?? 'ws://localhost:9844';
+const relay2Url = process.argv[3] ?? 'ws://localhost:9844';
+
+async function pullIdentities(relayUrl: string): Promise<[any[], any[]]> {
+ const identities: any[] = [];
+ const subs: any[] = [];
+
+ await usingPlaygrounds(async helper => {
+ try {
+ // iterate over every identity
+ for(const [key, value] of await getIdentities(helper)) {
+ // if any of the judgements resulted in a good confirmed outcome, keep this identity
+ if(value.toHuman().judgements.filter((x: any) => x[1] == 'Reasonable' || x[1] == 'KnownGood').length == 0) continue;
+ identities.push([key, value]);
+ }
+
+ const supersOfSubs = await getSupers(helper);
+
+ // iterate over every sub-identity
+ for(const [key, value] of await getSubs(helper)) {
+ // only get subs of the identities interesting to us
+ if(identities.find((x: any) => x[0] == key) == -1) continue;
+ subs.push(constructSubInfo(key, value, supersOfSubs));
+ }
+ } catch (error) {
+ console.error(error);
+ throw Error(`Error during fetching identities on ${relayUrl}`);
+ }
+ }, relayUrl);
+
+ return [identities, subs];
+}
+
+// The utility for pulling identity and sub-identity data
+const checkRelayIdentities = async (): Promise<void> => {
+ const [identitiesOnRelay1, subIdentitiesOnRelay1] = await pullIdentities(relay1Url);
+ const [identitiesOnRelay2, subIdentitiesOnRelay2] = await pullIdentities(relay2Url);
+
+ console.log('identities counts:\t', identitiesOnRelay1.length, identitiesOnRelay2.length);
+ console.log('sub-identities counts:\t', subIdentitiesOnRelay1.length, subIdentitiesOnRelay2.length);
+ console.log();
+
+ try {
+ const matchingAddresses: string[] = [];
+ const inequalIdentities: {[name: string]: [any, any]} = {};
+
+ for(const [key1, value1] of identitiesOnRelay1) {
+ const address = encodeAddress(key1);
+ const identity2 = identitiesOnRelay2.find(([key2, _value2]) => address === encodeAddress(key2));
+ if(!identity2) continue;
+ matchingAddresses.push(address);
+
+ //const [[key2, value2]] = identitiesOnRelay2.splice(index2, 1);
+ const [_key2, value2] = identity2;
+ if(JSON.stringify(value1.info) === JSON.stringify(value2.info)) continue;
+ inequalIdentities[address] = [value1, value2];
+ }
+
+ /*for (const [v1, v2] of Object.values(inequalIdentities)) {
+ console.log(v1.toHuman().info);
+ console.log();
+ console.log(v2.toHuman().info);
+ await new Promise(resolve => setTimeout(resolve, 4000));
+ }*/
+
+ console.log(`Accounts with identities on both relays:\t${matchingAddresses.length}`);
+ console.log(`Sub-identities with conflicting information:\t${Object.entries(inequalIdentities).length}`);
+ console.log();
+
+ const inequalSubIdentities = [];
+ let matchesFound = 0;
+ for(const address of matchingAddresses) {
+ const sub1 = subIdentitiesOnRelay1.find(([key1, _value1]) => address === encodeAddress(key1));
+ if(!sub1) continue;
+ const sub2 = subIdentitiesOnRelay2.find(([key2, _value2]) => address === encodeAddress(key2));
+ if(!sub2) continue;
+
+ const [value1, value2] = [sub1[1], sub2[1]];
+ matchesFound++;
+
+ if(JSON.stringify(value1[1]) === JSON.stringify(value2[1])) {
+ continue;
+ }
+ inequalSubIdentities.push([value1, value2]);
+ }
+
+ /*for (const [v1, v2] of inequalSubIdentities) {
+ console.log(v1[1]);
+ console.log();
+ console.log(v2[1]);
+ await new Promise(resolve => setTimeout(resolve, 300));
+ }*/
+ console.log(`Accounts with sub-identities on both relays:\t${matchesFound}`);
+ console.log(`Of them, those with conflicting sub-identities:\t${inequalSubIdentities.length}`);
+ } catch (error) {
+ console.error(error);
+ throw Error('Error during comparison');
+ }
+};
+
+if(process.argv[1] === module.filename)
+ checkRelayIdentities().catch(() => process.exit(1));
js-packages/tests/util/setCode.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/util/setCode.ts
@@ -0,0 +1,15 @@
+import {readFile} from 'fs/promises';
+import {u8aToHex} from '@polkadot/util';
+import {usingPlaygrounds} from './index.js';
+
+const codePath = process.argv[2];
+if(!codePath) throw new Error('missing code path argument');
+
+const code = await readFile(codePath);
+
+await usingPlaygrounds(async (helper, privateKey) => {
+ const alice = await privateKey('//Alice');
+ await helper.getSudo().executeExtrinsicUncheckedWeight(alice, 'api.tx.system.setCode', [u8aToHex(code)]);
+});
+// We miss disconnect/unref somewhere.
+process.exit(0);
js-packages/tests/vesting.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/vesting.test.ts
@@ -0,0 +1,151 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from './util/index.js';
+
+describe('Vesting', () => {
+ let donor: IKeyringPair;
+ let nominal: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ donor = await privateKey({url: import.meta.url});
+ nominal = helper.balance.getOneTokenNominal();
+ });
+ });
+
+ itSub('can perform vestedTransfer and claim tokens', async ({helper}) => {
+ // arrange
+ const [sender, recepient] = await helper.arrange.createAccounts([1000n, 1n], donor);
+ const currentRelayBlock = await helper.chain.getRelayBlockNumber();
+ const SCHEDULE_1_PERIOD = 6n; // 6 blocks one period
+ const SCHEDULE_1_START = currentRelayBlock + 6n; // Block when 1 schedule starts
+ const SCHEDULE_2_PERIOD = 12n; // 12 blocks one period
+ const SCHEDULE_2_START = currentRelayBlock + 12n; // Block when 2 schedule starts
+ const schedule1 = {start: SCHEDULE_1_START, period: SCHEDULE_1_PERIOD, periodCount: 2n, perPeriod: 50n * nominal};
+ const schedule2 = {start: SCHEDULE_2_START, period: SCHEDULE_2_PERIOD, periodCount: 2n, perPeriod: 100n * nominal};
+
+ // act
+ await helper.balance.vestedTransfer(sender, recepient.address, schedule1);
+ await helper.balance.vestedTransfer(sender, recepient.address, schedule2);
+ let schedule = await helper.balance.getVestingSchedules(recepient.address);
+
+ // check senders balance after vesting:
+ let balanceSender = await helper.balance.getSubstrateFull(sender.address);
+ expect(balanceSender.free / nominal).to.eq(699n);
+ expect(balanceSender.frozen).to.eq(0n);
+ expect(balanceSender.reserved).to.eq(0n);
+
+ // check recepient balance after vesting:
+ let balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
+ expect(balanceRecepient.free).to.eq(301n * nominal);
+ expect(balanceRecepient.frozen).to.eq(300n * nominal);
+ expect(balanceRecepient.reserved).to.eq(0n);
+
+ // Schedules list correct:
+ expect(schedule).to.has.length(2);
+ expect(schedule[0]).to.deep.eq(schedule1);
+ expect(schedule[1]).to.deep.eq(schedule2);
+
+ // Wait first part available:
+ await helper.wait.forRelayBlockNumber(SCHEDULE_1_START + SCHEDULE_1_PERIOD);
+ await helper.balance.claim(recepient);
+
+ // check recepient balance after claim (50 tokens claimed, 250 left):
+ balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
+ expect(balanceRecepient.free / nominal).to.eq(300n);
+ expect(balanceRecepient.frozen).to.eq(250n * nominal);
+ expect(balanceRecepient.reserved).to.eq(0n);
+
+ // Wait first schedule ends and first part od second schedule:
+ await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD);
+ await helper.balance.claim(recepient);
+
+ // check recepient balance after second claim (150 tokens claimed, 100 left):
+ balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
+ expect(balanceRecepient.free / nominal).to.eq(300n);
+ expect(balanceRecepient.frozen).to.eq(100n * nominal);
+ expect(balanceRecepient.reserved).to.eq(0n);
+
+ // Schedules list contain 1 vesting:
+ schedule = await helper.balance.getVestingSchedules(recepient.address);
+ expect(schedule).to.has.length(1);
+ expect(schedule[0]).to.deep.eq(schedule2);
+
+ // Wait 2 schedule ends:
+ await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD * 2n);
+ await helper.balance.claim(recepient);
+
+ // check recepient balance after second claim (100 tokens claimed, 0 left):
+ balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);
+ expect(balanceRecepient.free / nominal).to.eq(300n);
+ expect(balanceRecepient.frozen).to.eq(0n);
+ expect(balanceRecepient.reserved).to.eq(0n);
+
+ // check sender balance does not changed:
+ balanceSender = await helper.balance.getSubstrateFull(sender.address);
+ expect(balanceSender.free / nominal).to.eq(699n);
+ expect(balanceSender.frozen).to.eq(0n);
+ expect(balanceSender.reserved).to.eq(0n);
+ });
+
+ itSub('cannot send more tokens than have', async ({helper}) => {
+ const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor);
+ const schedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 100n * nominal};
+ const manyPeriodsSchedule = {start: 0n, period: 1n, periodCount: 100n, perPeriod: 10n * nominal};
+ const oneBigSumSchedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 5000n * nominal};
+
+ // Sender cannot send vestedTransfer to self or other
+ await expect(helper.balance.vestedTransfer(sender, sender.address, manyPeriodsSchedule)).to.be.rejectedWith(/^vesting.InsufficientBalanceToLock$/);
+ await expect(helper.balance.vestedTransfer(sender, receiver.address, manyPeriodsSchedule)).to.be.rejectedWith(/^Token: FundsUnavailable$/);
+ await expect(helper.balance.vestedTransfer(sender, sender.address, oneBigSumSchedule)).to.be.rejectedWith(/^vesting.InsufficientBalanceToLock$/);
+ await expect(helper.balance.vestedTransfer(sender, receiver.address, oneBigSumSchedule)).to.be.rejectedWith(/^Token: FundsUnavailable$/);
+
+ const balanceSender = await helper.balance.getSubstrateFull(sender.address);
+ const balanceReceiver = await helper.balance.getSubstrateFull(receiver.address);
+
+ // Sender's balance has not changed
+ expect(balanceSender.free / nominal).to.eq(999n);
+ expect(balanceSender.frozen).to.eq(0n);
+ expect(balanceSender.reserved).to.eq(0n);
+
+ // Receiver's balance has not changed
+ expect(balanceReceiver.free).to.be.eq(1n * nominal);
+ expect(balanceReceiver.frozen).to.be.eq(0n);
+ expect(balanceReceiver.reserved).to.be.eq(0n);
+
+ // Receiver cannot send vestedTransfer back because of freeze
+ await expect(helper.balance.vestedTransfer(receiver, sender.address, schedule)).to.be.rejectedWith(/^Token: FundsUnavailable$/);
+ });
+
+ itSub('cannot send vestedTransfer with incorrect parameters', async ({helper}) => {
+ const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor);
+ const incorrectperiodSchedule = {start: 0n, period: 0n, periodCount: 10n, perPeriod: 10n * nominal};
+ const incorrectPeriodCountSchedule = {start: 0n, period: 1n, periodCount: 0n, perPeriod: 10n * nominal};
+ const incorrectPerPeriodSchedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 0n * nominal};
+
+ await expect(helper.balance.vestedTransfer(sender, sender.address, incorrectperiodSchedule)).to.be.rejectedWith(/vesting.ZeroVestingPeriod/);
+ await expect(helper.balance.vestedTransfer(sender, receiver.address, incorrectPeriodCountSchedule)).to.be.rejectedWith(/vesting.ZeroVestingPeriod/);
+ await expect(helper.balance.vestedTransfer(sender, receiver.address, incorrectPerPeriodSchedule)).to.be.rejectedWith(/vesting.AmountLow/);
+
+ const balanceSender = await helper.balance.getSubstrateFull(sender.address);
+ // Sender's balance has not changed
+ expect(balanceSender.free / nominal).to.eq(999n);
+ expect(balanceSender.frozen).to.eq(0n);
+ expect(balanceSender.reserved).to.eq(0n);
+ });
+});
js-packages/tests/xcm/lowLevelXcmQuartz.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/xcm/lowLevelXcmQuartz.test.ts
@@ -0,0 +1,364 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingMoonriverPlaygrounds, usingShidenPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
+import {QUARTZ_CHAIN, QTZ_DECIMALS, SHIDEN_DECIMALS, karuraUrl, moonriverUrl, shidenUrl, SAFE_XCM_VERSION, XcmTestHelper, TRANSFER_AMOUNT, SENDER_BUDGET, relayUrl} from './xcm.types.js';
+import {hexToString} from '@polkadot/util';
+
+const testHelper = new XcmTestHelper('quartz');
+
+describeXCM('[XCMLL] Integration test: Exchanging tokens with Karura', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ const metadata = {
+ name: 'Quartz',
+ symbol: 'QTZ',
+ decimals: 18,
+ minimalBalance: 1000000000000000000n,
+ };
+
+ const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>
+ hexToString(v.toJSON()['symbol'])) as string[];
+
+ if(!assets.includes('QTZ')) {
+ await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+ } else {
+ console.log('QTZ token already registered on Karura assetRegistry pallet');
+ }
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
+ });
+ });
+
+ itSub('Should connect and send QTZ to Karura', async () => {
+ await testHelper.sendUnqTo('karura', randomAccount);
+ });
+
+ itSub('Should connect to Karura and send QTZ back', async () => {
+ await testHelper.sendUnqBack('karura', alice, randomAccount);
+ });
+
+ itSub('Karura can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('karura', alice);
+ });
+});
+// These tests are relevant only when
+// the the corresponding foreign assets are not registered
+describeXCM('[XCMLL] Integration test: Quartz rejects non-native tokens', () => {
+ let alice: IKeyringPair;
+
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+
+
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+ });
+
+ itSub('Quartz rejects KAR tokens from Karura', async () => {
+ await testHelper.rejectNativeTokensFrom('karura', alice);
+ });
+
+ itSub('Quartz rejects MOVR tokens from Moonriver', async () => {
+ await testHelper.rejectNativeTokensFrom('moonriver', alice);
+ });
+
+ itSub('Quartz rejects SDN tokens from Shiden', async () => {
+ await testHelper.rejectNativeTokensFrom('shiden', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: Exchanging QTZ with Moonriver', () => {
+ // Quartz constants
+ let alice: IKeyringPair;
+ let quartzAssetLocation;
+
+ let randomAccountQuartz: IKeyringPair;
+ let randomAccountMoonriver: IKeyringPair;
+
+ // Moonriver constants
+ let assetId: string;
+
+ const quartzAssetMetadata = {
+ name: 'xcQuartz',
+ symbol: 'xcQTZ',
+ decimals: 18,
+ isFrozen: false,
+ minimalBalance: 1n,
+ };
+
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);
+
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const alithAccount = helper.account.alithAccount();
+ const baltatharAccount = helper.account.baltatharAccount();
+ const dorothyAccount = helper.account.dorothyAccount();
+
+ randomAccountMoonriver = helper.account.create();
+
+ // >>> Sponsoring Dorothy >>>
+ console.log('Sponsoring Dorothy.......');
+ await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring Dorothy.......DONE');
+ // <<< Sponsoring Dorothy <<<
+
+ quartzAssetLocation = {
+ XCM: {
+ parents: 1,
+ interior: {X1: {Parachain: QUARTZ_CHAIN}},
+ },
+ };
+ const existentialDeposit = 1n;
+ const isSufficient = true;
+ const unitsPerSecond = 1n;
+ const numAssetsWeightHint = 0;
+ if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {
+ console.log('Quartz asset already registered on Moonriver');
+ } else {
+ const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
+ location: quartzAssetLocation,
+ metadata: quartzAssetMetadata,
+ existentialDeposit,
+ isSufficient,
+ unitsPerSecond,
+ numAssetsWeightHint,
+ });
+
+ console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
+
+ await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
+ }
+ // >>> Acquire Quartz AssetId Info on Moonriver >>>
+ console.log('Acquire Quartz AssetId Info on Moonriver.......');
+
+ assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();
+
+ console.log('QTZ asset ID is %s', assetId);
+ console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');
+ // >>> Acquire Quartz AssetId Info on Moonriver >>>
+
+ // >>> Sponsoring random Account >>>
+ console.log('Sponsoring random Account.......');
+ await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring random Account.......DONE');
+ // <<< Sponsoring random Account <<<
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
+ });
+ });
+
+ itSub('Should connect and send QTZ to Moonriver', async () => {
+ await testHelper.sendUnqTo('moonriver', randomAccountQuartz, randomAccountMoonriver);
+ });
+
+ itSub('Should connect to Moonriver and send QTZ back', async () => {
+ await testHelper.sendUnqBack('moonriver', alice, randomAccountQuartz);
+ });
+
+ itSub('Moonriver can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('moonriver', alice);
+ });
+
+ itSub('Should not accept reserve transfer of QTZ from Moonriver', async () => {
+ await testHelper.rejectReserveTransferUNQfrom('moonriver', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: Exchanging tokens with Shiden', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ const QTZ_ASSET_ID_ON_SHIDEN = 18_446_744_073_709_551_633n; // The value is taken from the live Shiden
+ const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; // The value is taken from the live Shiden
+
+ // Quartz -> Shiden
+ const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden
+ const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ randomAccount = helper.arrange.createEmptyAccount();
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
+ console.log('sender: ', randomAccount.address);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
+ console.log('1. Create foreign asset and metadata');
+ await helper.getSudo().assets.forceCreate(
+ alice,
+ QTZ_ASSET_ID_ON_SHIDEN,
+ alice.address,
+ QTZ_MINIMAL_BALANCE_ON_SHIDEN,
+ );
+
+ await helper.assets.setMetadata(
+ alice,
+ QTZ_ASSET_ID_ON_SHIDEN,
+ 'Quartz',
+ 'QTZ',
+ Number(QTZ_DECIMALS),
+ );
+
+ console.log('2. Register asset location on Shiden');
+ const assetLocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
+
+ console.log('3. Set QTZ payment for XCM execution on Shiden');
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+ } else {
+ console.log('QTZ is already registered on Shiden');
+ }
+ console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, shidenInitialBalance);
+ });
+ });
+
+ itSub('Should connect and send QTZ to Shiden', async () => {
+ await testHelper.sendUnqTo('shiden', randomAccount);
+ });
+
+ itSub('Should connect to Shiden and send QTZ back', async () => {
+ await testHelper.sendUnqBack('shiden', alice, randomAccount);
+ });
+
+ itSub('Shiden can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('shiden', alice);
+ });
+
+ itSub('Should not accept reserve transfer of QTZ from Shiden', async () => {
+ await testHelper.rejectReserveTransferUNQfrom('shiden', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {
+ let sudoer: IKeyringPair;
+
+ before(async function () {
+ await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {
+ sudoer = await privateKey('//Alice');
+ });
+ });
+
+ // At the moment there is no reliable way
+ // to establish the correspondence between the `ExecutedDownward` event
+ // and the relay's sent message due to `SetTopic` instruction
+ // containing an unpredictable topic silently added by the relay's messages on the router level.
+ // This changes the message hash on arrival to our chain.
+ //
+ // See:
+ // * The relay's router: https://github.com/paritytech/polkadot-sdk/blob/f60318f68687e601c47de5ad5ca88e2c3f8139a7/polkadot/runtime/westend/src/xcm_config.rs#L83
+ // * The `WithUniqueTopic` helper: https://github.com/paritytech/polkadot-sdk/blob/945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e/polkadot/xcm/xcm-builder/src/routing.rs#L36
+ //
+ // Because of this, we insert time gaps between tests so
+ // different `ExecutedDownward` events won't interfere with each other.
+ afterEach(async () => {
+ await usingPlaygrounds(async (helper) => {
+ await helper.wait.newBlocks(3);
+ });
+ });
+
+ itSub('The relay can set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');
+ });
+
+ itSub('The relay can batch set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');
+ });
+
+ itSub('The relay can batchAll set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');
+ });
+
+ itSub('The relay can forceBatch set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');
+ });
+
+ itSub('[negative] The relay cannot set balance', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');
+ });
+
+ itSub('[negative] The relay cannot set balance via batch', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');
+ });
+
+ itSub('[negative] The relay cannot set balance via batchAll', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');
+ });
+
+ itSub('[negative] The relay cannot set balance via forceBatch', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');
+ });
+
+ itSub('[negative] The relay cannot set balance via dispatchAs', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');
+ });
+});
js-packages/tests/xcm/lowLevelXcmUnique.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/xcm/lowLevelXcmUnique.test.ts
@@ -0,0 +1,430 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import config from '../config.js';
+import {itSub, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
+import {nToBigInt} from '@polkadot/util';
+import {hexToString} from '@polkadot/util';
+import {ASTAR_DECIMALS, SAFE_XCM_VERSION, SENDER_BUDGET, UNIQUE_CHAIN, UNQ_DECIMALS, XcmTestHelper, acalaUrl, astarUrl, moonbeamUrl, polkadexUrl, relayUrl, uniqueAssetId} from './xcm.types.js';
+
+const testHelper = new XcmTestHelper('unique');
+
+
+
+
+describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ console.log(config.acalaUrl);
+ randomAccount = helper.arrange.createEmptyAccount();
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ const metadata = {
+ name: 'Unique Network',
+ symbol: 'UNQ',
+ decimals: 18,
+ minimalBalance: 1250_000_000_000_000_000n,
+ };
+ const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>
+ hexToString(v.toJSON()['symbol'])) as string[];
+
+ if(!assets.includes('UNQ')) {
+ await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+ } else {
+ console.log('UNQ token already registered on Acala assetRegistry pallet');
+ }
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Acala', async () => {
+ await testHelper.sendUnqTo('acala', randomAccount);
+ });
+
+ itSub('Should connect to Acala and send UNQ back', async () => {
+ await testHelper.sendUnqBack('acala', alice, randomAccount);
+ });
+
+ itSub('Acala can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('acala', alice);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Acala', async () => {
+ await testHelper.rejectReserveTransferUNQfrom('acala', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: Exchanging tokens with Polkadex', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ randomAccount = helper.arrange.createEmptyAccount();
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))
+ .toJSON() as [])
+ .map(nToBigInt).length != 0;
+ /*
+ Check whether the Unique token has been added
+ to the whitelist, since an error will occur
+ if it is added again. Needed for debugging
+ when this test is run multiple times.
+ */
+ if(isWhitelisted) {
+ console.log('UNQ token is already whitelisted on Polkadex');
+ } else {
+ await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);
+ }
+
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Polkadex', async () => {
+ await testHelper.sendUnqTo('polkadex', randomAccount);
+ });
+
+
+ itSub('Should connect to Polkadex and send UNQ back', async () => {
+ await testHelper.sendUnqBack('polkadex', alice, randomAccount);
+ });
+
+ itSub('Polkadex can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('polkadex', alice);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Polkadex', async () => {
+ await testHelper.rejectReserveTransferUNQfrom('polkadex', alice);
+ });
+});
+
+// These tests are relevant only when
+// the the corresponding foreign assets are not registered
+describeXCM('[XCMLL] Integration test: Unique rejects non-native tokens', () => {
+ let alice: IKeyringPair;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+ });
+
+ itSub('Unique rejects ACA tokens from Acala', async () => {
+ await testHelper.rejectNativeTokensFrom('acala', alice);
+ });
+
+ itSub('Unique rejects GLMR tokens from Moonbeam', async () => {
+ await testHelper.rejectNativeTokensFrom('moonbeam', alice);
+ });
+
+ itSub('Unique rejects ASTR tokens from Astar', async () => {
+ await testHelper.rejectNativeTokensFrom('astar', alice);
+ });
+
+ itSub('Unique rejects PDX tokens from Polkadex', async () => {
+ await testHelper.rejectNativeTokensFrom('polkadex', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: Exchanging UNQ with Moonbeam', () => {
+ // Unique constants
+ let alice: IKeyringPair;
+ let uniqueAssetLocation;
+
+ let randomAccountUnique: IKeyringPair;
+ let randomAccountMoonbeam: IKeyringPair;
+
+ // Moonbeam constants
+ let assetId: string;
+
+ const uniqueAssetMetadata = {
+ name: 'xcUnique',
+ symbol: 'xcUNQ',
+ decimals: 18,
+ isFrozen: false,
+ minimalBalance: 1n,
+ };
+
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);
+
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const alithAccount = helper.account.alithAccount();
+ const baltatharAccount = helper.account.baltatharAccount();
+ const dorothyAccount = helper.account.dorothyAccount();
+
+ randomAccountMoonbeam = helper.account.create();
+
+ // >>> Sponsoring Dorothy >>>
+ console.log('Sponsoring Dorothy.......');
+ await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring Dorothy.......DONE');
+ // <<< Sponsoring Dorothy <<<
+ uniqueAssetLocation = {
+ XCM: {
+ parents: 1,
+ interior: {X1: {Parachain: UNIQUE_CHAIN}},
+ },
+ };
+ const existentialDeposit = 1n;
+ const isSufficient = true;
+ const unitsPerSecond = 1n;
+ const numAssetsWeightHint = 0;
+
+ if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {
+ console.log('Unique asset already registered on Moonbeam');
+ } else {
+ const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
+ location: uniqueAssetLocation,
+ metadata: uniqueAssetMetadata,
+ existentialDeposit,
+ isSufficient,
+ unitsPerSecond,
+ numAssetsWeightHint,
+ });
+
+ console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
+
+ await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);
+ }
+
+ // >>> Acquire Unique AssetId Info on Moonbeam >>>
+ console.log('Acquire Unique AssetId Info on Moonbeam.......');
+
+ assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();
+
+ console.log('UNQ asset ID is %s', assetId);
+ console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');
+
+ // >>> Sponsoring random Account >>>
+ console.log('Sponsoring random Account.......');
+ await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring random Account.......DONE');
+ // <<< Sponsoring random Account <<<
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Moonbeam', async () => {
+ await testHelper.sendUnqTo('moonbeam', randomAccountUnique, randomAccountMoonbeam);
+ });
+
+ itSub('Should connect to Moonbeam and send UNQ back', async () => {
+ await testHelper.sendUnqBack('moonbeam', alice, randomAccountUnique);
+ });
+
+ itSub('Moonbeam can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('moonbeam', alice);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Moonbeam', async () => {
+ await testHelper.rejectReserveTransferUNQfrom('moonbeam', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: Exchanging tokens with Astar', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; // The value is taken from the live Astar
+ const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; // The value is taken from the live Astar
+
+ // Unique -> Astar
+ const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.
+ const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ randomAccount = helper.arrange.createEmptyAccount();
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
+ console.log('randomAccount', randomAccount.address);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {
+ console.log('1. Create foreign asset and metadata');
+ await helper.getSudo().assets.forceCreate(
+ alice,
+ UNQ_ASSET_ID_ON_ASTAR,
+ alice.address,
+ UNQ_MINIMAL_BALANCE_ON_ASTAR,
+ );
+
+ await helper.assets.setMetadata(
+ alice,
+ UNQ_ASSET_ID_ON_ASTAR,
+ 'Unique Network',
+ 'UNQ',
+ Number(UNQ_DECIMALS),
+ );
+
+ console.log('2. Register asset location on Astar');
+ const assetLocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);
+
+ console.log('3. Set UNQ payment for XCM execution on Astar');
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+ } else {
+ console.log('UNQ is already registered on Astar');
+ }
+ console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Astar', async () => {
+ await testHelper.sendUnqTo('astar', randomAccount);
+ });
+
+ itSub('Should connect to Astar and send UNQ back', async () => {
+ await testHelper.sendUnqBack('astar', alice, randomAccount);
+ });
+
+ itSub('Astar can send only up to its balance', async () => {
+ await testHelper.sendOnlyOwnedBalance('astar', alice);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Astar', async () => {
+ await testHelper.rejectReserveTransferUNQfrom('astar', alice);
+ });
+});
+
+describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {
+ let sudoer: IKeyringPair;
+
+ before(async function () {
+ await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {
+ sudoer = await privateKey('//Alice');
+ });
+ });
+
+ // At the moment there is no reliable way
+ // to establish the correspondence between the `ExecutedDownward` event
+ // and the relay's sent message due to `SetTopic` instruction
+ // containing an unpredictable topic silently added by the relay's messages on the router level.
+ // This changes the message hash on arrival to our chain.
+ //
+ // See:
+ // * The relay's router: https://github.com/paritytech/polkadot-sdk/blob/f60318f68687e601c47de5ad5ca88e2c3f8139a7/polkadot/runtime/westend/src/xcm_config.rs#L83
+ // * The `WithUniqueTopic` helper: https://github.com/paritytech/polkadot-sdk/blob/945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e/polkadot/xcm/xcm-builder/src/routing.rs#L36
+ //
+ // Because of this, we insert time gaps between tests so
+ // different `ExecutedDownward` events won't interfere with each other.
+ afterEach(async () => {
+ await usingPlaygrounds(async (helper) => {
+ await helper.wait.newBlocks(3);
+ });
+ });
+
+ itSub('The relay can set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');
+ });
+
+ itSub('The relay can batch set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');
+ });
+
+ itSub('The relay can batchAll set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');
+ });
+
+ itSub('The relay can forceBatch set storage', async () => {
+ await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');
+ });
+
+ itSub('[negative] The relay cannot set balance', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');
+ });
+
+ itSub('[negative] The relay cannot set balance via batch', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');
+ });
+
+ itSub('[negative] The relay cannot set balance via batchAll', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');
+ });
+
+ itSub('[negative] The relay cannot set balance via forceBatch', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');
+ });
+
+ itSub('[negative] The relay cannot set balance via dispatchAs', async () => {
+ await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');
+ });
+});
js-packages/tests/xcm/xcm.types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/xcm/xcm.types.ts
@@ -0,0 +1,621 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {hexToString} from '@polkadot/util';
+import {expect, usingAcalaPlaygrounds, usingAstarPlaygrounds, usingKaruraPlaygrounds, usingMoonbeamPlaygrounds, usingMoonriverPlaygrounds, usingPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds, usingShidenPlaygrounds} from '../util/index.js';
+import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
+import config from '../config.js';
+
+export const UNIQUE_CHAIN = +(process.env.RELAY_UNIQUE_ID || 2037);
+export const STATEMINT_CHAIN = +(process.env.RELAY_STATEMINT_ID || 1000);
+export const ACALA_CHAIN = +(process.env.RELAY_ACALA_ID || 2000);
+export const MOONBEAM_CHAIN = +(process.env.RELAY_MOONBEAM_ID || 2004);
+export const ASTAR_CHAIN = +(process.env.RELAY_ASTAR_ID || 2006);
+export const POLKADEX_CHAIN = +(process.env.RELAY_POLKADEX_ID || 2040);
+
+export const QUARTZ_CHAIN = +(process.env.RELAY_QUARTZ_ID || 2095);
+export const STATEMINE_CHAIN = +(process.env.RELAY_STATEMINE_ID || 1000);
+export const KARURA_CHAIN = +(process.env.RELAY_KARURA_ID || 2000);
+export const MOONRIVER_CHAIN = +(process.env.RELAY_MOONRIVER_ID || 2023);
+export const SHIDEN_CHAIN = +(process.env.RELAY_SHIDEN_ID || 2007);
+
+export const relayUrl = config.relayUrl;
+export const statemintUrl = config.statemintUrl;
+export const statemineUrl = config.statemineUrl;
+
+export const acalaUrl = config.acalaUrl;
+export const moonbeamUrl = config.moonbeamUrl;
+export const astarUrl = config.astarUrl;
+export const polkadexUrl = config.polkadexUrl;
+
+export const karuraUrl = config.karuraUrl;
+export const moonriverUrl = config.moonriverUrl;
+export const shidenUrl = config.shidenUrl;
+
+export const SAFE_XCM_VERSION = 3;
+
+
+export const RELAY_DECIMALS = 12;
+export const STATEMINE_DECIMALS = 12;
+export const KARURA_DECIMALS = 12;
+export const SHIDEN_DECIMALS = 18n;
+export const QTZ_DECIMALS = 18n;
+
+export const ASTAR_DECIMALS = 18n;
+export const UNQ_DECIMALS = 18n;
+
+export const maxWaitBlocks = 6;
+
+export const uniqueMultilocation = {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+};
+export const uniqueVersionedMultilocation = {
+ V3: uniqueMultilocation,
+};
+
+export const uniqueAssetId = {
+ Concrete: uniqueMultilocation,
+};
+
+export const expectFailedToTransact = async (helper: DevUniqueHelper, messageSent: any) => {
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+};
+export const expectUntrustedReserveLocationFail = async (helper: DevUniqueHelper, messageSent: any) => {
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+};
+
+export const expectDownwardXcmNoPermission = async (helper: DevUniqueHelper) => {
+ // The correct messageHash for downward messages can't be reliably obtained
+ await helper.wait.expectEvent(maxWaitBlocks, Event.DmpQueue.ExecutedDownward, event => event.outcome.asIncomplete[1].isNoPermission);
+};
+
+export const expectDownwardXcmComplete = async (helper: DevUniqueHelper) => {
+ // The correct messageHash for downward messages can't be reliably obtained
+ await helper.wait.expectEvent(maxWaitBlocks, Event.DmpQueue.ExecutedDownward, event => event.outcome.isComplete);
+};
+
+export const NETWORKS = {
+ acala: usingAcalaPlaygrounds,
+ astar: usingAstarPlaygrounds,
+ polkadex: usingPolkadexPlaygrounds,
+ moonbeam: usingMoonbeamPlaygrounds,
+ moonriver: usingMoonriverPlaygrounds,
+ karura: usingKaruraPlaygrounds,
+ shiden: usingShidenPlaygrounds,
+} as const;
+type NetworkNames = keyof typeof NETWORKS;
+
+type NativeRuntime = 'opal' | 'quartz' | 'unique';
+
+export function mapToChainId(networkName: keyof typeof NETWORKS): number {
+ switch (networkName) {
+ case 'acala':
+ return ACALA_CHAIN;
+ case 'astar':
+ return ASTAR_CHAIN;
+ case 'moonbeam':
+ return MOONBEAM_CHAIN;
+ case 'polkadex':
+ return POLKADEX_CHAIN;
+ case 'moonriver':
+ return MOONRIVER_CHAIN;
+ case 'karura':
+ return KARURA_CHAIN;
+ case 'shiden':
+ return SHIDEN_CHAIN;
+ }
+}
+
+export function mapToChainUrl(networkName: NetworkNames): string {
+ switch (networkName) {
+ case 'acala':
+ return acalaUrl;
+ case 'astar':
+ return astarUrl;
+ case 'moonbeam':
+ return moonbeamUrl;
+ case 'polkadex':
+ return polkadexUrl;
+ case 'moonriver':
+ return moonriverUrl;
+ case 'karura':
+ return karuraUrl;
+ case 'shiden':
+ return shidenUrl;
+ }
+}
+
+export function getDevPlayground(name: NetworkNames) {
+ return NETWORKS[name];
+}
+
+export const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;
+export const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;
+export const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;
+export const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;
+export const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;
+
+export class XcmTestHelper {
+ private _balanceUniqueTokenInit: bigint = 0n;
+ private _balanceUniqueTokenMiddle: bigint = 0n;
+ private _balanceUniqueTokenFinal: bigint = 0n;
+ private _unqFees: bigint = 0n;
+ private _nativeRuntime: NativeRuntime;
+
+ constructor(runtime: NativeRuntime) {
+ this._nativeRuntime = runtime;
+ }
+
+ private _getNativeId() {
+ switch (this._nativeRuntime) {
+ case 'opal':
+ // To-Do
+ return 1001;
+ case 'quartz':
+ return QUARTZ_CHAIN;
+ case 'unique':
+ return UNIQUE_CHAIN;
+ }
+ }
+
+ private _isAddress20FormatFor(network: NetworkNames) {
+ switch (network) {
+ case 'moonbeam':
+ case 'moonriver':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private _runtimeVersionedMultilocation() {
+ return {
+ V3: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: this._getNativeId(),
+ },
+ },
+ },
+ };
+ }
+
+ private _uniqueChainMultilocationForRelay() {
+ return {
+ V3: {
+ parents: 0,
+ interior: {
+ X1: {Parachain: this._getNativeId()},
+ },
+ },
+ };
+ }
+
+ async sendUnqTo(
+ networkName: keyof typeof NETWORKS,
+ randomAccount: IKeyringPair,
+ randomAccountOnTargetChain = randomAccount,
+ ) {
+ const networkUrl = mapToChainUrl(networkName);
+ const targetPlayground = getDevPlayground(networkName);
+ await usingPlaygrounds(async (helper) => {
+ this._balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: mapToChainId(networkName),
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: (
+ this._isAddress20FormatFor(networkName) ?
+ {
+ AccountKey20: {
+ network: 'Any',
+ key: randomAccountOnTargetChain.address,
+ },
+ }
+ :
+ {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccountOnTargetChain.addressRaw,
+ },
+ }
+ ),
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ this._balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
+
+ this._unqFees = this._balanceUniqueTokenInit - this._balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[%s -> %s] transaction fees: %s', this._nativeRuntime, networkName, helper.util.bigIntToDecimals(this._unqFees));
+ expect(this._unqFees > 0n, 'Negative fees, looks like nothing was transferred').to.be.true;
+
+ await targetPlayground(networkUrl, async (helper) => {
+ /*
+ Since only the parachain part of the Polkadex
+ infrastructure is launched (without their
+ solochain validators), processing incoming
+ assets will lead to an error.
+ This error indicates that the Polkadex chain
+ received a message from the Unique network,
+ since the hash is being checked to ensure
+ it matches what was sent.
+ */
+ if(networkName == 'polkadex') {
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);
+ } else {
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == messageSent.messageHash);
+ }
+ });
+
+ });
+ }
+
+ async sendUnqBack(
+ networkName: keyof typeof NETWORKS,
+ sudoer: IKeyringPair,
+ randomAccountOnUnq: IKeyringPair,
+ ) {
+ const networkUrl = mapToChainUrl(networkName);
+
+ const targetPlayground = getDevPlayground(networkName);
+ await usingPlaygrounds(async (helper) => {
+
+ const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ randomAccountOnUnq.addressRaw,
+ {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: this._getNativeId()},
+ },
+ },
+ },
+ SENDBACK_AMOUNT,
+ );
+
+ let xcmProgramSent: any;
+
+
+ await targetPlayground(networkUrl, async (helper) => {
+ if('getSudo' in helper) {
+ await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), xcmProgram);
+ xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ } else if('fastDemocracy' in helper) {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), xcmProgram]);
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
+ xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);
+
+ this._balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountOnUnq.address);
+
+ expect(this._balanceUniqueTokenFinal).to.be.equal(this._balanceUniqueTokenInit - this._unqFees - STAYED_ON_TARGET_CHAIN);
+
+ });
+ }
+
+ async sendOnlyOwnedBalance(
+ networkName: keyof typeof NETWORKS,
+ sudoer: IKeyringPair,
+ ) {
+ const networkUrl = mapToChainUrl(networkName);
+ const targetPlayground = getDevPlayground(networkName);
+
+ const targetChainBalance = 10000n * (10n ** UNQ_DECIMALS);
+
+ await usingPlaygrounds(async (helper) => {
+ const targetChainSovereignAccount = helper.address.paraSiblingSovereignAccount(mapToChainId(networkName));
+ await helper.getSudo().balance.setBalanceSubstrate(sudoer, targetChainSovereignAccount, targetChainBalance);
+ const moreThanTargetChainHas = 2n * targetChainBalance;
+
+ const targetAccount = helper.arrange.createEmptyAccount();
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanTargetChainHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+
+
+ await targetPlayground(networkUrl, async (helper) => {
+ if('getSudo' in helper) {
+ await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgram);
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ } else if('fastDemocracy' in helper) {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgram]);
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ });
+
+ await expectFailedToTransact(helper, maliciousXcmProgramSent);
+
+ const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+ });
+ }
+
+ async rejectReserveTransferUNQfrom(networkName: keyof typeof NETWORKS, sudoer: IKeyringPair) {
+ const networkUrl = mapToChainUrl(networkName);
+ const targetPlayground = getDevPlayground(networkName);
+
+ await usingPlaygrounds(async (helper) => {
+ const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
+ const targetAccount = helper.arrange.createEmptyAccount();
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: this._getNativeId(),
+ },
+ },
+ },
+ },
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique using full UNQ identification
+ await targetPlayground(networkUrl, async (helper) => {
+ if('getSudo' in helper) {
+ await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId);
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ // Moonbeam case
+ else if('fastDemocracy' in helper) {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId]);
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal(`${networkName} try to act like a reserve location for UNQ using path asset identification`,batchCall);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ });
+
+
+ await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Unique using shortened UNQ identification
+ await targetPlayground(networkUrl, async (helper) => {
+ if('getSudo' in helper) {
+ await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgramHereId);
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ else if('fastDemocracy' in helper) {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramHereId]);
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal(`${networkName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ });
+
+ await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+ }
+
+ async rejectNativeTokensFrom(networkName: keyof typeof NETWORKS, sudoerOnTargetChain: IKeyringPair) {
+ const networkUrl = mapToChainUrl(networkName);
+ const targetPlayground = getDevPlayground(networkName);
+ let messageSent: any;
+
+ await usingPlaygrounds(async (helper) => {
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ helper.arrange.createEmptyAccount().addressRaw,
+ {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: mapToChainId(networkName),
+ },
+ },
+ },
+ },
+ TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT,
+ );
+ await targetPlayground(networkUrl, async (helper) => {
+ if('getSudo' in helper) {
+ await helper.getSudo().xcm.send(sudoerOnTargetChain, this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId);
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ } else if('fastDemocracy' in helper) {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId]);
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal(`${networkName} sending native tokens to the Unique via fast democracy`, batchCall);
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ }
+ });
+ await expectFailedToTransact(helper, messageSent);
+ });
+ }
+
+ private async _relayXcmTransactSetStorage(variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch') {
+ // eslint-disable-next-line require-await
+ return await usingPlaygrounds(async (helper) => {
+ const relayForceKV = () => {
+ const random = Math.random();
+ const key = `relay-forced-key (instance: ${random})`;
+ const val = `relay-forced-value (instance: ${random})`;
+ const call = helper.constructApiCall('api.tx.system.setStorage', [[[key, val]]]).method.toHex();
+
+ return {
+ call,
+ key,
+ val,
+ };
+ };
+
+ if(variant == 'plain') {
+ const kv = relayForceKV();
+ return {
+ program: helper.arrange.makeUnpaidSudoTransactProgram({
+ weightMultiplier: 1,
+ call: kv.call,
+ }),
+ kvs: [kv],
+ };
+ } else {
+ const kv0 = relayForceKV();
+ const kv1 = relayForceKV();
+
+ const batchCall = helper.constructApiCall(`api.tx.utility.${variant}`, [[kv0.call, kv1.call]]).method.toHex();
+ return {
+ program: helper.arrange.makeUnpaidSudoTransactProgram({
+ weightMultiplier: 2,
+ call: batchCall,
+ }),
+ kvs: [kv0, kv1],
+ };
+ }
+ });
+ }
+
+ async relayIsPermittedToSetStorage(relaySudoer: IKeyringPair, variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch') {
+ const {program, kvs} = await this._relayXcmTransactSetStorage(variant);
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ await helper.getSudo().executeExtrinsic(relaySudoer, 'api.tx.xcmPallet.send', [
+ this._uniqueChainMultilocationForRelay(),
+ program,
+ ]);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await expectDownwardXcmComplete(helper);
+
+ for(const kv of kvs) {
+ const forcedValue = await helper.callRpc('api.rpc.state.getStorage', [kv.key]);
+ expect(hexToString(forcedValue.toHex())).to.be.equal(kv.val);
+ }
+ });
+ }
+
+ private async _relayXcmTransactSetBalance(variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch' | 'dispatchAs') {
+ // eslint-disable-next-line require-await
+ return await usingPlaygrounds(async (helper) => {
+ const emptyAccount = helper.arrange.createEmptyAccount().address;
+
+ const forceSetBalanceCall = helper.constructApiCall('api.tx.balances.forceSetBalance', [emptyAccount, 10_000n]).method.toHex();
+
+ let call;
+
+ if(variant == 'plain') {
+ call = forceSetBalanceCall;
+
+ } else if(variant == 'dispatchAs') {
+ call = helper.constructApiCall('api.tx.utility.dispatchAs', [
+ {
+ system: 'Root',
+ },
+ forceSetBalanceCall,
+ ]).method.toHex();
+ } else {
+ call = helper.constructApiCall(`api.tx.utility.${variant}`, [[forceSetBalanceCall]]).method.toHex();
+ }
+
+ return {
+ program: helper.arrange.makeUnpaidSudoTransactProgram({
+ weightMultiplier: 1,
+ call,
+ }),
+ emptyAccount,
+ };
+ });
+ }
+
+ async relayIsNotPermittedToSetBalance(
+ relaySudoer: IKeyringPair,
+ variant: 'plain' | 'batch' | 'batchAll' | 'forceBatch' | 'dispatchAs',
+ ) {
+ const {program, emptyAccount} = await this._relayXcmTransactSetBalance(variant);
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ await helper.getSudo().executeExtrinsic(relaySudoer, 'api.tx.xcmPallet.send', [
+ this._uniqueChainMultilocationForRelay(),
+ program,
+ ]);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await expectDownwardXcmNoPermission(helper);
+ expect(await helper.balance.getSubstrate(emptyAccount)).to.be.equal(0n);
+ });
+ }
+}
js-packages/tests/xcm/xcmOpal.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/xcm/xcmOpal.test.ts
@@ -0,0 +1,409 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import config from '../config.js';
+import {itSub, expect, describeXCM, usingPlaygrounds, usingWestmintPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
+
+const STATEMINE_CHAIN = +(process.env.RELAY_WESTMINT_ID || 1000);
+const UNIQUE_CHAIN = +(process.env.RELAY_OPAL_ID || 2095);
+
+const relayUrl = config.relayUrl;
+const westmintUrl = config.westmintUrl;
+
+const STATEMINE_PALLET_INSTANCE = 50;
+const ASSET_ID = 100;
+const ASSET_METADATA_DECIMALS = 18;
+const ASSET_METADATA_NAME = 'USDT';
+const ASSET_METADATA_DESCRIPTION = 'USDT';
+const ASSET_METADATA_MINIMAL_BALANCE = 1n;
+
+const RELAY_DECIMALS = 12;
+const WESTMINT_DECIMALS = 12;
+
+const TRANSFER_AMOUNT = 1_000_000_000_000_000_000n;
+
+// 10,000.00 (ten thousands) USDT
+const ASSET_AMOUNT = 1_000_000_000_000_000_000_000n;
+
+describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ let balanceStmnBefore: bigint;
+ let balanceStmnAfter: bigint;
+
+ let balanceOpalBefore: bigint;
+ let balanceOpalAfter: bigint;
+ let balanceOpalFinal: bigint;
+
+ let balanceBobBefore: bigint;
+ let balanceBobAfter: bigint;
+ let balanceBobFinal: bigint;
+
+ let balanceBobRelayTokenBefore: bigint;
+ let balanceBobRelayTokenAfter: bigint;
+
+
+ before(async () => {
+ await usingPlaygrounds(async (_helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ bob = await privateKey('//Bob'); // funds donor
+ });
+
+ await usingWestmintPlaygrounds(westmintUrl, async (helper) => {
+ // 350.00 (three hundred fifty) DOT
+ const fundingAmount = 3_500_000_000_000n;
+
+ await helper.assets.create(alice, ASSET_ID, alice.address, ASSET_METADATA_MINIMAL_BALANCE);
+ await helper.assets.setMetadata(alice, ASSET_ID, ASSET_METADATA_NAME, ASSET_METADATA_DESCRIPTION, ASSET_METADATA_DECIMALS);
+ await helper.assets.mint(alice, ASSET_ID, alice.address, ASSET_AMOUNT);
+
+ // funding parachain sovereing account (Parachain: 2095)
+ const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);
+ await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, fundingAmount);
+ });
+
+
+ await usingPlaygrounds(async (helper) => {
+ const location = {
+ V2: {
+ parents: 1,
+ interior: {X3: [
+ {
+ Parachain: STATEMINE_CHAIN,
+ },
+ {
+ PalletInstance: STATEMINE_PALLET_INSTANCE,
+ },
+ {
+ GeneralIndex: ASSET_ID,
+ },
+ ]},
+ },
+ };
+
+ const metadata =
+ {
+ name: ASSET_ID,
+ symbol: ASSET_METADATA_NAME,
+ decimals: ASSET_METADATA_DECIMALS,
+ minimalBalance: ASSET_METADATA_MINIMAL_BALANCE,
+ };
+ await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
+ balanceOpalBefore = await helper.balance.getSubstrate(alice.address);
+ });
+
+
+ // Providing the relay currency to the unique sender account
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: 50_000_000_000_000_000n,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ });
+
+ });
+
+ itSub('Should connect and send USDT from Westmint to Opal', async ({helper}) => {
+ await usingWestmintPlaygrounds(westmintUrl, async (helper) => {
+ const dest = {
+ V2: {
+ parents: 1,
+ interior: {X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: {
+ X2: [
+ {
+ PalletInstance: STATEMINE_PALLET_INSTANCE,
+ },
+ {
+ GeneralIndex: ASSET_ID,
+ },
+ ]},
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
+ await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
+
+ balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
+
+ // common good parachain take commission in it native token
+ console.log(
+ '[Westmint -> Opal] transaction fees on Westmint: %s WND',
+ helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, WESTMINT_DECIMALS),
+ );
+ expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
+
+ });
+
+
+ // ensure that asset has been delivered
+ await helper.wait.newBlocks(3);
+
+ // expext collection id will be with id 1
+ const free = await helper.ft.getBalance(1, {Substrate: alice.address});
+
+ balanceOpalAfter = await helper.balance.getSubstrate(alice.address);
+
+ console.log(
+ '[Westmint -> Opal] transaction fees on Opal: %s USDT',
+ helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, ASSET_METADATA_DECIMALS),
+ );
+ console.log(
+ '[Westmint -> Opal] transaction fees on Opal: %s OPL',
+ helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore),
+ );
+
+ // commission has not paid in USDT token
+ expect(free == TRANSFER_AMOUNT).to.be.true;
+ // ... and parachain native token
+ expect(balanceOpalAfter == balanceOpalBefore).to.be.true;
+ });
+
+ itSub('Should connect and send USDT from Unique to Statemine back', async ({helper}) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {X2: [
+ {
+ Parachain: STATEMINE_CHAIN,
+ },
+ {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ },
+ ]},
+ },
+ };
+
+ const currencies: [any, bigint][] = [
+ [
+ {
+ ForeignAssetId: 0,
+ },
+ //10_000_000_000_000_000n,
+ TRANSFER_AMOUNT,
+ ],
+ [
+ {
+ NativeAssetId: 'Parent',
+ },
+ 400_000_000_000_000n,
+ ],
+ ];
+
+ const feeItem = 1;
+
+ await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
+
+ // the commission has been paid in parachain native token
+ balanceOpalFinal = await helper.balance.getSubstrate(alice.address);
+ expect(balanceOpalAfter > balanceOpalFinal).to.be.true;
+
+ await usingWestmintPlaygrounds(westmintUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+
+ // The USDT token never paid fees. Its amount not changed from begin value.
+ // Also check that xcm transfer has been succeeded
+ expect((await helper.assets.account(ASSET_ID, alice.address))! == ASSET_AMOUNT).to.be.true;
+ });
+ });
+
+ itSub('Should connect and send Relay token to Unique', async ({helper}) => {
+ const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
+
+ balanceBobBefore = await helper.balance.getSubstrate(bob.address);
+ balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
+
+ // Providing the relay currency to the unique sender account
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: bob.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT_RELAY,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceBobAfter = await helper.balance.getSubstrate(bob.address);
+ balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
+
+ const wndFee = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
+ console.log(
+ 'Relay (Westend) to Opal transaction fees: %s OPL',
+ helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
+ );
+ console.log(
+ 'Relay (Westend) to Opal transaction fees: %s WND',
+ helper.util.bigIntToDecimals(wndFee, WESTMINT_DECIMALS),
+ );
+ expect(balanceBobBefore == balanceBobAfter).to.be.true;
+ expect(balanceBobRelayTokenBefore < balanceBobRelayTokenAfter).to.be.true;
+ });
+
+ itSub('Should connect and send Relay token back', async ({helper}) => {
+ let relayTokenBalanceBefore: bigint;
+ let relayTokenBalanceAfter: bigint;
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ });
+
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1:{
+ AccountId32: {
+ network: 'Any',
+ id: bob.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const currencies: any = [
+ [
+ {
+ NativeAssetId: 'Parent',
+ },
+ 50_000_000_000_000_000n,
+ ],
+ ];
+
+ const feeItem = 0;
+
+ await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
+
+ balanceBobFinal = await helper.balance.getSubstrate(bob.address);
+ console.log('[Opal -> Relay (Westend)] transaction fees: %s OPL', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ await helper.wait.newBlocks(10);
+ relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
+ console.log('[Opal -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
+ expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
+ });
+ });
+});
js-packages/tests/xcm/xcmQuartz.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/xcm/xcmQuartz.test.ts
@@ -0,0 +1,1636 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util/index.js';
+import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
+import {STATEMINE_CHAIN, QUARTZ_CHAIN, KARURA_CHAIN, MOONRIVER_CHAIN, SHIDEN_CHAIN, STATEMINE_DECIMALS, KARURA_DECIMALS, QTZ_DECIMALS, RELAY_DECIMALS, SHIDEN_DECIMALS, karuraUrl, moonriverUrl, relayUrl, shidenUrl, statemineUrl} from './xcm.types.js';
+import {hexToString} from '@polkadot/util';
+
+
+
+const STATEMINE_PALLET_INSTANCE = 50;
+
+const TRANSFER_AMOUNT = 2000000000000000000000000n;
+
+const FUNDING_AMOUNT = 3_500_000_0000_000_000n;
+
+const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
+
+const USDT_ASSET_ID = 100;
+const USDT_ASSET_METADATA_DECIMALS = 18;
+const USDT_ASSET_METADATA_NAME = 'USDT';
+const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';
+const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
+const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
+
+const SAFE_XCM_VERSION = 2;
+
+describeXCM('[XCM] Integration test: Exchanging USDT with Statemine', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ let balanceStmnBefore: bigint;
+ let balanceStmnAfter: bigint;
+
+ let balanceQuartzBefore: bigint;
+ let balanceQuartzAfter: bigint;
+ let balanceQuartzFinal: bigint;
+
+ let balanceBobBefore: bigint;
+ let balanceBobAfter: bigint;
+ let balanceBobFinal: bigint;
+
+ let balanceBobRelayTokenBefore: bigint;
+ let balanceBobRelayTokenAfter: bigint;
+
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ bob = await privateKey('//Bob'); // sovereign account on Statemine(t) funds donor
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ // Fund accounts on Statemine(t)
+ await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, alice.addressRaw, FUNDING_AMOUNT);
+ await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, bob.addressRaw, FUNDING_AMOUNT);
+ });
+
+ await usingStateminePlaygrounds(statemineUrl, async (helper) => {
+ const sovereignFundingAmount = 3_500_000_000n;
+
+ await helper.assets.create(
+ alice,
+ USDT_ASSET_ID,
+ alice.address,
+ USDT_ASSET_METADATA_MINIMAL_BALANCE,
+ );
+ await helper.assets.setMetadata(
+ alice,
+ USDT_ASSET_ID,
+ USDT_ASSET_METADATA_NAME,
+ USDT_ASSET_METADATA_DESCRIPTION,
+ USDT_ASSET_METADATA_DECIMALS,
+ );
+ await helper.assets.mint(
+ alice,
+ USDT_ASSET_ID,
+ alice.address,
+ USDT_ASSET_AMOUNT,
+ );
+
+ // funding parachain sovereing account on Statemine(t).
+ // The sovereign account should be created before any action
+ // (the assets pallet on Statemine(t) check if the sovereign account exists)
+ const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(QUARTZ_CHAIN);
+ await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);
+ });
+
+
+ await usingPlaygrounds(async (helper) => {
+ const location = {
+ V2: {
+ parents: 1,
+ interior: {X3: [
+ {
+ Parachain: STATEMINE_CHAIN,
+ },
+ {
+ PalletInstance: STATEMINE_PALLET_INSTANCE,
+ },
+ {
+ GeneralIndex: USDT_ASSET_ID,
+ },
+ ]},
+ },
+ };
+
+ const metadata =
+ {
+ name: USDT_ASSET_ID,
+ symbol: USDT_ASSET_METADATA_NAME,
+ decimals: USDT_ASSET_METADATA_DECIMALS,
+ minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,
+ };
+ await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
+ balanceQuartzBefore = await helper.balance.getSubstrate(alice.address);
+ });
+
+
+ // Providing the relay currency to the quartz sender account
+ // (fee for USDT XCM are paid in relay tokens)
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT_RELAY,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ });
+
+ });
+
+ itSub('Should connect and send USDT from Statemine to Quartz', async ({helper}) => {
+ await usingStateminePlaygrounds(statemineUrl, async (helper) => {
+ const dest = {
+ V2: {
+ parents: 1,
+ interior: {X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: {
+ X2: [
+ {
+ PalletInstance: STATEMINE_PALLET_INSTANCE,
+ },
+ {
+ GeneralIndex: USDT_ASSET_ID,
+ },
+ ]},
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
+ await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
+
+ balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
+
+ // common good parachain take commission in it native token
+ console.log(
+ '[Statemine -> Quartz] transaction fees on Statemine: %s WND',
+ helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINE_DECIMALS),
+ );
+ expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
+
+ });
+
+
+ // ensure that asset has been delivered
+ await helper.wait.newBlocks(3);
+
+ // expext collection id will be with id 1
+ const free = await helper.ft.getBalance(1, {Substrate: alice.address});
+
+ balanceQuartzAfter = await helper.balance.getSubstrate(alice.address);
+
+ console.log(
+ '[Statemine -> Quartz] transaction fees on Quartz: %s USDT',
+ helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),
+ );
+ console.log(
+ '[Statemine -> Quartz] transaction fees on Quartz: %s QTZ',
+ helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzBefore),
+ );
+ // commission has not paid in USDT token
+ expect(free).to.be.equal(TRANSFER_AMOUNT);
+ // ... and parachain native token
+ expect(balanceQuartzAfter == balanceQuartzBefore).to.be.true;
+ });
+
+ itSub('Should connect and send USDT from Quartz to Statemine back', async ({helper}) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {X2: [
+ {
+ Parachain: STATEMINE_CHAIN,
+ },
+ {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ },
+ ]},
+ },
+ };
+
+ const relayFee = 400_000_000_000_000n;
+ const currencies: [any, bigint][] = [
+ [
+ {
+ ForeignAssetId: 0,
+ },
+ TRANSFER_AMOUNT,
+ ],
+ [
+ {
+ NativeAssetId: 'Parent',
+ },
+ relayFee,
+ ],
+ ];
+
+ const feeItem = 1;
+
+ await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
+
+ // the commission has been paid in parachain native token
+ balanceQuartzFinal = await helper.balance.getSubstrate(alice.address);
+ console.log('[Quartz -> Statemine] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzFinal));
+ expect(balanceQuartzAfter > balanceQuartzFinal).to.be.true;
+
+ await usingStateminePlaygrounds(statemineUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+
+ // The USDT token never paid fees. Its amount not changed from begin value.
+ // Also check that xcm transfer has been succeeded
+ expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
+ });
+ });
+
+ itSub('Should connect and send Relay token to Quartz', async ({helper}) => {
+ balanceBobBefore = await helper.balance.getSubstrate(bob.address);
+ balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: bob.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT_RELAY,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceBobAfter = await helper.balance.getSubstrate(bob.address);
+ balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
+
+ const wndFeeOnQuartz = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
+ const wndDiffOnQuartz = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;
+ console.log(
+ '[Relay (Westend) -> Quartz] transaction fees: %s QTZ',
+ helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
+ );
+ console.log(
+ '[Relay (Westend) -> Quartz] transaction fees: %s WND',
+ helper.util.bigIntToDecimals(wndFeeOnQuartz, STATEMINE_DECIMALS),
+ );
+ console.log('[Relay (Westend) -> Quartz] actually delivered: %s WND', wndDiffOnQuartz);
+ expect(wndFeeOnQuartz == 0n, 'No incoming WND fees should be taken').to.be.true;
+ expect(balanceBobBefore == balanceBobAfter, 'No incoming QTZ fees should be taken').to.be.true;
+ });
+
+ itSub('Should connect and send Relay token back', async ({helper}) => {
+ let relayTokenBalanceBefore: bigint;
+ let relayTokenBalanceAfter: bigint;
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ });
+
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1:{
+ AccountId32: {
+ network: 'Any',
+ id: bob.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const currencies: any = [
+ [
+ {
+ NativeAssetId: 'Parent',
+ },
+ TRANSFER_AMOUNT_RELAY,
+ ],
+ ];
+
+ const feeItem = 0;
+
+ await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
+
+ balanceBobFinal = await helper.balance.getSubstrate(bob.address);
+ console.log('[Quartz -> Relay (Westend)] transaction fees: %s QTZ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ await helper.wait.newBlocks(10);
+ relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
+ console.log('[Quartz -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
+ expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
+ });
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ let balanceQuartzTokenInit: bigint;
+ let balanceQuartzTokenMiddle: bigint;
+ let balanceQuartzTokenFinal: bigint;
+ let balanceKaruraTokenInit: bigint;
+ let balanceKaruraTokenMiddle: bigint;
+ let balanceKaruraTokenFinal: bigint;
+ let balanceQuartzForeignTokenInit: bigint;
+ let balanceQuartzForeignTokenMiddle: bigint;
+ let balanceQuartzForeignTokenFinal: bigint;
+
+ // computed by a test transfer from prod Quartz to prod Karura.
+ // 2 QTZ sent https://quartz.subscan.io/xcm_message/kusama-f60d821b049f8835a3005ce7102285006f5b61e9
+ // 1.919176000000000000 QTZ received (you can check Karura's chain state in the corresponding block)
+ const expectedKaruraIncomeFee = 2000000000000000000n - 1919176000000000000n;
+ const karuraEps = 8n * 10n ** 16n;
+
+ let karuraBackwardTransferAmount: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ const metadata = {
+ name: 'Quartz',
+ symbol: 'QTZ',
+ decimals: 18,
+ minimalBalance: 1000000000000000000n,
+ };
+
+ const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>
+ hexToString(v.toJSON()['symbol'])) as string[];
+
+ if(!assets.includes('QTZ')) {
+ await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+ } else {
+ console.log('QTZ token already registered on Karura assetRegistry pallet');
+ }
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
+ balanceKaruraTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+ balanceQuartzForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
+ balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+ });
+ });
+
+ itSub('Should connect and send QTZ to Karura', async ({helper}) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: KARURA_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
+
+ const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
+ expect(qtzFees > 0n, 'Negative fees QTZ, looks like nothing was transferred').to.be.true;
+ console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
+
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+
+ balanceQuartzForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
+ balanceKaruraTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
+
+ const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;
+ const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;
+ karuraBackwardTransferAmount = qtzIncomeTransfer;
+
+ const karUnqFees = TRANSFER_AMOUNT - qtzIncomeTransfer;
+
+ console.log(
+ '[Quartz -> Karura] transaction fees on Karura: %s KAR',
+ helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),
+ );
+ console.log(
+ '[Quartz -> Karura] transaction fees on Karura: %s QTZ',
+ helper.util.bigIntToDecimals(karUnqFees),
+ );
+ console.log('[Quartz -> Karura] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));
+ expect(karFees == 0n).to.be.true;
+
+ const bigintAbs = (n: bigint) => (n < 0n) ? -n : n;
+
+ expect(
+ bigintAbs(karUnqFees - expectedKaruraIncomeFee) < karuraEps,
+ 'Karura took different income fee, check the Karura foreign asset config',
+ ).to.be.true;
+ });
+ });
+
+ itSub('Should connect to Karura and send QTZ back', async ({helper}) => {
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: QUARTZ_CHAIN},
+ {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ ],
+ },
+ },
+ };
+
+ const id = {
+ ForeignAsset: 0,
+ };
+
+ await helper.xTokens.transfer(randomAccount, id, karuraBackwardTransferAmount, destination, 'Unlimited');
+ balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
+ balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);
+
+ const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;
+ const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;
+
+ console.log(
+ '[Karura -> Quartz] transaction fees on Karura: %s KAR',
+ helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),
+ );
+ console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));
+
+ expect(karFees > 0, 'Negative fees KAR, looks like nothing was transferred').to.be.true;
+ expect(qtzOutcomeTransfer == karuraBackwardTransferAmount).to.be.true;
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
+ const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;
+ expect(actuallyDelivered > 0).to.be.true;
+
+ console.log('[Karura -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));
+
+ const qtzFees = karuraBackwardTransferAmount - actuallyDelivered;
+ console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
+ expect(qtzFees == 0n).to.be.true;
+ });
+
+ itSub('Karura can send only up to its balance', async ({helper}) => {
+ // set Karura's sovereign account's balance
+ const karuraBalance = 10000n * (10n ** QTZ_DECIMALS);
+ const karuraSovereignAccount = helper.address.paraSiblingSovereignAccount(KARURA_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, karuraSovereignAccount, karuraBalance);
+
+ const moreThanKaruraHas = karuraBalance * 2n;
+
+ let targetAccountBalance = 0n;
+ const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+ const quartzMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: QUARTZ_CHAIN},
+ },
+ },
+ };
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanKaruraHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+ const maxWaitBlocks = 5;
+
+ // Try to trick Quartz
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+
+ // But Karura still can send the correct amount
+ const validTransferAmount = karuraBalance / 2n;
+ const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ validTransferAmount,
+ );
+
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, validXcmProgram);
+ });
+
+ await helper.wait.newBlocks(maxWaitBlocks);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(validTransferAmount);
+ });
+
+ itSub('Should not accept reserve transfer of QTZ from Karura', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
+ const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ const quartzMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ },
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Quartz using full QTZ identification
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Quartz using shortened QTZ identification
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
+
+// These tests are relevant only when
+// the the corresponding foreign assets are not registered
+describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => {
+ let alice: IKeyringPair;
+ let alith: IKeyringPair;
+
+ const testAmount = 100_000_000_000n;
+ let quartzParachainJunction;
+ let quartzAccountJunction;
+
+ let quartzParachainMultilocation: any;
+ let quartzAccountMultilocation: any;
+ let quartzCombinedMultilocation: any;
+
+ let messageSent: any;
+
+ const maxWaitBlocks = 3;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+
+ quartzParachainJunction = {Parachain: QUARTZ_CHAIN};
+ quartzAccountJunction = {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ };
+
+ quartzParachainMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: quartzParachainJunction,
+ },
+ },
+ };
+
+ quartzAccountMultilocation = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: quartzAccountJunction,
+ },
+ },
+ };
+
+ quartzCombinedMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [quartzParachainJunction, quartzAccountJunction],
+ },
+ },
+ };
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ // eslint-disable-next-line require-await
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ alith = helper.account.alithAccount();
+ });
+ });
+
+ const expectFailedToTransact = async (helper: DevUniqueHelper, messageSent: any) => {
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+ };
+
+ itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {
+ await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+ const id = {
+ Token: 'KAR',
+ };
+ const destination = quartzCombinedMultilocation;
+ await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+
+ itSub('Quartz rejects MOVR tokens from Moonriver', async ({helper}) => {
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const id = 'SelfReserve';
+ const destination = quartzCombinedMultilocation;
+ await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+
+ itSub('Quartz rejects SDN tokens from Shiden', async ({helper}) => {
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ const destinationParachain = quartzParachainMultilocation;
+ const beneficiary = quartzAccountMultilocation;
+ const assets = {
+ V2: [{
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: testAmount,
+ },
+ }],
+ };
+ const feeAssetItem = 0;
+
+ await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [
+ destinationParachain,
+ beneficiary,
+ assets,
+ feeAssetItem,
+ ]);
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {
+ // Quartz constants
+ let alice: IKeyringPair;
+ let quartzAssetLocation;
+
+ let randomAccountQuartz: IKeyringPair;
+ let randomAccountMoonriver: IKeyringPair;
+
+ // Moonriver constants
+ let assetId: string;
+
+ const quartzAssetMetadata = {
+ name: 'xcQuartz',
+ symbol: 'xcQTZ',
+ decimals: 18,
+ isFrozen: false,
+ minimalBalance: 1n,
+ };
+
+ let balanceQuartzTokenInit: bigint;
+ let balanceQuartzTokenMiddle: bigint;
+ let balanceQuartzTokenFinal: bigint;
+ let balanceForeignQtzTokenInit: bigint;
+ let balanceForeignQtzTokenMiddle: bigint;
+ let balanceForeignQtzTokenFinal: bigint;
+ let balanceMovrTokenInit: bigint;
+ let balanceMovrTokenMiddle: bigint;
+ let balanceMovrTokenFinal: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);
+
+ balanceForeignQtzTokenInit = 0n;
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const alithAccount = helper.account.alithAccount();
+ const baltatharAccount = helper.account.baltatharAccount();
+ const dorothyAccount = helper.account.dorothyAccount();
+
+ randomAccountMoonriver = helper.account.create();
+
+ // >>> Sponsoring Dorothy >>>
+ console.log('Sponsoring Dorothy.......');
+ await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring Dorothy.......DONE');
+ // <<< Sponsoring Dorothy <<<
+
+ quartzAssetLocation = {
+ XCM: {
+ parents: 1,
+ interior: {X1: {Parachain: QUARTZ_CHAIN}},
+ },
+ };
+ const existentialDeposit = 1n;
+ const isSufficient = true;
+ const unitsPerSecond = 1n;
+ const numAssetsWeightHint = 0;
+
+ if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {
+ console.log('Quartz asset already registered on Moonriver');
+ } else {
+ const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
+ location: quartzAssetLocation,
+ metadata: quartzAssetMetadata,
+ existentialDeposit,
+ isSufficient,
+ unitsPerSecond,
+ numAssetsWeightHint,
+ });
+
+ console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
+
+ await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
+ }
+ // >>> Acquire Quartz AssetId Info on Moonriver >>>
+ console.log('Acquire Quartz AssetId Info on Moonriver.......');
+
+ assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();
+
+ console.log('QTZ asset ID is %s', assetId);
+ console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');
+ // >>> Acquire Quartz AssetId Info on Moonriver >>>
+
+ // >>> Sponsoring random Account >>>
+ console.log('Sponsoring random Account.......');
+ await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring random Account.......DONE');
+ // <<< Sponsoring random Account <<<
+
+ balanceMovrTokenInit = await helper.balance.getEthereum(randomAccountMoonriver.address);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
+ balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);
+ });
+ });
+
+ itSub('Should connect and send QTZ to Moonriver', async ({helper}) => {
+ const currencyId = {
+ NativeAssetId: 'Here',
+ };
+ const dest = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: MOONRIVER_CHAIN},
+ {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},
+ ],
+ },
+ },
+ };
+ const amount = TRANSFER_AMOUNT;
+
+ await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, 'Unlimited');
+
+ balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address);
+ expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;
+
+ const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees));
+ expect(transactionFees > 0, 'Negative fees QTZ, looks like nothing was transferred').to.be.true;
+
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+
+ balanceMovrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonriver.address);
+
+ const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;
+ console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR',helper.util.bigIntToDecimals(movrFees));
+ expect(movrFees == 0n).to.be.true;
+
+ balanceForeignQtzTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonriver.address))!; // BigInt(qtzRandomAccountAsset['balance']);
+ const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;
+ console.log('[Quartz -> Moonriver] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));
+ expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ });
+ });
+
+ itSub('Should connect to Moonriver and send QTZ back', async ({helper}) => {
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const asset = {
+ V2: {
+ id: {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: QUARTZ_CHAIN},
+ },
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ };
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: QUARTZ_CHAIN},
+ {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},
+ ],
+ },
+ },
+ };
+
+ await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, 'Unlimited');
+
+ balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address);
+
+ const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;
+ console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees));
+ expect(movrFees > 0, 'Negative fees MOVR, looks like nothing was transferred').to.be.true;
+
+ const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address);
+
+ expect(qtzRandomAccountAsset).to.be.null;
+
+ balanceForeignQtzTokenFinal = 0n;
+
+ const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;
+ console.log('[Quartz -> Moonriver] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));
+ expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccountQuartz.address);
+ const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;
+ expect(actuallyDelivered > 0).to.be.true;
+
+ console.log('[Moonriver -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));
+
+ const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;
+ console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
+ expect(qtzFees == 0n).to.be.true;
+ });
+
+ itSub('Moonriver can send only up to its balance', async ({helper}) => {
+ // set Moonriver's sovereign account's balance
+ const moonriverBalance = 10000n * (10n ** QTZ_DECIMALS);
+ const moonriverSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONRIVER_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, moonriverSovereignAccount, moonriverBalance);
+
+ const moreThanMoonriverHas = moonriverBalance * 2n;
+
+ let targetAccountBalance = 0n;
+ const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+ const quartzMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: QUARTZ_CHAIN},
+ },
+ },
+ };
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanMoonriverHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Quartz
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgram]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('try to spend more QTZ than Moonriver has', batchCall);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+
+ // But Moonriver still can send the correct amount
+ const validTransferAmount = moonriverBalance / 2n;
+ const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ validTransferAmount,
+ );
+
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, validXcmProgram]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('Spend the correct amount of QTZ', batchCall);
+ });
+
+ await helper.wait.newBlocks(maxWaitBlocks);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(validTransferAmount);
+ });
+
+ itSub('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
+ const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ const quartzMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ },
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Quartz using full QTZ identification
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramFullId]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using path asset identification', batchCall);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Quartz using shortened QTZ identification
+ await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramHereId]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using "here" asset identification', batchCall);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging tokens with Shiden', () => {
+ let alice: IKeyringPair;
+ let sender: IKeyringPair;
+
+ const QTZ_ASSET_ID_ON_SHIDEN = 18_446_744_073_709_551_633n; // The value is taken from the live Shiden
+ const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; // The value is taken from the live Shiden
+
+ // Quartz -> Shiden
+ const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden
+ const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden
+ const qtzToShidenTransferred = 10n * (10n ** QTZ_DECIMALS); // 10 QTZ
+ const qtzToShidenArrived = 7_998_196_000_000_000_000n; // 7.99 ... QTZ, Shiden takes a commision in foreign tokens
+
+ // Shiden -> Quartz
+ const qtzFromShidenTransfered = 5n * (10n ** QTZ_DECIMALS); // 5 QTZ
+ const qtzOnShidenLeft = qtzToShidenArrived - qtzFromShidenTransfered; // 2.99 ... QTZ
+
+ let balanceAfterQuartzToShidenXCM: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [sender] = await helper.arrange.createAccounts([100n], alice);
+ console.log('sender', sender.address);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
+ console.log('1. Create foreign asset and metadata');
+ await helper.getSudo().assets.forceCreate(
+ alice,
+ QTZ_ASSET_ID_ON_SHIDEN,
+ alice.address,
+ QTZ_MINIMAL_BALANCE_ON_SHIDEN,
+ );
+
+ await helper.assets.setMetadata(
+ alice,
+ QTZ_ASSET_ID_ON_SHIDEN,
+ 'Quartz',
+ 'QTZ',
+ Number(QTZ_DECIMALS),
+ );
+
+ console.log('2. Register asset location on Shiden');
+ const assetLocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
+
+ console.log('3. Set QTZ payment for XCM execution on Shiden');
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+ } else {
+ console.log('QTZ is already registered on Shiden');
+ }
+ console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');
+ await helper.balance.transferToSubstrate(alice, sender.address, shidenInitialBalance);
+ });
+ });
+
+ itSub('Should connect and send QTZ to Shiden', async ({helper}) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: SHIDEN_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: sender.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: qtzToShidenTransferred,
+ },
+ },
+ ],
+ };
+
+ // Initial balance is 100 QTZ
+ const balanceBefore = await helper.balance.getSubstrate(sender.address);
+ console.log(`Initial balance is: ${balanceBefore}`);
+
+ const feeAssetItem = 0;
+ await helper.xcm.limitedReserveTransferAssets(sender, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+
+ // Balance after reserve transfer is less than 90
+ balanceAfterQuartzToShidenXCM = await helper.balance.getSubstrate(sender.address);
+ console.log(`QTZ Balance on Quartz after XCM is: ${balanceAfterQuartzToShidenXCM}`);
+ console.log(`Quartz's QTZ commission is: ${balanceBefore - balanceAfterQuartzToShidenXCM}`);
+ expect(balanceBefore - balanceAfterQuartzToShidenXCM > 0).to.be.true;
+
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+ const xcQTZbalance = await helper.assets.account(QTZ_ASSET_ID_ON_SHIDEN, sender.address);
+ const shidenBalance = await helper.balance.getSubstrate(sender.address);
+
+ console.log(`xcQTZ balance on Shiden after XCM is: ${xcQTZbalance}`);
+ console.log(`Shiden's QTZ commission is: ${qtzToShidenTransferred - xcQTZbalance!}`);
+
+ expect(xcQTZbalance).to.eq(qtzToShidenArrived);
+ // SHD balance does not changed:
+ expect(shidenBalance).to.eq(shidenInitialBalance);
+ });
+ });
+
+ itSub('Should connect to Shiden and send QTZ back', async ({helper}) => {
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: sender.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ },
+ fun: {
+ Fungible: qtzFromShidenTransfered,
+ },
+ },
+ ],
+ };
+
+ // Initial balance is 1 SDN
+ const balanceSDNbefore = await helper.balance.getSubstrate(sender.address);
+ console.log(`SDN balance is: ${balanceSDNbefore}, it does not changed`);
+ expect(balanceSDNbefore).to.eq(shidenInitialBalance);
+
+ const feeAssetItem = 0;
+ // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw
+ await helper.executeExtrinsic(sender, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);
+
+ // Balance after reserve transfer is less than 1 SDN
+ const xcQTZbalance = await helper.assets.account(QTZ_ASSET_ID_ON_SHIDEN, sender.address);
+ const balanceSDN = await helper.balance.getSubstrate(sender.address);
+ console.log(`xcQTZ balance on Shiden after XCM is: ${xcQTZbalance}`);
+
+ // Assert: xcQTZ balance correctly decreased
+ expect(xcQTZbalance).to.eq(qtzOnShidenLeft);
+ // Assert: SDN balance is 0.996...
+ expect(balanceSDN / (10n ** (SHIDEN_DECIMALS - 3n))).to.eq(996n);
+ });
+
+ await helper.wait.newBlocks(3);
+ const balanceQTZ = await helper.balance.getSubstrate(sender.address);
+ console.log(`QTZ Balance on Quartz after XCM is: ${balanceQTZ}`);
+ expect(balanceQTZ).to.eq(balanceAfterQuartzToShidenXCM + qtzFromShidenTransfered);
+ });
+
+ itSub('Shiden can send only up to its balance', async ({helper}) => {
+ // set Shiden's sovereign account's balance
+ const shidenBalance = 10000n * (10n ** QTZ_DECIMALS);
+ const shidenSovereignAccount = helper.address.paraSiblingSovereignAccount(SHIDEN_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, shidenSovereignAccount, shidenBalance);
+
+ const moreThanShidenHas = shidenBalance * 2n;
+
+ let targetAccountBalance = 0n;
+ const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+ const quartzMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: QUARTZ_CHAIN},
+ },
+ },
+ };
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanShidenHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Quartz
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+
+ // But Shiden still can send the correct amount
+ const validTransferAmount = shidenBalance / 2n;
+ const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ validTransferAmount,
+ );
+
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, validXcmProgram);
+ });
+
+ await helper.wait.newBlocks(maxWaitBlocks);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(validTransferAmount);
+ });
+
+ itSub('Should not accept reserve transfer of QTZ from Shiden', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
+ const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ const quartzMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ };
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: QUARTZ_CHAIN,
+ },
+ },
+ },
+ },
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Quartz using full QTZ identification
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Quartz using shortened QTZ identification
+ await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
js-packages/tests/xcm/xcmUnique.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/xcm/xcmUnique.test.ts
@@ -0,0 +1,1834 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import config from '../config.js';
+import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds} from '../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {hexToString, nToBigInt} from '@polkadot/util';
+import {ACALA_CHAIN, ASTAR_CHAIN, MOONBEAM_CHAIN, POLKADEX_CHAIN, SAFE_XCM_VERSION, STATEMINT_CHAIN, UNIQUE_CHAIN, expectFailedToTransact, expectUntrustedReserveLocationFail, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types.js';
+
+
+const STATEMINT_PALLET_INSTANCE = 50;
+
+const relayUrl = config.relayUrl;
+const statemintUrl = config.statemintUrl;
+const acalaUrl = config.acalaUrl;
+const moonbeamUrl = config.moonbeamUrl;
+const astarUrl = config.astarUrl;
+const polkadexUrl = config.polkadexUrl;
+
+const RELAY_DECIMALS = 12;
+const STATEMINT_DECIMALS = 12;
+const ACALA_DECIMALS = 12;
+const ASTAR_DECIMALS = 18n;
+const UNQ_DECIMALS = 18n;
+
+const TRANSFER_AMOUNT = 2000000000000000000000000n;
+
+const FUNDING_AMOUNT = 3_500_000_0000_000_000n;
+
+const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
+
+const USDT_ASSET_ID = 100;
+const USDT_ASSET_METADATA_DECIMALS = 18;
+const USDT_ASSET_METADATA_NAME = 'USDT';
+const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';
+const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
+const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
+
+describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {
+ let alice: IKeyringPair;
+ let bob: IKeyringPair;
+
+ let balanceStmnBefore: bigint;
+ let balanceStmnAfter: bigint;
+
+ let balanceUniqueBefore: bigint;
+ let balanceUniqueAfter: bigint;
+ let balanceUniqueFinal: bigint;
+
+ let balanceBobBefore: bigint;
+ let balanceBobAfter: bigint;
+ let balanceBobFinal: bigint;
+
+ let balanceBobRelayTokenBefore: bigint;
+ let balanceBobRelayTokenAfter: bigint;
+
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ // Fund accounts on Statemint
+ await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);
+ await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);
+ });
+
+ await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
+ const sovereignFundingAmount = 3_500_000_000n;
+
+ await helper.assets.create(
+ alice,
+ USDT_ASSET_ID,
+ alice.address,
+ USDT_ASSET_METADATA_MINIMAL_BALANCE,
+ );
+ await helper.assets.setMetadata(
+ alice,
+ USDT_ASSET_ID,
+ USDT_ASSET_METADATA_NAME,
+ USDT_ASSET_METADATA_DESCRIPTION,
+ USDT_ASSET_METADATA_DECIMALS,
+ );
+ await helper.assets.mint(
+ alice,
+ USDT_ASSET_ID,
+ alice.address,
+ USDT_ASSET_AMOUNT,
+ );
+
+ // funding parachain sovereing account on Statemint.
+ // The sovereign account should be created before any action
+ // (the assets pallet on Statemint check if the sovereign account exists)
+ const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);
+ await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);
+ });
+
+
+ await usingPlaygrounds(async (helper) => {
+ const location = {
+ V2: {
+ parents: 1,
+ interior: {X3: [
+ {
+ Parachain: STATEMINT_CHAIN,
+ },
+ {
+ PalletInstance: STATEMINT_PALLET_INSTANCE,
+ },
+ {
+ GeneralIndex: USDT_ASSET_ID,
+ },
+ ]},
+ },
+ };
+
+ const metadata =
+ {
+ name: USDT_ASSET_ID,
+ symbol: USDT_ASSET_METADATA_NAME,
+ decimals: USDT_ASSET_METADATA_DECIMALS,
+ minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,
+ };
+ await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
+ balanceUniqueBefore = await helper.balance.getSubstrate(alice.address);
+ });
+
+
+ // Providing the relay currency to the unique sender account
+ // (fee for USDT XCM are paid in relay tokens)
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT_RELAY,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ });
+
+ });
+
+ itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {
+ await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
+ const dest = {
+ V2: {
+ parents: 1,
+ interior: {X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: {
+ X2: [
+ {
+ PalletInstance: STATEMINT_PALLET_INSTANCE,
+ },
+ {
+ GeneralIndex: USDT_ASSET_ID,
+ },
+ ]},
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
+ await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
+
+ balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
+
+ // common good parachain take commission in it native token
+ console.log(
+ '[Statemint -> Unique] transaction fees on Statemint: %s WND',
+ helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS),
+ );
+ expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
+
+ });
+
+
+ // ensure that asset has been delivered
+ await helper.wait.newBlocks(3);
+
+ // expext collection id will be with id 1
+ const free = await helper.ft.getBalance(1, {Substrate: alice.address});
+
+ balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);
+
+ console.log(
+ '[Statemint -> Unique] transaction fees on Unique: %s USDT',
+ helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),
+ );
+ console.log(
+ '[Statemint -> Unique] transaction fees on Unique: %s UNQ',
+ helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore),
+ );
+ // commission has not paid in USDT token
+ expect(free).to.be.equal(TRANSFER_AMOUNT);
+ // ... and parachain native token
+ expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;
+ });
+
+ itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {X2: [
+ {
+ Parachain: STATEMINT_CHAIN,
+ },
+ {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ },
+ ]},
+ },
+ };
+
+ const relayFee = 400_000_000_000_000n;
+ const currencies: [any, bigint][] = [
+ [
+ {
+ ForeignAssetId: 0,
+ },
+ TRANSFER_AMOUNT,
+ ],
+ [
+ {
+ NativeAssetId: 'Parent',
+ },
+ relayFee,
+ ],
+ ];
+
+ const feeItem = 1;
+
+ await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
+
+ // the commission has been paid in parachain native token
+ balanceUniqueFinal = await helper.balance.getSubstrate(alice.address);
+ console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueFinal));
+ expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true;
+
+ await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+
+ // The USDT token never paid fees. Its amount not changed from begin value.
+ // Also check that xcm transfer has been succeeded
+ expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
+ });
+ });
+
+ itSub('Should connect and send Relay token to Unique', async ({helper}) => {
+ balanceBobBefore = await helper.balance.getSubstrate(bob.address);
+ balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ }};
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {X1: {
+ AccountId32: {
+ network: 'Any',
+ id: bob.addressRaw,
+ },
+ }},
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT_RELAY,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceBobAfter = await helper.balance.getSubstrate(bob.address);
+ balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
+
+ const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
+ const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;
+ console.log(
+ '[Relay (Westend) -> Unique] transaction fees: %s UNQ',
+ helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
+ );
+ console.log(
+ '[Relay (Westend) -> Unique] transaction fees: %s WND',
+ helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS),
+ );
+ console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique);
+ expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true;
+ expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true;
+ });
+
+ itSub('Should connect and send Relay token back', async ({helper}) => {
+ let relayTokenBalanceBefore: bigint;
+ let relayTokenBalanceAfter: bigint;
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
+ });
+
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1:{
+ AccountId32: {
+ network: 'Any',
+ id: bob.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const currencies: any = [
+ [
+ {
+ NativeAssetId: 'Parent',
+ },
+ TRANSFER_AMOUNT_RELAY,
+ ],
+ ];
+
+ const feeItem = 0;
+
+ await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
+
+ balanceBobFinal = await helper.balance.getSubstrate(bob.address);
+ console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
+
+ await usingRelayPlaygrounds(relayUrl, async (helper) => {
+ await helper.wait.newBlocks(10);
+ relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+ const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
+ console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
+ expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
+ });
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ let balanceUniqueTokenInit: bigint;
+ let balanceUniqueTokenMiddle: bigint;
+ let balanceUniqueTokenFinal: bigint;
+ let balanceAcalaTokenInit: bigint;
+ let balanceAcalaTokenMiddle: bigint;
+ let balanceAcalaTokenFinal: bigint;
+ let balanceUniqueForeignTokenInit: bigint;
+ let balanceUniqueForeignTokenMiddle: bigint;
+ let balanceUniqueForeignTokenFinal: bigint;
+
+ // computed by a test transfer from prod Unique to prod Acala.
+ // 2 UNQ sent https://unique.subscan.io/xcm_message/polkadot-bad0b68847e2398af25d482e9ee6f9c1f9ec2a48
+ // 1.898970000000000000 UNQ received (you can check Acala's chain state in the corresponding block)
+ const expectedAcalaIncomeFee = 2000000000000000000n - 1898970000000000000n;
+ const acalaEps = 8n * 10n ** 16n;
+
+ let acalaBackwardTransferAmount: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ const metadata = {
+ name: 'Unique Network',
+ symbol: 'UNQ',
+ decimals: 18,
+ minimalBalance: 1250000000000000000n,
+ };
+ const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>
+ hexToString(v.toJSON()['symbol'])) as string[];
+
+ if(!assets.includes('UNQ')) {
+ await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+ } else {
+ console.log('UNQ token already registered on Acala assetRegistry pallet');
+ }
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
+ balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+ balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
+ balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Acala', async ({helper}) => {
+
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: ACALA_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
+
+ const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
+ expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
+
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+
+ balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
+ balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
+
+ const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;
+ const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;
+ acalaBackwardTransferAmount = unqIncomeTransfer;
+
+ const acaUnqFees = TRANSFER_AMOUNT - unqIncomeTransfer;
+
+ console.log(
+ '[Unique -> Acala] transaction fees on Acala: %s ACA',
+ helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),
+ );
+ console.log(
+ '[Unique -> Acala] transaction fees on Acala: %s UNQ',
+ helper.util.bigIntToDecimals(acaUnqFees),
+ );
+ console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));
+ expect(acaFees == 0n).to.be.true;
+
+ const bigintAbs = (n: bigint) => (n < 0n) ? -n : n;
+
+ expect(
+ bigintAbs(acaUnqFees - expectedAcalaIncomeFee) < acalaEps,
+ 'Acala took different income fee, check the Acala foreign asset config',
+ ).to.be.true;
+ });
+ });
+
+ itSub('Should connect to Acala and send UNQ back', async ({helper}) => {
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: UNIQUE_CHAIN},
+ {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ ],
+ },
+ },
+ };
+
+ const id = {
+ ForeignAsset: 0,
+ };
+
+ await helper.xTokens.transfer(randomAccount, id, acalaBackwardTransferAmount, destination, 'Unlimited');
+ balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
+ balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);
+
+ const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;
+ const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;
+
+ console.log(
+ '[Acala -> Unique] transaction fees on Acala: %s ACA',
+ helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),
+ );
+ console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));
+
+ expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;
+ expect(unqOutcomeTransfer == acalaBackwardTransferAmount).to.be.true;
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
+ const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
+ expect(actuallyDelivered > 0).to.be.true;
+
+ console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));
+
+ const unqFees = acalaBackwardTransferAmount - actuallyDelivered;
+ console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
+ expect(unqFees == 0n).to.be.true;
+ });
+
+ itSub('Acala can send only up to its balance', async ({helper}) => {
+ // set Acala's sovereign account's balance
+ const acalaBalance = 10000n * (10n ** UNQ_DECIMALS);
+ const acalaSovereignAccount = helper.address.paraSiblingSovereignAccount(ACALA_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, acalaSovereignAccount, acalaBalance);
+
+ const moreThanAcalaHas = acalaBalance * 2n;
+
+ let targetAccountBalance = 0n;
+ const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanAcalaHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+
+ // But Acala still can send the correct amount
+ const validTransferAmount = acalaBalance / 2n;
+ const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ validTransferAmount,
+ );
+
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);
+ });
+
+ await helper.wait.newBlocks(maxWaitBlocks);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(validTransferAmount);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Acala', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
+ const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ const uniqueMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ uniqueAssetId,
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique using full UNQ identification
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Unique using shortened UNQ identification
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging tokens with Polkadex', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+ let unqFees: bigint;
+ let balanceUniqueTokenInit: bigint;
+ let balanceUniqueTokenMiddle: bigint;
+ let balanceUniqueTokenFinal: bigint;
+ const maxWaitBlocks = 6;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))
+ .toJSON() as [])
+ .map(nToBigInt).length != 0;
+ /*
+ Check whether the Unique token has been added
+ to the whitelist, since an error will occur
+ if it is added again. Needed for debugging
+ when this test is run multiple times.
+ */
+ if(isWhitelisted) {
+ console.log('UNQ token is already whitelisted on Polkadex');
+ } else {
+ await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);
+ }
+
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
+ balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Polkadex', async ({helper}) => {
+
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: POLKADEX_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+ const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
+
+ unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[Unique -> Polkadex] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
+ expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
+
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ /*
+ Since only the parachain part of the Polkadex
+ infrastructure is launched (without their
+ solochain validators), processing incoming
+ assets will lead to an error.
+ This error indicates that the Polkadex chain
+ received a message from the Unique network,
+ since the hash is being checked to ensure
+ it matches what was sent.
+ */
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);
+ });
+ });
+
+
+ itSub('Should connect to Polkadex and send UNQ back', async ({helper}) => {
+
+ const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ randomAccount.addressRaw,
+ uniqueAssetId,
+ TRANSFER_AMOUNT,
+ );
+
+ let xcmProgramSent: any;
+
+
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, xcmProgram);
+
+ xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);
+
+ balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
+
+ expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees);
+ });
+
+ itSub('Polkadex can send only up to its balance', async ({helper}) => {
+ const polkadexBalance = 10000n * (10n ** UNQ_DECIMALS);
+ const polkadexSovereignAccount = helper.address.paraSiblingSovereignAccount(POLKADEX_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, polkadexSovereignAccount, polkadexBalance);
+ const moreThanPolkadexHas = 2n * polkadexBalance;
+
+ const targetAccount = helper.arrange.createEmptyAccount();
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanPolkadexHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+
+
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, maliciousXcmProgramSent);
+
+ const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Polkadex', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
+ const targetAccount = helper.arrange.createEmptyAccount();
+
+ const uniqueMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ uniqueAssetId,
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique using full UNQ identification
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Unique using shortened UNQ identification
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
+
+// These tests are relevant only when
+// the the corresponding foreign assets are not registered
+describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {
+ let alice: IKeyringPair;
+ let alith: IKeyringPair;
+
+ const testAmount = 100_000_000_000n;
+ let uniqueParachainJunction;
+ let uniqueAccountJunction;
+
+ let uniqueParachainMultilocation: any;
+ let uniqueAccountMultilocation: any;
+ let uniqueCombinedMultilocation: any;
+ let uniqueCombinedMultilocationAcala: any; // TODO remove when Acala goes V2
+
+ let messageSent: any;
+
+ const maxWaitBlocks = 3;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+
+ uniqueParachainJunction = {Parachain: UNIQUE_CHAIN};
+ uniqueAccountJunction = {
+ AccountId32: {
+ network: 'Any',
+ id: alice.addressRaw,
+ },
+ };
+
+ uniqueParachainMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: uniqueParachainJunction,
+ },
+ },
+ };
+
+ uniqueAccountMultilocation = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: uniqueAccountJunction,
+ },
+ },
+ };
+
+ uniqueCombinedMultilocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [uniqueParachainJunction, uniqueAccountJunction],
+ },
+ },
+ };
+
+ uniqueCombinedMultilocationAcala = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [uniqueParachainJunction, uniqueAccountJunction],
+ },
+ },
+ };
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ // eslint-disable-next-line require-await
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ alith = helper.account.alithAccount();
+ });
+ });
+
+
+
+ itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {
+ await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+ const id = {
+ Token: 'ACA',
+ };
+ const destination = uniqueCombinedMultilocationAcala;
+ await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+
+ itSub('Unique rejects GLMR tokens from Moonbeam', async ({helper}) => {
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const id = 'SelfReserve';
+ const destination = uniqueCombinedMultilocation;
+ await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+
+ itSub('Unique rejects ASTR tokens from Astar', async ({helper}) => {
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ const destinationParachain = uniqueParachainMultilocation;
+ const beneficiary = uniqueAccountMultilocation;
+ const assets = {
+ V2: [{
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: testAmount,
+ },
+ }],
+ };
+ const feeAssetItem = 0;
+
+ await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [
+ destinationParachain,
+ beneficiary,
+ assets,
+ feeAssetItem,
+ ]);
+
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+
+ itSub('Unique rejects PDX tokens from Polkadex', async ({helper}) => {
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ helper.arrange.createEmptyAccount().addressRaw,
+ {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: POLKADEX_CHAIN,
+ },
+ },
+ },
+ },
+ testAmount,
+ );
+
+ await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueParachainMultilocation, maliciousXcmProgramFullId);
+ messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await expectFailedToTransact(helper, messageSent);
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {
+ // Unique constants
+ let alice: IKeyringPair;
+ let uniqueAssetLocation;
+
+ let randomAccountUnique: IKeyringPair;
+ let randomAccountMoonbeam: IKeyringPair;
+
+ // Moonbeam constants
+ let assetId: string;
+
+ const uniqueAssetMetadata = {
+ name: 'xcUnique',
+ symbol: 'xcUNQ',
+ decimals: 18,
+ isFrozen: false,
+ minimalBalance: 1n,
+ };
+
+ let balanceUniqueTokenInit: bigint;
+ let balanceUniqueTokenMiddle: bigint;
+ let balanceUniqueTokenFinal: bigint;
+ let balanceForeignUnqTokenInit: bigint;
+ let balanceForeignUnqTokenMiddle: bigint;
+ let balanceForeignUnqTokenFinal: bigint;
+ let balanceGlmrTokenInit: bigint;
+ let balanceGlmrTokenMiddle: bigint;
+ let balanceGlmrTokenFinal: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);
+
+ balanceForeignUnqTokenInit = 0n;
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const alithAccount = helper.account.alithAccount();
+ const baltatharAccount = helper.account.baltatharAccount();
+ const dorothyAccount = helper.account.dorothyAccount();
+
+ randomAccountMoonbeam = helper.account.create();
+
+ // >>> Sponsoring Dorothy >>>
+ console.log('Sponsoring Dorothy.......');
+ await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring Dorothy.......DONE');
+ // <<< Sponsoring Dorothy <<<
+
+ uniqueAssetLocation = {
+ XCM: {
+ parents: 1,
+ interior: {X1: {Parachain: UNIQUE_CHAIN}},
+ },
+ };
+ const existentialDeposit = 1n;
+ const isSufficient = true;
+ const unitsPerSecond = 1n;
+ const numAssetsWeightHint = 0;
+
+ if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {
+ console.log('Unique asset is already registered on MoonBeam');
+ } else {
+ const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
+ location: uniqueAssetLocation,
+ metadata: uniqueAssetMetadata,
+ existentialDeposit,
+ isSufficient,
+ unitsPerSecond,
+ numAssetsWeightHint,
+ });
+
+ console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
+
+ await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);
+ }
+
+ // >>> Acquire Unique AssetId Info on Moonbeam >>>
+ console.log('Acquire Unique AssetId Info on Moonbeam.......');
+
+ assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();
+ console.log('UNQ asset ID is %s', assetId);
+ console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');
+ // >>> Acquire Unique AssetId Info on Moonbeam >>>
+
+ // >>> Sponsoring random Account >>>
+ console.log('Sponsoring random Account.......');
+ await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);
+ console.log('Sponsoring random Account.......DONE');
+ // <<< Sponsoring random Account <<<
+
+ balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);
+ });
+
+ await usingPlaygrounds(async (helper) => {
+ await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);
+ balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {
+ const currencyId = {
+ NativeAssetId: 'Here',
+ };
+ const dest = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: MOONBEAM_CHAIN},
+ {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},
+ ],
+ },
+ },
+ };
+ const amount = TRANSFER_AMOUNT;
+
+ await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited');
+
+ balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);
+ expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;
+
+ const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));
+ expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
+
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+ balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);
+
+ const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;
+ console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));
+ expect(glmrFees == 0n).to.be.true;
+
+ balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;
+
+ const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;
+ console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));
+ expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ });
+ });
+
+ itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const asset = {
+ V2: {
+ id: {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: UNIQUE_CHAIN},
+ },
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ };
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: UNIQUE_CHAIN},
+ {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},
+ ],
+ },
+ },
+ };
+
+ await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, 'Unlimited');
+
+ balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);
+
+ const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;
+ console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));
+ expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;
+
+ const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);
+
+ expect(unqRandomAccountAsset).to.be.null;
+
+ balanceForeignUnqTokenFinal = 0n;
+
+ const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;
+ console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));
+ expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ });
+
+ await helper.wait.newBlocks(3);
+
+ balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);
+ const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
+ expect(actuallyDelivered > 0).to.be.true;
+
+ console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));
+
+ const unqFees = TRANSFER_AMOUNT - actuallyDelivered;
+ console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
+ expect(unqFees == 0n).to.be.true;
+ });
+
+ itSub('Moonbeam can send only up to its balance', async ({helper}) => {
+ // set Moonbeam's sovereign account's balance
+ const moonbeamBalance = 10000n * (10n ** UNQ_DECIMALS);
+ const moonbeamSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONBEAM_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, moonbeamSovereignAccount, moonbeamBalance);
+
+ const moreThanMoonbeamHas = moonbeamBalance * 2n;
+
+ let targetAccountBalance = 0n;
+ const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanMoonbeamHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('try to spend more UNQ than Moonbeam has', batchCall);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+
+ // But Moonbeam still can send the correct amount
+ const validTransferAmount = moonbeamBalance / 2n;
+ const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ validTransferAmount,
+ );
+
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, validXcmProgram]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('Spend the correct amount of UNQ', batchCall);
+ });
+
+ await helper.wait.newBlocks(maxWaitBlocks);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(validTransferAmount);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
+ const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ uniqueAssetId,
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique using full UNQ identification
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using path asset identification', batchCall);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Unique using shortened UNQ identification
+ await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+ const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);
+
+ // Needed to bypass the call filter.
+ const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+ await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using "here" asset identification', batchCall);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
+
+describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; // The value is taken from the live Astar
+ const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; // The value is taken from the live Astar
+
+ // Unique -> Astar
+ const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.
+ const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar
+ const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ
+ const unqToAstarArrived = 9_962_196_000_000_000_000n; // 9.962 ... UNQ, Astar takes a commision in foreign tokens
+
+ // Astar -> Unique
+ const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ
+ const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.962_219_600_000_000_000n UNQ
+
+ let balanceAfterUniqueToAstarXCM: bigint;
+
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ [randomAccount] = await helper.arrange.createAccounts([100n], alice);
+ console.log('randomAccount', randomAccount.address);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
+ });
+
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {
+ console.log('1. Create foreign asset and metadata');
+ await helper.getSudo().assets.forceCreate(
+ alice,
+ UNQ_ASSET_ID_ON_ASTAR,
+ alice.address,
+ UNQ_MINIMAL_BALANCE_ON_ASTAR,
+ );
+
+ await helper.assets.setMetadata(
+ alice,
+ UNQ_ASSET_ID_ON_ASTAR,
+ 'Unique Network',
+ 'UNQ',
+ Number(UNQ_DECIMALS),
+ );
+
+ console.log('2. Register asset location on Astar');
+ const assetLocation = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);
+
+ console.log('3. Set UNQ payment for XCM execution on Astar');
+ await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+ } else {
+ console.log('UNQ is already registered on Astar');
+ }
+ console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');
+ await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);
+ });
+ });
+
+ itSub('Should connect and send UNQ to Astar', async ({helper}) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: ASTAR_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: unqToAstarTransferred,
+ },
+ },
+ ],
+ };
+
+ // Initial balance is 100 UNQ
+ const balanceBefore = await helper.balance.getSubstrate(randomAccount.address);
+ console.log(`Initial balance is: ${balanceBefore}`);
+
+ const feeAssetItem = 0;
+ await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
+
+ // Balance after reserve transfer is less than 90
+ balanceAfterUniqueToAstarXCM = await helper.balance.getSubstrate(randomAccount.address);
+ console.log(`UNQ Balance on Unique after XCM is: ${balanceAfterUniqueToAstarXCM}`);
+ console.log(`Unique's UNQ commission is: ${balanceBefore - balanceAfterUniqueToAstarXCM}`);
+ expect(balanceBefore - balanceAfterUniqueToAstarXCM > 0).to.be.true;
+
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ await helper.wait.newBlocks(3);
+ const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);
+ const astarBalance = await helper.balance.getSubstrate(randomAccount.address);
+
+ console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);
+ console.log(`Astar's UNQ commission is: ${unqToAstarTransferred - xcUNQbalance!}`);
+
+ expect(xcUNQbalance).to.eq(unqToAstarArrived);
+ // Astar balance does not changed
+ expect(astarBalance).to.eq(astarInitialBalance);
+ });
+ });
+
+ itSub('Should connect to Astar and send UNQ back', async ({helper}) => {
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ const destination = {
+ V2: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ };
+
+ const beneficiary = {
+ V2: {
+ parents: 0,
+ interior: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V2: [
+ {
+ id: {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {
+ Parachain: UNIQUE_CHAIN,
+ },
+ },
+ },
+ },
+ fun: {
+ Fungible: unqFromAstarTransfered,
+ },
+ },
+ ],
+ };
+
+ // Initial balance is 1 ASTR
+ const balanceASTRbefore = await helper.balance.getSubstrate(randomAccount.address);
+ console.log(`ASTR balance is: ${balanceASTRbefore}, it does not changed`);
+ expect(balanceASTRbefore).to.eq(astarInitialBalance);
+
+ const feeAssetItem = 0;
+ // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw
+ await helper.executeExtrinsic(randomAccount, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);
+
+ const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);
+ const balanceAstar = await helper.balance.getSubstrate(randomAccount.address);
+ console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);
+
+ // Assert: xcUNQ balance correctly decreased
+ expect(xcUNQbalance).to.eq(unqOnAstarLeft);
+ // Assert: ASTR balance is 0.996...
+ expect(balanceAstar / (10n ** (ASTAR_DECIMALS - 3n))).to.eq(996n);
+ });
+
+ await helper.wait.newBlocks(3);
+ const balanceUNQ = await helper.balance.getSubstrate(randomAccount.address);
+ console.log(`UNQ Balance on Unique after XCM is: ${balanceUNQ}`);
+ expect(balanceUNQ).to.eq(balanceAfterUniqueToAstarXCM + unqFromAstarTransfered);
+ });
+
+ itSub('Astar can send only up to its balance', async ({helper}) => {
+ // set Astar's sovereign account's balance
+ const astarBalance = 10000n * (10n ** UNQ_DECIMALS);
+ const astarSovereignAccount = helper.address.paraSiblingSovereignAccount(ASTAR_CHAIN);
+ await helper.getSudo().balance.setBalanceSubstrate(alice, astarSovereignAccount, astarBalance);
+
+ const moreThanAstarHas = astarBalance * 2n;
+
+ let targetAccountBalance = 0n;
+ const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+ const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ moreThanAstarHas,
+ );
+
+ let maliciousXcmProgramSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);
+
+ maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash
+ && event.outcome.isFailedToTransactAsset);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(0n);
+
+ // But Astar still can send the correct amount
+ const validTransferAmount = astarBalance / 2n;
+ const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ validTransferAmount,
+ );
+
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);
+ });
+
+ await helper.wait.newBlocks(maxWaitBlocks);
+
+ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(targetAccountBalance).to.be.equal(validTransferAmount);
+ });
+
+ itSub('Should not accept reserve transfer of UNQ from Astar', async ({helper}) => {
+ const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
+ const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ uniqueAssetId,
+ testAmount,
+ );
+
+ const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+ targetAccount.addressRaw,
+ {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ testAmount,
+ );
+
+ let maliciousXcmProgramFullIdSent: any;
+ let maliciousXcmProgramHereIdSent: any;
+ const maxWaitBlocks = 3;
+
+ // Try to trick Unique using full UNQ identification
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramFullId);
+
+ maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+
+ // Try to trick Unique using shortened UNQ identification
+ await usingAstarPlaygrounds(astarUrl, async (helper) => {
+ await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramHereId);
+
+ maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+ });
+
+ await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash
+ && event.outcome.isUntrustedReserveLocation);
+
+ accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+ expect(accountBalance).to.be.equal(0n);
+ });
+});
js-packages/tsconfig.base.jsondiffbeforeafterboth--- a/js-packages/tsconfig.base.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- /**
- * There uses the strictest configs as the base
- * https://github.com/tsconfig/bases/blob/f674fa6cbca17062ff02511b02872f8729a597ec/bases/strictest.json
- */
- "extends": "@tsconfig/strictest/tsconfig.json",
- "compilerOptions": {
- /**
- * This needs to align with scripts/polkadot-dev-build-ts & dev-ts/loader
- * (target here is specifically tied to the minimum supported version)
- */
- "module": "nodenext",
- "moduleResolution": "nodenext",
- "target": "es2022",
-
- /**
- * Specific compilation configs for polkadot-js projects as it is used
- * (we only compile *.d.ts via the tsc command-line)
- */
- "declaration": true,
- "emitDeclarationOnly": true,
- "jsx": "preserve",
- "verbatimModuleSyntax": true,
-
- /**
- * These appear in strictest, however we don't (yet) use them. For the most part it means
- * that we actually do have a large number of these lurking (especially on index checks)
- */
- "checkJs": false,
- "exactOptionalPropertyTypes": false,
- "noPropertyAccessFromIndexSignature": false,
- "noUncheckedIndexedAccess": false,
- }
- }
\ No newline at end of file
js-packages/tsconfig.jsondiffbeforeafterboth--- a/js-packages/tsconfig.json
+++ b/js-packages/tsconfig.json
@@ -1,11 +1,15 @@
{
- "references": [
- { "path": "./types/tsconfig.json" },
- { "path": "./playgrounds/tsconfig.json" },
- { "path": "./scripts/tsconfig.json" },
- { "path": "./tests/tsconfig.json" }
+ "exclude": [
+ "**/node_modules"
],
- "files": [],
- "exclude": ["**/node_modules"]
- }
-
\ No newline at end of file
+ "compilerOptions": {
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "target": "ES2022",
+ "declaration": true,
+ "checkJs": false,
+ "strict": true,
+ "resolveJsonModule": true,
+ },
+}
js-packages/tsconfig.packages.jsondiffbeforeafterboth--- a/js-packages/tsconfig.packages.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
-
- /**
- * This needs to align with scripts/polkadot-dev-build-ts & dev-ts/loader
- * (target here is specifically tied to the minimum supported version)
- */
- "module": "nodenext",
- "moduleResolution": "nodenext",
- "target": "ES2022",
-
- /**
- * Specific compilation configs for polkadot-js projects as it is used
- * (we only compile *.d.ts via the tsc command-line)
- */
- "declaration": true,
- "emitDeclarationOnly": true,
- "jsx": "preserve",
- "verbatimModuleSyntax": false,
-
- /**
- * These appear in strictest, however we don't (yet) use them. For the most part it means
- * that we actually do have a large number of these lurking (especially on index checks)
- */
- "checkJs": false,
- "exactOptionalPropertyTypes": false,
- "noPropertyAccessFromIndexSignature": false,
- "noUncheckedIndexedAccess": false,
- },
-}
\ No newline at end of file
js-packages/types/.gitignorediffbeforeafterboth--- /dev/null
+++ b/js-packages/types/.gitignore
@@ -0,0 +1 @@
+metadata.json
js-packages/types/appPromotion/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/appPromotion/definitions.ts
@@ -0,0 +1,58 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+type RpcParam = {
+ name: string;
+ type: string;
+ isOptional?: true;
+};
+
+const CROSS_ACCOUNT_ID_TYPE = 'PalletEvmAccountBasicCrossAccountIdRepr';
+
+const crossAccountParam = (name = 'account') => ({name, type: CROSS_ACCOUNT_ID_TYPE});
+const atParam = {name: 'at', type: 'Hash', isOptional: true};
+
+const fun = (description: string, params: RpcParam[], type: string) => ({
+ description,
+ params: [...params, atParam],
+ type,
+});
+
+export default {
+ types: {},
+ rpc: {
+ totalStaked: fun(
+ 'Returns the total amount of staked tokens',
+ [{name: 'staker', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
+ 'u128',
+ ),
+ totalStakedPerBlock: fun(
+ 'Returns the total amount of staked tokens per block when staked',
+ [crossAccountParam('staker')],
+ 'Vec<(u32, u128)>',
+ ),
+ pendingUnstake: fun(
+ 'Returns the total amount of unstaked tokens',
+ [{name: 'staker', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
+ 'u128',
+ ),
+ pendingUnstakePerBlock: fun(
+ 'Returns the total amount of unstaked tokens per block',
+ [crossAccountParam('staker')],
+ 'Vec<(u32, u128)>',
+ ),
+ },
+};
js-packages/types/appPromotion/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/appPromotion/index.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './types.js';
js-packages/types/appPromotion/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/appPromotion/types.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export type PHANTOM_APPPROMOTION = 'appPromotion';
js-packages/types/augment-api-consts.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-consts.ts
@@ -0,0 +1,552 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/api-base/types/consts';
+
+import type { ApiTypes, AugmentedConst } from '@polkadot/api-base/types';
+import type { Option, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { Codec, ITuple } from '@polkadot/types-codec/types';
+import type { H160, Perbill, Permill } from '@polkadot/types/interfaces/runtime';
+import type { FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, PalletReferendaTrackInfo, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, StagingXcmV3MultiLocation, UpDataStructsCollectionLimits } from '@polkadot/types/lookup';
+
+export type __AugmentedConst<ApiType extends ApiTypes> = AugmentedConst<ApiType>;
+
+declare module '@polkadot/api-base/types/consts' {
+ interface AugmentedConsts<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * Freeze identifier used by the pallet
+ **/
+ freezeIdentifier: U8aFixed & AugmentedConst<ApiType>;
+ /**
+ * Rate of return for interval in blocks defined in `RecalculationInterval`.
+ **/
+ intervalIncome: Perbill & AugmentedConst<ApiType>;
+ /**
+ * Decimals for the `Currency`.
+ **/
+ nominal: u128 & AugmentedConst<ApiType>;
+ /**
+ * The app's pallet id, used for deriving its sovereign account address.
+ **/
+ palletId: FrameSupportPalletId & AugmentedConst<ApiType>;
+ /**
+ * In parachain blocks.
+ **/
+ pendingInterval: u32 & AugmentedConst<ApiType>;
+ /**
+ * In relay blocks.
+ **/
+ recalculationInterval: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ balances: {
+ /**
+ * The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO!
+ *
+ * If you *really* need it to be zero, you can enable the feature `insecure_zero_ed` for
+ * this pallet. However, you do so at your own risk: this will open up a major DoS vector.
+ * In case you have multiple sources of provider references, you may also get unexpected
+ * behaviour if you set this to zero.
+ *
+ * Bottom line: Do yourself a favour and make it at least one!
+ **/
+ existentialDeposit: u128 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of individual freeze locks that can exist on an account at any time.
+ **/
+ maxFreezes: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of holds that can exist on an account at any time.
+ **/
+ maxHolds: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of locks that should exist on an account.
+ * Not strictly enforced, but used for weight estimation.
+ **/
+ maxLocks: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of named reserves that can exist on an account.
+ **/
+ maxReserves: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ common: {
+ /**
+ * Maximum admins per collection.
+ **/
+ collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
+ /**
+ * Set price to create a collection.
+ **/
+ collectionCreationPrice: u128 & AugmentedConst<ApiType>;
+ /**
+ * Address under which the CollectionHelper contract would be available.
+ **/
+ contractAddress: H160 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ configuration: {
+ appPromotionDailyRate: Perbill & AugmentedConst<ApiType>;
+ dayRelayBlocks: u32 & AugmentedConst<ApiType>;
+ defaultCollatorSelectionKickThreshold: u32 & AugmentedConst<ApiType>;
+ defaultCollatorSelectionLicenseBond: u128 & AugmentedConst<ApiType>;
+ defaultCollatorSelectionMaxCollators: u32 & AugmentedConst<ApiType>;
+ defaultMinGasPrice: u64 & AugmentedConst<ApiType>;
+ defaultWeightToFeeCoefficient: u64 & AugmentedConst<ApiType>;
+ maxXcmAllowedLocations: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ council: {
+ /**
+ * The maximum weight of a dispatch call that can be proposed and executed.
+ **/
+ maxProposalWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ democracy: {
+ /**
+ * Period in blocks where an external proposal may not be re-submitted after being vetoed.
+ **/
+ cooloffPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * The period between a proposal being approved and enacted.
+ *
+ * It should generally be a little more than the unstake period to ensure that
+ * voting stakers have an opportunity to remove themselves from the system in the case
+ * where they are on the losing side of a vote.
+ **/
+ enactmentPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * Minimum voting period allowed for a fast-track referendum.
+ **/
+ fastTrackVotingPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * Indicator for whether an emergency origin is even allowed to happen. Some chains may
+ * want to set this permanently to `false`, others may want to condition it on things such
+ * as an upgrade having happened recently.
+ **/
+ instantAllowed: bool & AugmentedConst<ApiType>;
+ /**
+ * How often (in blocks) new public referenda are launched.
+ **/
+ launchPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of items which can be blacklisted.
+ **/
+ maxBlacklisted: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of deposits a public proposal may have at any time.
+ **/
+ maxDeposits: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of public proposals that can exist at any time.
+ **/
+ maxProposals: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of votes for an account.
+ *
+ * Also used to compute weight, an overly big value can
+ * lead to extrinsic with very big weight: see `delegate` for instance.
+ **/
+ maxVotes: u32 & AugmentedConst<ApiType>;
+ /**
+ * The minimum amount to be used as a deposit for a public referendum proposal.
+ **/
+ minimumDeposit: u128 & AugmentedConst<ApiType>;
+ /**
+ * The minimum period of vote locking.
+ *
+ * It should be no shorter than enactment period to ensure that in the case of an approval,
+ * those successful voters are locked into the consequences that their votes entail.
+ **/
+ voteLockingPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * How often (in blocks) to check for new votes.
+ **/
+ votingPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ evmContractHelpers: {
+ /**
+ * Address, under which magic contract will be available
+ **/
+ contractAddress: H160 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ fellowshipReferenda: {
+ /**
+ * Quantization level for the referendum wakeup scheduler. A higher number will result in
+ * fewer storage reads/writes needed for smaller voters, but also result in delays to the
+ * automatic referendum status changes. Explicit servicing instructions are unaffected.
+ **/
+ alarmInterval: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximum size of the referendum queue for a single track.
+ **/
+ maxQueued: u32 & AugmentedConst<ApiType>;
+ /**
+ * The minimum amount to be used as a deposit for a public referendum proposal.
+ **/
+ submissionDeposit: u128 & AugmentedConst<ApiType>;
+ /**
+ * Information concerning the different referendum tracks.
+ **/
+ tracks: Vec<ITuple<[u16, PalletReferendaTrackInfo]>> & AugmentedConst<ApiType>;
+ /**
+ * The number of blocks after submission that a referendum must begin being decided by.
+ * Once this passes, then anyone may cancel the referendum.
+ **/
+ undecidingTimeout: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ identity: {
+ /**
+ * The amount held on deposit for a registered identity
+ **/
+ basicDeposit: u128 & AugmentedConst<ApiType>;
+ /**
+ * The amount held on deposit per additional field for a registered identity.
+ **/
+ fieldDeposit: u128 & AugmentedConst<ApiType>;
+ /**
+ * Maximum number of additional fields that may be stored in an ID. Needed to bound the I/O
+ * required to access an identity, but can be pretty high.
+ **/
+ maxAdditionalFields: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maxmimum number of registrars allowed in the system. Needed to bound the complexity
+ * of, e.g., updating judgements.
+ **/
+ maxRegistrars: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of sub-accounts allowed per identified account.
+ **/
+ maxSubAccounts: u32 & AugmentedConst<ApiType>;
+ /**
+ * The amount held on deposit for a registered subaccount. This should account for the fact
+ * that one storage item's value will increase by the size of an account ID, and there will
+ * be another trie item whose value is the size of an account ID plus 32 bytes.
+ **/
+ subAccountDeposit: u128 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ inflation: {
+ /**
+ * Number of blocks that pass between treasury balance updates due to inflation
+ **/
+ inflationBlockInterval: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ scheduler: {
+ /**
+ * The maximum weight that may be scheduled per block for any dispatchables.
+ **/
+ maximumWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of scheduled calls in the queue for a single block.
+ *
+ * NOTE:
+ * + Dependent pallets' benchmarks might require a higher limit for the setting. Set a
+ * higher limit under `runtime-benchmarks` feature.
+ **/
+ maxScheduledPerBlock: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ stateTrieMigration: {
+ /**
+ * Maximal number of bytes that a key can have.
+ *
+ * FRAME itself does not limit the key length.
+ * The concrete value must therefore depend on your storage usage.
+ * A [`frame_support::storage::StorageNMap`] for example can have an arbitrary number of
+ * keys which are then hashed and concatenated, resulting in arbitrarily long keys.
+ *
+ * Use the *state migration RPC* to retrieve the length of the longest key in your
+ * storage: <https://github.com/paritytech/substrate/issues/11642>
+ *
+ * The migration will halt with a `Halted` event if this value is too small.
+ * Since there is no real penalty from over-estimating, it is advised to use a large
+ * value. The default is 512 byte.
+ *
+ * Some key lengths for reference:
+ * - [`frame_support::storage::StorageValue`]: 32 byte
+ * - [`frame_support::storage::StorageMap`]: 64 byte
+ * - [`frame_support::storage::StorageDoubleMap`]: 96 byte
+ *
+ * For more info see
+ * <https://www.shawntabrizi.com/substrate/querying-substrate-storage-via-rpc/>
+ **/
+ maxKeyLen: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ system: {
+ /**
+ * Maximum number of block number to block hash mappings to keep (oldest pruned first).
+ **/
+ blockHashCount: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum length of a block (in bytes).
+ **/
+ blockLength: FrameSystemLimitsBlockLength & AugmentedConst<ApiType>;
+ /**
+ * Block & extrinsics weights: base values and limits.
+ **/
+ blockWeights: FrameSystemLimitsBlockWeights & AugmentedConst<ApiType>;
+ /**
+ * The weight of runtime database operations the runtime can invoke.
+ **/
+ dbWeight: SpWeightsRuntimeDbWeight & AugmentedConst<ApiType>;
+ /**
+ * The designated SS58 prefix of this chain.
+ *
+ * This replaces the "ss58Format" property declared in the chain spec. Reason is
+ * that the runtime should know about the prefix in order to make use of it as
+ * an identifier of the chain.
+ **/
+ ss58Prefix: u16 & AugmentedConst<ApiType>;
+ /**
+ * Get the chain's current version.
+ **/
+ version: SpVersionRuntimeVersion & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ technicalCommittee: {
+ /**
+ * The maximum weight of a dispatch call that can be proposed and executed.
+ **/
+ maxProposalWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ timestamp: {
+ /**
+ * The minimum period between blocks. Beware that this is different to the *expected*
+ * period that the block production apparatus provides. Your chosen consensus system will
+ * generally work with this to determine a sensible block time. e.g. For Aura, it will be
+ * double this period on default settings.
+ **/
+ minimumPeriod: u64 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ tokens: {
+ maxLocks: u32 & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of named reserves that can exist on an account.
+ **/
+ maxReserves: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ transactionPayment: {
+ /**
+ * A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their
+ * `priority`
+ *
+ * This value is multipled by the `final_fee` to obtain a "virtual tip" that is later
+ * added to a tip component in regular `priority` calculations.
+ * It means that a `Normal` transaction can front-run a similarly-sized `Operational`
+ * extrinsic (with no tip), by including a tip value greater than the virtual tip.
+ *
+ * ```rust,ignore
+ * // For `Normal`
+ * let priority = priority_calc(tip);
+ *
+ * // For `Operational`
+ * let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;
+ * let priority = priority_calc(tip + virtual_tip);
+ * ```
+ *
+ * Note that since we use `final_fee` the multiplier applies also to the regular `tip`
+ * sent with the transaction. So, not only does the transaction get a priority bump based
+ * on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`
+ * transactions.
+ **/
+ operationalFeeMultiplier: u8 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ treasury: {
+ /**
+ * Percentage of spare funds (if any) that are burnt per spend period.
+ **/
+ burn: Permill & AugmentedConst<ApiType>;
+ /**
+ * The maximum number of approvals that can wait in the spending queue.
+ *
+ * NOTE: This parameter is also used within the Bounties Pallet extension if enabled.
+ **/
+ maxApprovals: u32 & AugmentedConst<ApiType>;
+ /**
+ * The treasury's pallet id, used for deriving its sovereign account ID.
+ **/
+ palletId: FrameSupportPalletId & AugmentedConst<ApiType>;
+ /**
+ * Fraction of a proposal's value that should be bonded in order to place the proposal.
+ * An accepted proposal gets these back. A rejected proposal does not.
+ **/
+ proposalBond: Permill & AugmentedConst<ApiType>;
+ /**
+ * Maximum amount of funds that should be placed in a deposit for making a proposal.
+ **/
+ proposalBondMaximum: Option<u128> & AugmentedConst<ApiType>;
+ /**
+ * Minimum amount of funds that should be placed in a deposit for making a proposal.
+ **/
+ proposalBondMinimum: u128 & AugmentedConst<ApiType>;
+ /**
+ * Period between successive spends.
+ **/
+ spendPeriod: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ unique: {
+ /**
+ * Maximum admins per collection.
+ **/
+ collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
+ /**
+ * Default FT collection limit.
+ **/
+ ftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
+ /**
+ * Maximal length of a collection description.
+ **/
+ maxCollectionDescriptionLength: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximal length of a collection name.
+ **/
+ maxCollectionNameLength: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximum size for all collection properties.
+ **/
+ maxCollectionPropertiesSize: u32 & AugmentedConst<ApiType>;
+ /**
+ * A maximum number of token properties.
+ **/
+ maxPropertiesPerItem: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximal length of a property key.
+ **/
+ maxPropertyKeyLength: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximal length of a property value.
+ **/
+ maxPropertyValueLength: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximal length of a token prefix.
+ **/
+ maxTokenPrefixLength: u32 & AugmentedConst<ApiType>;
+ /**
+ * Maximum size of all token properties.
+ **/
+ maxTokenPropertiesSize: u32 & AugmentedConst<ApiType>;
+ /**
+ * A maximum number of levels of depth in the token nesting tree.
+ **/
+ nestingBudget: u32 & AugmentedConst<ApiType>;
+ /**
+ * Default NFT collection limit.
+ **/
+ nftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
+ /**
+ * Default RFT collection limit.
+ **/
+ rftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ utility: {
+ /**
+ * The limit on the number of batched calls.
+ **/
+ batchedCallsLimit: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ vesting: {
+ /**
+ * The minimum amount transferred to call `vested_transfer`.
+ **/
+ minVestedTransfer: u128 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ xTokens: {
+ /**
+ * Base XCM weight.
+ *
+ * The actually weight for an XCM message is `T::BaseXcmWeight +
+ * T::Weigher::weight(&msg)`.
+ **/
+ baseXcmWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
+ /**
+ * Self chain location.
+ **/
+ selfLocation: StagingXcmV3MultiLocation & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
+ } // AugmentedConsts
+} // declare module
js-packages/types/augment-api-errors.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-errors.ts
@@ -0,0 +1,1521 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/api-base/types/errors';
+
+import type { ApiTypes, AugmentedError } from '@polkadot/api-base/types';
+
+export type __AugmentedError<ApiType extends ApiTypes> = AugmentedError<ApiType>;
+
+declare module '@polkadot/api-base/types/errors' {
+ interface AugmentedErrors<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * Error due to action requiring admin to be set.
+ **/
+ AdminNotSet: AugmentedError<ApiType>;
+ /**
+ * Errors caused by incorrect state of a staker in context of the pallet.
+ **/
+ InconsistencyState: AugmentedError<ApiType>;
+ /**
+ * Errors caused by insufficient staked balance.
+ **/
+ InsufficientStakedBalance: AugmentedError<ApiType>;
+ /**
+ * No permission to perform an action.
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * Insufficient funds to perform an action.
+ **/
+ NotSufficientFunds: AugmentedError<ApiType>;
+ /**
+ * Occurs when a pending unstake cannot be added in this block. PENDING_LIMIT_PER_BLOCK` limits exceeded.
+ **/
+ PendingForBlockOverflow: AugmentedError<ApiType>;
+ /**
+ * The error is due to the fact that the collection/contract must already be sponsored in order to perform the action.
+ **/
+ SponsorNotSet: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ balances: {
+ /**
+ * Beneficiary account must pre-exist.
+ **/
+ DeadAccount: AugmentedError<ApiType>;
+ /**
+ * Value too low to create account due to existential deposit.
+ **/
+ ExistentialDeposit: AugmentedError<ApiType>;
+ /**
+ * A vesting schedule already exists for this account.
+ **/
+ ExistingVestingSchedule: AugmentedError<ApiType>;
+ /**
+ * Transfer/payment would kill account.
+ **/
+ Expendability: AugmentedError<ApiType>;
+ /**
+ * Balance too low to send value.
+ **/
+ InsufficientBalance: AugmentedError<ApiType>;
+ /**
+ * Account liquidity restrictions prevent withdrawal.
+ **/
+ LiquidityRestrictions: AugmentedError<ApiType>;
+ /**
+ * Number of freezes exceed `MaxFreezes`.
+ **/
+ TooManyFreezes: AugmentedError<ApiType>;
+ /**
+ * Number of holds exceed `MaxHolds`.
+ **/
+ TooManyHolds: AugmentedError<ApiType>;
+ /**
+ * Number of named reserves exceed `MaxReserves`.
+ **/
+ TooManyReserves: AugmentedError<ApiType>;
+ /**
+ * Vesting balance too high to send value.
+ **/
+ VestingBalance: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ collatorSelection: {
+ /**
+ * User is already a candidate
+ **/
+ AlreadyCandidate: AugmentedError<ApiType>;
+ /**
+ * User already holds license to collate
+ **/
+ AlreadyHoldingLicense: AugmentedError<ApiType>;
+ /**
+ * User is already an Invulnerable
+ **/
+ AlreadyInvulnerable: AugmentedError<ApiType>;
+ /**
+ * Account has no associated validator ID
+ **/
+ NoAssociatedValidatorId: AugmentedError<ApiType>;
+ /**
+ * User does not hold a license to collate
+ **/
+ NoLicense: AugmentedError<ApiType>;
+ /**
+ * User is not a candidate
+ **/
+ NotCandidate: AugmentedError<ApiType>;
+ /**
+ * User is not an Invulnerable
+ **/
+ NotInvulnerable: AugmentedError<ApiType>;
+ /**
+ * Permission issue
+ **/
+ Permission: AugmentedError<ApiType>;
+ /**
+ * Too few invulnerables
+ **/
+ TooFewInvulnerables: AugmentedError<ApiType>;
+ /**
+ * Too many candidates
+ **/
+ TooManyCandidates: AugmentedError<ApiType>;
+ /**
+ * Too many invulnerables
+ **/
+ TooManyInvulnerables: AugmentedError<ApiType>;
+ /**
+ * Unknown error
+ **/
+ Unknown: AugmentedError<ApiType>;
+ /**
+ * Validator ID is not yet registered
+ **/
+ ValidatorNotRegistered: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ common: {
+ /**
+ * Account token limit exceeded per collection
+ **/
+ AccountTokenLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * Only spending from eth mirror could be approved
+ **/
+ AddressIsNotEthMirror: AugmentedError<ApiType>;
+ /**
+ * Can't transfer tokens to ethereum zero address
+ **/
+ AddressIsZero: AugmentedError<ApiType>;
+ /**
+ * Address is not in allow list.
+ **/
+ AddressNotInAllowlist: AugmentedError<ApiType>;
+ /**
+ * Requested value is more than the approved
+ **/
+ ApprovedValueTooLow: AugmentedError<ApiType>;
+ /**
+ * Tried to approve more than owned
+ **/
+ CantApproveMoreThanOwned: AugmentedError<ApiType>;
+ /**
+ * Destroying only empty collections is allowed
+ **/
+ CantDestroyNotEmptyCollection: AugmentedError<ApiType>;
+ /**
+ * Exceeded max admin count
+ **/
+ CollectionAdminCountExceeded: AugmentedError<ApiType>;
+ /**
+ * Collection description can not be longer than 255 char.
+ **/
+ CollectionDescriptionLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * Tried to store more data than allowed in collection field
+ **/
+ CollectionFieldSizeExceeded: AugmentedError<ApiType>;
+ /**
+ * Tried to access an external collection with an internal API
+ **/
+ CollectionIsExternal: AugmentedError<ApiType>;
+ /**
+ * Tried to access an internal collection with an external API
+ **/
+ CollectionIsInternal: AugmentedError<ApiType>;
+ /**
+ * Collection limit bounds per collection exceeded
+ **/
+ CollectionLimitBoundsExceeded: AugmentedError<ApiType>;
+ /**
+ * Collection name can not be longer than 63 char.
+ **/
+ CollectionNameLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * This collection does not exist.
+ **/
+ CollectionNotFound: AugmentedError<ApiType>;
+ /**
+ * Collection token limit exceeded
+ **/
+ CollectionTokenLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * Token prefix can not be longer than 15 char.
+ **/
+ CollectionTokenPrefixLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * This address is not set as sponsor, use setCollectionSponsor first.
+ **/
+ ConfirmSponsorshipFail: AugmentedError<ApiType>;
+ /**
+ * Empty property keys are forbidden
+ **/
+ EmptyPropertyKey: AugmentedError<ApiType>;
+ /**
+ * Fungible tokens hold no ID, and the default value of TokenId for a fungible collection is 0.
+ **/
+ FungibleItemsHaveNoId: AugmentedError<ApiType>;
+ /**
+ * Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed
+ **/
+ InvalidCharacterInPropertyKey: AugmentedError<ApiType>;
+ /**
+ * Metadata flag frozen
+ **/
+ MetadataFlagFrozen: AugmentedError<ApiType>;
+ /**
+ * Sender parameter and item owner must be equal.
+ **/
+ MustBeTokenOwner: AugmentedError<ApiType>;
+ /**
+ * No permission to perform action
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * Tried to store more property data than allowed
+ **/
+ NoSpaceForProperty: AugmentedError<ApiType>;
+ /**
+ * Insufficient funds to perform an action
+ **/
+ NotSufficientFounds: AugmentedError<ApiType>;
+ /**
+ * Tried to enable permissions which are only permitted to be disabled
+ **/
+ OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;
+ /**
+ * Property key is too long
+ **/
+ PropertyKeyIsTooLong: AugmentedError<ApiType>;
+ /**
+ * Tried to store more property keys than allowed
+ **/
+ PropertyLimitReached: AugmentedError<ApiType>;
+ /**
+ * Collection is not in mint mode.
+ **/
+ PublicMintingNotAllowed: AugmentedError<ApiType>;
+ /**
+ * Only tokens from specific collections may nest tokens under this one
+ **/
+ SourceCollectionIsNotAllowedToNest: AugmentedError<ApiType>;
+ /**
+ * Item does not exist
+ **/
+ TokenNotFound: AugmentedError<ApiType>;
+ /**
+ * Item is balance not enough
+ **/
+ TokenValueTooLow: AugmentedError<ApiType>;
+ /**
+ * Total collections bound exceeded.
+ **/
+ TotalCollectionsLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * Collection settings not allowing items transferring
+ **/
+ TransferNotAllowed: AugmentedError<ApiType>;
+ /**
+ * The operation is not supported
+ **/
+ UnsupportedOperation: AugmentedError<ApiType>;
+ /**
+ * User does not satisfy the nesting rule
+ **/
+ UserIsNotAllowedToNest: AugmentedError<ApiType>;
+ /**
+ * The user is not an administrator.
+ **/
+ UserIsNotCollectionAdmin: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ configuration: {
+ InconsistentConfiguration: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ council: {
+ /**
+ * Members are already initialized!
+ **/
+ AlreadyInitialized: AugmentedError<ApiType>;
+ /**
+ * Duplicate proposals not allowed
+ **/
+ DuplicateProposal: AugmentedError<ApiType>;
+ /**
+ * Duplicate vote ignored
+ **/
+ DuplicateVote: AugmentedError<ApiType>;
+ /**
+ * Account is not a member
+ **/
+ NotMember: AugmentedError<ApiType>;
+ /**
+ * Prime account is not a member
+ **/
+ PrimeAccountNotMember: AugmentedError<ApiType>;
+ /**
+ * Proposal must exist
+ **/
+ ProposalMissing: AugmentedError<ApiType>;
+ /**
+ * The close call was made too early, before the end of the voting.
+ **/
+ TooEarly: AugmentedError<ApiType>;
+ /**
+ * There can only be a maximum of `MaxProposals` active proposals.
+ **/
+ TooManyProposals: AugmentedError<ApiType>;
+ /**
+ * Mismatched index
+ **/
+ WrongIndex: AugmentedError<ApiType>;
+ /**
+ * The given length bound for the proposal was too low.
+ **/
+ WrongProposalLength: AugmentedError<ApiType>;
+ /**
+ * The given weight bound for the proposal was too low.
+ **/
+ WrongProposalWeight: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ councilMembership: {
+ /**
+ * Already a member.
+ **/
+ AlreadyMember: AugmentedError<ApiType>;
+ /**
+ * Not a member.
+ **/
+ NotMember: AugmentedError<ApiType>;
+ /**
+ * Too many members.
+ **/
+ TooManyMembers: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ cumulusXcm: {
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ democracy: {
+ /**
+ * Cannot cancel the same proposal twice
+ **/
+ AlreadyCanceled: AugmentedError<ApiType>;
+ /**
+ * The account is already delegating.
+ **/
+ AlreadyDelegating: AugmentedError<ApiType>;
+ /**
+ * Identity may not veto a proposal twice
+ **/
+ AlreadyVetoed: AugmentedError<ApiType>;
+ /**
+ * Proposal already made
+ **/
+ DuplicateProposal: AugmentedError<ApiType>;
+ /**
+ * The instant referendum origin is currently disallowed.
+ **/
+ InstantNotAllowed: AugmentedError<ApiType>;
+ /**
+ * Too high a balance was provided that the account cannot afford.
+ **/
+ InsufficientFunds: AugmentedError<ApiType>;
+ /**
+ * Invalid hash
+ **/
+ InvalidHash: AugmentedError<ApiType>;
+ /**
+ * Maximum number of votes reached.
+ **/
+ MaxVotesReached: AugmentedError<ApiType>;
+ /**
+ * No proposals waiting
+ **/
+ NoneWaiting: AugmentedError<ApiType>;
+ /**
+ * Delegation to oneself makes no sense.
+ **/
+ Nonsense: AugmentedError<ApiType>;
+ /**
+ * The actor has no permission to conduct the action.
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * No external proposal
+ **/
+ NoProposal: AugmentedError<ApiType>;
+ /**
+ * The account is not currently delegating.
+ **/
+ NotDelegating: AugmentedError<ApiType>;
+ /**
+ * Next external proposal not simple majority
+ **/
+ NotSimpleMajority: AugmentedError<ApiType>;
+ /**
+ * The given account did not vote on the referendum.
+ **/
+ NotVoter: AugmentedError<ApiType>;
+ /**
+ * The preimage does not exist.
+ **/
+ PreimageNotExist: AugmentedError<ApiType>;
+ /**
+ * Proposal still blacklisted
+ **/
+ ProposalBlacklisted: AugmentedError<ApiType>;
+ /**
+ * Proposal does not exist
+ **/
+ ProposalMissing: AugmentedError<ApiType>;
+ /**
+ * Vote given for invalid referendum
+ **/
+ ReferendumInvalid: AugmentedError<ApiType>;
+ /**
+ * Maximum number of items reached.
+ **/
+ TooMany: AugmentedError<ApiType>;
+ /**
+ * Value too low
+ **/
+ ValueLow: AugmentedError<ApiType>;
+ /**
+ * The account currently has votes attached to it and the operation cannot succeed until
+ * these are removed, either through `unvote` or `reap_vote`.
+ **/
+ VotesExist: AugmentedError<ApiType>;
+ /**
+ * Voting period too low
+ **/
+ VotingPeriodLow: AugmentedError<ApiType>;
+ /**
+ * Invalid upper bound.
+ **/
+ WrongUpperBound: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ dmpQueue: {
+ /**
+ * The amount of weight given is possibly not enough for executing the message.
+ **/
+ OverLimit: AugmentedError<ApiType>;
+ /**
+ * The message index given is unknown.
+ **/
+ Unknown: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ ethereum: {
+ /**
+ * Signature is invalid.
+ **/
+ InvalidSignature: AugmentedError<ApiType>;
+ /**
+ * Pre-log is present, therefore transact is not allowed.
+ **/
+ PreLogExists: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ evm: {
+ /**
+ * Not enough balance to perform action
+ **/
+ BalanceLow: AugmentedError<ApiType>;
+ /**
+ * Calculating total fee overflowed
+ **/
+ FeeOverflow: AugmentedError<ApiType>;
+ /**
+ * Gas limit is too high.
+ **/
+ GasLimitTooHigh: AugmentedError<ApiType>;
+ /**
+ * Gas limit is too low.
+ **/
+ GasLimitTooLow: AugmentedError<ApiType>;
+ /**
+ * Gas price is too low.
+ **/
+ GasPriceTooLow: AugmentedError<ApiType>;
+ /**
+ * Nonce is invalid
+ **/
+ InvalidNonce: AugmentedError<ApiType>;
+ /**
+ * Calculating total payment overflowed
+ **/
+ PaymentOverflow: AugmentedError<ApiType>;
+ /**
+ * EVM reentrancy
+ **/
+ Reentrancy: AugmentedError<ApiType>;
+ /**
+ * EIP-3607,
+ **/
+ TransactionMustComeFromEOA: AugmentedError<ApiType>;
+ /**
+ * Undefined error.
+ **/
+ Undefined: AugmentedError<ApiType>;
+ /**
+ * Withdraw fee failed
+ **/
+ WithdrawFailed: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ evmCoderSubstrate: {
+ OutOfFund: AugmentedError<ApiType>;
+ OutOfGas: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ evmContractHelpers: {
+ /**
+ * No pending sponsor for contract.
+ **/
+ NoPendingSponsor: AugmentedError<ApiType>;
+ /**
+ * This method is only executable by contract owner
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * Number of methods that sponsored limit is defined for exceeds maximum.
+ **/
+ TooManyMethodsHaveSponsoredLimit: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ evmMigration: {
+ /**
+ * Migration of this account is not yet started, or already finished.
+ **/
+ AccountIsNotMigrating: AugmentedError<ApiType>;
+ /**
+ * Can only migrate to empty address.
+ **/
+ AccountNotEmpty: AugmentedError<ApiType>;
+ /**
+ * Failed to decode event bytes
+ **/
+ BadEvent: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ fellowshipCollective: {
+ /**
+ * Account is already a member.
+ **/
+ AlreadyMember: AugmentedError<ApiType>;
+ /**
+ * Unexpected error in state.
+ **/
+ Corruption: AugmentedError<ApiType>;
+ /**
+ * The information provided is incorrect.
+ **/
+ InvalidWitness: AugmentedError<ApiType>;
+ /**
+ * There are no further records to be removed.
+ **/
+ NoneRemaining: AugmentedError<ApiType>;
+ /**
+ * The origin is not sufficiently privileged to do the operation.
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * Account is not a member.
+ **/
+ NotMember: AugmentedError<ApiType>;
+ /**
+ * The given poll index is unknown or has closed.
+ **/
+ NotPolling: AugmentedError<ApiType>;
+ /**
+ * The given poll is still ongoing.
+ **/
+ Ongoing: AugmentedError<ApiType>;
+ /**
+ * The member's rank is too low to vote.
+ **/
+ RankTooLow: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ fellowshipReferenda: {
+ /**
+ * The referendum index provided is invalid in this context.
+ **/
+ BadReferendum: AugmentedError<ApiType>;
+ /**
+ * The referendum status is invalid for this operation.
+ **/
+ BadStatus: AugmentedError<ApiType>;
+ /**
+ * The track identifier given was invalid.
+ **/
+ BadTrack: AugmentedError<ApiType>;
+ /**
+ * There are already a full complement of referenda in progress for this track.
+ **/
+ Full: AugmentedError<ApiType>;
+ /**
+ * Referendum's decision deposit is already paid.
+ **/
+ HasDeposit: AugmentedError<ApiType>;
+ /**
+ * The deposit cannot be refunded since none was made.
+ **/
+ NoDeposit: AugmentedError<ApiType>;
+ /**
+ * The deposit refunder is not the depositor.
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * There was nothing to do in the advancement.
+ **/
+ NothingToDo: AugmentedError<ApiType>;
+ /**
+ * Referendum is not ongoing.
+ **/
+ NotOngoing: AugmentedError<ApiType>;
+ /**
+ * No track exists for the proposal origin.
+ **/
+ NoTrack: AugmentedError<ApiType>;
+ /**
+ * The preimage does not exist.
+ **/
+ PreimageNotExist: AugmentedError<ApiType>;
+ /**
+ * The queue of the track is empty.
+ **/
+ QueueEmpty: AugmentedError<ApiType>;
+ /**
+ * Any deposit cannot be refunded until after the decision is over.
+ **/
+ Unfinished: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ foreignAssets: {
+ /**
+ * AssetId exists
+ **/
+ AssetIdExisted: AugmentedError<ApiType>;
+ /**
+ * AssetId not exists
+ **/
+ AssetIdNotExists: AugmentedError<ApiType>;
+ /**
+ * The given location could not be used (e.g. because it cannot be expressed in the
+ * desired version of XCM).
+ **/
+ BadLocation: AugmentedError<ApiType>;
+ /**
+ * MultiLocation existed
+ **/
+ MultiLocationExisted: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ fungible: {
+ /**
+ * Fungible token does not support nesting.
+ **/
+ FungibleDisallowsNesting: AugmentedError<ApiType>;
+ /**
+ * Tried to set data for fungible item.
+ **/
+ FungibleItemsDontHaveData: AugmentedError<ApiType>;
+ /**
+ * Only a fungible collection could be possibly broken; any fungible token is valid.
+ **/
+ FungibleTokensAreAlwaysValid: AugmentedError<ApiType>;
+ /**
+ * Not Fungible item data used to mint in Fungible collection.
+ **/
+ NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
+ /**
+ * Setting allowance for all is not allowed.
+ **/
+ SettingAllowanceForAllNotAllowed: AugmentedError<ApiType>;
+ /**
+ * Setting item properties is not allowed.
+ **/
+ SettingPropertiesNotAllowed: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ identity: {
+ /**
+ * Account ID is already named.
+ **/
+ AlreadyClaimed: AugmentedError<ApiType>;
+ /**
+ * Empty index.
+ **/
+ EmptyIndex: AugmentedError<ApiType>;
+ /**
+ * Fee is changed.
+ **/
+ FeeChanged: AugmentedError<ApiType>;
+ /**
+ * The index is invalid.
+ **/
+ InvalidIndex: AugmentedError<ApiType>;
+ /**
+ * Invalid judgement.
+ **/
+ InvalidJudgement: AugmentedError<ApiType>;
+ /**
+ * The target is invalid.
+ **/
+ InvalidTarget: AugmentedError<ApiType>;
+ /**
+ * The provided judgement was for a different identity.
+ **/
+ JudgementForDifferentIdentity: AugmentedError<ApiType>;
+ /**
+ * Judgement given.
+ **/
+ JudgementGiven: AugmentedError<ApiType>;
+ /**
+ * Error that occurs when there is an issue paying for judgement.
+ **/
+ JudgementPaymentFailed: AugmentedError<ApiType>;
+ /**
+ * No identity found.
+ **/
+ NoIdentity: AugmentedError<ApiType>;
+ /**
+ * Account isn't found.
+ **/
+ NotFound: AugmentedError<ApiType>;
+ /**
+ * Account isn't named.
+ **/
+ NotNamed: AugmentedError<ApiType>;
+ /**
+ * Sub-account isn't owned by sender.
+ **/
+ NotOwned: AugmentedError<ApiType>;
+ /**
+ * Sender is not a sub-account.
+ **/
+ NotSub: AugmentedError<ApiType>;
+ /**
+ * Sticky judgement.
+ **/
+ StickyJudgement: AugmentedError<ApiType>;
+ /**
+ * Too many additional fields.
+ **/
+ TooManyFields: AugmentedError<ApiType>;
+ /**
+ * Maximum amount of registrars reached. Cannot add any more.
+ **/
+ TooManyRegistrars: AugmentedError<ApiType>;
+ /**
+ * Too many subs-accounts.
+ **/
+ TooManySubAccounts: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ maintenance: {
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ nonfungible: {
+ /**
+ * Unable to burn NFT with children
+ **/
+ CantBurnNftWithChildren: AugmentedError<ApiType>;
+ /**
+ * Used amount > 1 with NFT
+ **/
+ NonfungibleItemsHaveNoAmount: AugmentedError<ApiType>;
+ /**
+ * Not Nonfungible item data used to mint in Nonfungible collection.
+ **/
+ NotNonfungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ parachainSystem: {
+ /**
+ * The inherent which supplies the host configuration did not run this block.
+ **/
+ HostConfigurationNotAvailable: AugmentedError<ApiType>;
+ /**
+ * No code upgrade has been authorized.
+ **/
+ NothingAuthorized: AugmentedError<ApiType>;
+ /**
+ * No validation function upgrade is currently scheduled.
+ **/
+ NotScheduled: AugmentedError<ApiType>;
+ /**
+ * Attempt to upgrade validation function while existing upgrade pending.
+ **/
+ OverlappingUpgrades: AugmentedError<ApiType>;
+ /**
+ * Polkadot currently prohibits this parachain from upgrading its validation function.
+ **/
+ ProhibitedByPolkadot: AugmentedError<ApiType>;
+ /**
+ * The supplied validation function has compiled into a blob larger than Polkadot is
+ * willing to run.
+ **/
+ TooBig: AugmentedError<ApiType>;
+ /**
+ * The given code upgrade has not been authorized.
+ **/
+ Unauthorized: AugmentedError<ApiType>;
+ /**
+ * The inherent which supplies the validation data did not run this block.
+ **/
+ ValidationDataNotAvailable: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ polkadotXcm: {
+ /**
+ * The given account is not an identifiable sovereign account for any location.
+ **/
+ AccountNotSovereign: AugmentedError<ApiType>;
+ /**
+ * The location is invalid since it already has a subscription from us.
+ **/
+ AlreadySubscribed: AugmentedError<ApiType>;
+ /**
+ * The given location could not be used (e.g. because it cannot be expressed in the
+ * desired version of XCM).
+ **/
+ BadLocation: AugmentedError<ApiType>;
+ /**
+ * The version of the `Versioned` value used is not able to be interpreted.
+ **/
+ BadVersion: AugmentedError<ApiType>;
+ /**
+ * Could not re-anchor the assets to declare the fees for the destination chain.
+ **/
+ CannotReanchor: AugmentedError<ApiType>;
+ /**
+ * The destination `MultiLocation` provided cannot be inverted.
+ **/
+ DestinationNotInvertible: AugmentedError<ApiType>;
+ /**
+ * The assets to be sent are empty.
+ **/
+ Empty: AugmentedError<ApiType>;
+ /**
+ * The operation required fees to be paid which the initiator could not meet.
+ **/
+ FeesNotMet: AugmentedError<ApiType>;
+ /**
+ * The message execution fails the filter.
+ **/
+ Filtered: AugmentedError<ApiType>;
+ /**
+ * The unlock operation cannot succeed because there are still consumers of the lock.
+ **/
+ InUse: AugmentedError<ApiType>;
+ /**
+ * Invalid asset for the operation.
+ **/
+ InvalidAsset: AugmentedError<ApiType>;
+ /**
+ * Origin is invalid for sending.
+ **/
+ InvalidOrigin: AugmentedError<ApiType>;
+ /**
+ * A remote lock with the corresponding data could not be found.
+ **/
+ LockNotFound: AugmentedError<ApiType>;
+ /**
+ * The owner does not own (all) of the asset that they wish to do the operation on.
+ **/
+ LowBalance: AugmentedError<ApiType>;
+ /**
+ * The referenced subscription could not be found.
+ **/
+ NoSubscription: AugmentedError<ApiType>;
+ /**
+ * There was some other issue (i.e. not to do with routing) in sending the message.
+ * Perhaps a lack of space for buffering the message.
+ **/
+ SendFailure: AugmentedError<ApiType>;
+ /**
+ * Too many assets have been attempted for transfer.
+ **/
+ TooManyAssets: AugmentedError<ApiType>;
+ /**
+ * The asset owner has too many locks on the asset.
+ **/
+ TooManyLocks: AugmentedError<ApiType>;
+ /**
+ * The desired destination was unreachable, generally because there is a no way of routing
+ * to it.
+ **/
+ Unreachable: AugmentedError<ApiType>;
+ /**
+ * The message's weight could not be determined.
+ **/
+ UnweighableMessage: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ preimage: {
+ /**
+ * Preimage has already been noted on-chain.
+ **/
+ AlreadyNoted: AugmentedError<ApiType>;
+ /**
+ * The user is not authorized to perform this action.
+ **/
+ NotAuthorized: AugmentedError<ApiType>;
+ /**
+ * The preimage cannot be removed since it has not yet been noted.
+ **/
+ NotNoted: AugmentedError<ApiType>;
+ /**
+ * The preimage request cannot be removed since no outstanding requests exist.
+ **/
+ NotRequested: AugmentedError<ApiType>;
+ /**
+ * A preimage may not be removed when there are outstanding requests.
+ **/
+ Requested: AugmentedError<ApiType>;
+ /**
+ * Preimage is too large to store on-chain.
+ **/
+ TooBig: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ refungible: {
+ /**
+ * Not Refungible item data used to mint in Refungible collection.
+ **/
+ NotRefungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
+ /**
+ * Refungible token can't nest other tokens.
+ **/
+ RefungibleDisallowsNesting: AugmentedError<ApiType>;
+ /**
+ * Refungible token can't be repartitioned by user who isn't owns all pieces.
+ **/
+ RepartitionWhileNotOwningAllPieces: AugmentedError<ApiType>;
+ /**
+ * Setting item properties is not allowed.
+ **/
+ SettingPropertiesNotAllowed: AugmentedError<ApiType>;
+ /**
+ * Maximum refungibility exceeded.
+ **/
+ WrongRefungiblePieces: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ scheduler: {
+ /**
+ * Failed to schedule a call
+ **/
+ FailedToSchedule: AugmentedError<ApiType>;
+ /**
+ * Attempt to use a non-named function on a named task.
+ **/
+ Named: AugmentedError<ApiType>;
+ /**
+ * Cannot find the scheduled call.
+ **/
+ NotFound: AugmentedError<ApiType>;
+ /**
+ * Reschedule failed because it does not change scheduled time.
+ **/
+ RescheduleNoChange: AugmentedError<ApiType>;
+ /**
+ * Given target block number is in the past.
+ **/
+ TargetBlockNumberInPast: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ session: {
+ /**
+ * Registered duplicate key.
+ **/
+ DuplicatedKey: AugmentedError<ApiType>;
+ /**
+ * Invalid ownership proof.
+ **/
+ InvalidProof: AugmentedError<ApiType>;
+ /**
+ * Key setting account is not live, so it's impossible to associate keys.
+ **/
+ NoAccount: AugmentedError<ApiType>;
+ /**
+ * No associated validator ID for account.
+ **/
+ NoAssociatedValidatorId: AugmentedError<ApiType>;
+ /**
+ * No keys are associated with this account.
+ **/
+ NoKeys: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ stateTrieMigration: {
+ /**
+ * Bad child root provided.
+ **/
+ BadChildRoot: AugmentedError<ApiType>;
+ /**
+ * Bad witness data provided.
+ **/
+ BadWitness: AugmentedError<ApiType>;
+ /**
+ * A key was longer than the configured maximum.
+ *
+ * This means that the migration halted at the current [`Progress`] and
+ * can be resumed with a larger [`crate::Config::MaxKeyLen`] value.
+ * Retrying with the same [`crate::Config::MaxKeyLen`] value will not work.
+ * The value should only be increased to avoid a storage migration for the currently
+ * stored [`crate::Progress::LastKey`].
+ **/
+ KeyTooLong: AugmentedError<ApiType>;
+ /**
+ * Max signed limits not respected.
+ **/
+ MaxSignedLimits: AugmentedError<ApiType>;
+ /**
+ * submitter does not have enough funds.
+ **/
+ NotEnoughFunds: AugmentedError<ApiType>;
+ /**
+ * Signed migration is not allowed because the maximum limit is not set yet.
+ **/
+ SignedMigrationNotAllowed: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ structure: {
+ /**
+ * While nesting, reached the breadth limit of nesting, exceeding the provided budget.
+ **/
+ BreadthLimit: AugmentedError<ApiType>;
+ /**
+ * Tried to nest token under collection contract address, instead of token address
+ **/
+ CantNestTokenUnderCollection: AugmentedError<ApiType>;
+ /**
+ * While nesting, reached the depth limit of nesting, exceeding the provided budget.
+ **/
+ DepthLimit: AugmentedError<ApiType>;
+ /**
+ * While nesting, encountered an already checked account, detecting a loop.
+ **/
+ OuroborosDetected: AugmentedError<ApiType>;
+ /**
+ * Couldn't find the token owner that is itself a token.
+ **/
+ TokenNotFound: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ sudo: {
+ /**
+ * Sender must be the Sudo account
+ **/
+ RequireSudo: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ system: {
+ /**
+ * The origin filter prevent the call to be dispatched.
+ **/
+ CallFiltered: AugmentedError<ApiType>;
+ /**
+ * Failed to extract the runtime version from the new runtime.
+ *
+ * Either calling `Core_version` or decoding `RuntimeVersion` failed.
+ **/
+ FailedToExtractRuntimeVersion: AugmentedError<ApiType>;
+ /**
+ * The name of specification does not match between the current runtime
+ * and the new runtime.
+ **/
+ InvalidSpecName: AugmentedError<ApiType>;
+ /**
+ * Suicide called when the account has non-default composite data.
+ **/
+ NonDefaultComposite: AugmentedError<ApiType>;
+ /**
+ * There is a non-zero reference count preventing the account from being purged.
+ **/
+ NonZeroRefCount: AugmentedError<ApiType>;
+ /**
+ * The specification version is not allowed to decrease between the current runtime
+ * and the new runtime.
+ **/
+ SpecVersionNeedsToIncrease: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ technicalCommittee: {
+ /**
+ * Members are already initialized!
+ **/
+ AlreadyInitialized: AugmentedError<ApiType>;
+ /**
+ * Duplicate proposals not allowed
+ **/
+ DuplicateProposal: AugmentedError<ApiType>;
+ /**
+ * Duplicate vote ignored
+ **/
+ DuplicateVote: AugmentedError<ApiType>;
+ /**
+ * Account is not a member
+ **/
+ NotMember: AugmentedError<ApiType>;
+ /**
+ * Prime account is not a member
+ **/
+ PrimeAccountNotMember: AugmentedError<ApiType>;
+ /**
+ * Proposal must exist
+ **/
+ ProposalMissing: AugmentedError<ApiType>;
+ /**
+ * The close call was made too early, before the end of the voting.
+ **/
+ TooEarly: AugmentedError<ApiType>;
+ /**
+ * There can only be a maximum of `MaxProposals` active proposals.
+ **/
+ TooManyProposals: AugmentedError<ApiType>;
+ /**
+ * Mismatched index
+ **/
+ WrongIndex: AugmentedError<ApiType>;
+ /**
+ * The given length bound for the proposal was too low.
+ **/
+ WrongProposalLength: AugmentedError<ApiType>;
+ /**
+ * The given weight bound for the proposal was too low.
+ **/
+ WrongProposalWeight: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ technicalCommitteeMembership: {
+ /**
+ * Already a member.
+ **/
+ AlreadyMember: AugmentedError<ApiType>;
+ /**
+ * Not a member.
+ **/
+ NotMember: AugmentedError<ApiType>;
+ /**
+ * Too many members.
+ **/
+ TooManyMembers: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ testUtils: {
+ TestPalletDisabled: AugmentedError<ApiType>;
+ TriggerRollback: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ tokens: {
+ /**
+ * Cannot convert Amount into Balance type
+ **/
+ AmountIntoBalanceFailed: AugmentedError<ApiType>;
+ /**
+ * The balance is too low
+ **/
+ BalanceTooLow: AugmentedError<ApiType>;
+ /**
+ * Beneficiary account must pre-exist
+ **/
+ DeadAccount: AugmentedError<ApiType>;
+ /**
+ * Value too low to create account due to existential deposit
+ **/
+ ExistentialDeposit: AugmentedError<ApiType>;
+ /**
+ * Transfer/payment would kill account
+ **/
+ KeepAlive: AugmentedError<ApiType>;
+ /**
+ * Failed because liquidity restrictions due to locking
+ **/
+ LiquidityRestrictions: AugmentedError<ApiType>;
+ /**
+ * Failed because the maximum locks was exceeded
+ **/
+ MaxLocksExceeded: AugmentedError<ApiType>;
+ TooManyReserves: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ treasury: {
+ /**
+ * The spend origin is valid but the amount it is allowed to spend is lower than the
+ * amount to be spent.
+ **/
+ InsufficientPermission: AugmentedError<ApiType>;
+ /**
+ * Proposer's balance is too low.
+ **/
+ InsufficientProposersBalance: AugmentedError<ApiType>;
+ /**
+ * No proposal or bounty at that index.
+ **/
+ InvalidIndex: AugmentedError<ApiType>;
+ /**
+ * Proposal has not been approved.
+ **/
+ ProposalNotApproved: AugmentedError<ApiType>;
+ /**
+ * Too many approvals in the queue.
+ **/
+ TooManyApprovals: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ unique: {
+ /**
+ * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].
+ **/
+ CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;
+ /**
+ * Length of items properties must be greater than 0.
+ **/
+ EmptyArgument: AugmentedError<ApiType>;
+ /**
+ * Repertition is only supported by refungible collection.
+ **/
+ RepartitionCalledOnNonRefungibleCollection: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ utility: {
+ /**
+ * Too many calls batched.
+ **/
+ TooManyCalls: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ vesting: {
+ /**
+ * The vested transfer amount is too low
+ **/
+ AmountLow: AugmentedError<ApiType>;
+ /**
+ * Insufficient amount of balance to lock
+ **/
+ InsufficientBalanceToLock: AugmentedError<ApiType>;
+ /**
+ * Failed because the maximum vesting schedules was exceeded
+ **/
+ MaxVestingSchedulesExceeded: AugmentedError<ApiType>;
+ /**
+ * This account have too many vesting schedules
+ **/
+ TooManyVestingSchedules: AugmentedError<ApiType>;
+ /**
+ * Vesting period is zero
+ **/
+ ZeroVestingPeriod: AugmentedError<ApiType>;
+ /**
+ * Number of vests is zero
+ **/
+ ZeroVestingPeriodCount: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ xcmpQueue: {
+ /**
+ * Bad overweight index.
+ **/
+ BadOverweightIndex: AugmentedError<ApiType>;
+ /**
+ * Bad XCM data.
+ **/
+ BadXcm: AugmentedError<ApiType>;
+ /**
+ * Bad XCM origin.
+ **/
+ BadXcmOrigin: AugmentedError<ApiType>;
+ /**
+ * Failed to send XCM message.
+ **/
+ FailedToSend: AugmentedError<ApiType>;
+ /**
+ * Provided weight is possibly not enough to execute the message.
+ **/
+ WeightOverLimit: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ xTokens: {
+ /**
+ * Asset has no reserve location.
+ **/
+ AssetHasNoReserve: AugmentedError<ApiType>;
+ /**
+ * The specified index does not exist in a MultiAssets struct.
+ **/
+ AssetIndexNonExistent: AugmentedError<ApiType>;
+ /**
+ * The version of the `Versioned` value used is not able to be
+ * interpreted.
+ **/
+ BadVersion: AugmentedError<ApiType>;
+ /**
+ * Could not re-anchor the assets to declare the fees for the
+ * destination chain.
+ **/
+ CannotReanchor: AugmentedError<ApiType>;
+ /**
+ * The destination `MultiLocation` provided cannot be inverted.
+ **/
+ DestinationNotInvertible: AugmentedError<ApiType>;
+ /**
+ * We tried sending distinct asset and fee but they have different
+ * reserve chains.
+ **/
+ DistinctReserveForAssetAndFee: AugmentedError<ApiType>;
+ /**
+ * Fee is not enough.
+ **/
+ FeeNotEnough: AugmentedError<ApiType>;
+ /**
+ * Could not get ancestry of asset reserve location.
+ **/
+ InvalidAncestry: AugmentedError<ApiType>;
+ /**
+ * The MultiAsset is invalid.
+ **/
+ InvalidAsset: AugmentedError<ApiType>;
+ /**
+ * Invalid transfer destination.
+ **/
+ InvalidDest: AugmentedError<ApiType>;
+ /**
+ * MinXcmFee not registered for certain reserve location
+ **/
+ MinXcmFeeNotDefined: AugmentedError<ApiType>;
+ /**
+ * Not cross-chain transfer.
+ **/
+ NotCrossChainTransfer: AugmentedError<ApiType>;
+ /**
+ * Currency is not cross-chain transferable.
+ **/
+ NotCrossChainTransferableCurrency: AugmentedError<ApiType>;
+ /**
+ * Not supported MultiLocation
+ **/
+ NotSupportedMultiLocation: AugmentedError<ApiType>;
+ /**
+ * The number of assets to be sent is over the maximum.
+ **/
+ TooManyAssetsBeingSent: AugmentedError<ApiType>;
+ /**
+ * The message's weight could not be determined.
+ **/
+ UnweighableMessage: AugmentedError<ApiType>;
+ /**
+ * XCM execution failed.
+ **/
+ XcmExecutionFailed: AugmentedError<ApiType>;
+ /**
+ * The transfering asset amount is zero.
+ **/
+ ZeroAmount: AugmentedError<ApiType>;
+ /**
+ * The fee is zero.
+ **/
+ ZeroFee: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
+ } // AugmentedErrors
+} // declare module
js-packages/types/augment-api-events.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-events.ts
@@ -0,0 +1,1294 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/api-base/types/events';
+
+import type { ApiTypes, AugmentedEvent } from '@polkadot/api-base/types';
+import type { Bytes, Null, Option, Result, U8aFixed, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { ITuple } from '@polkadot/types-codec/types';
+import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';
+import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportDispatchDispatchInfo, FrameSupportPreimagesBounded, FrameSupportTokensMiscBalanceStatus, OrmlVestingVestingSchedule, PalletDemocracyMetadataOwner, PalletDemocracyVoteAccountVote, PalletDemocracyVoteThreshold, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletRankedCollectiveTally, PalletRankedCollectiveVoteRecord, PalletStateTrieMigrationError, PalletStateTrieMigrationMigrationCompute, SpRuntimeDispatchError, SpWeightsWeightV2Weight, StagingXcmV3MultiAsset, StagingXcmV3MultiLocation, StagingXcmV3MultiassetMultiAssets, StagingXcmV3Response, StagingXcmV3TraitsError, StagingXcmV3TraitsOutcome, StagingXcmV3Xcm, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation } from '@polkadot/types/lookup';
+
+export type __AugmentedEvent<ApiType extends ApiTypes> = AugmentedEvent<ApiType>;
+
+declare module '@polkadot/api-base/types/events' {
+ interface AugmentedEvents<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * The admin was set
+ *
+ * # Arguments
+ * * AccountId: account address of the admin
+ **/
+ SetAdmin: AugmentedEvent<ApiType, [AccountId32]>;
+ /**
+ * Staking was performed
+ *
+ * # Arguments
+ * * AccountId: account of the staker
+ * * Balance : staking amount
+ **/
+ Stake: AugmentedEvent<ApiType, [AccountId32, u128]>;
+ /**
+ * Staking recalculation was performed
+ *
+ * # Arguments
+ * * AccountId: account of the staker.
+ * * Balance : recalculation base
+ * * Balance : total income
+ **/
+ StakingRecalculation: AugmentedEvent<ApiType, [AccountId32, u128, u128]>;
+ /**
+ * Unstaking was performed
+ *
+ * # Arguments
+ * * AccountId: account of the staker
+ * * Balance : unstaking amount
+ **/
+ Unstake: AugmentedEvent<ApiType, [AccountId32, u128]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ balances: {
+ /**
+ * A balance was set by root.
+ **/
+ BalanceSet: AugmentedEvent<ApiType, [who: AccountId32, free: u128], { who: AccountId32, free: u128 }>;
+ /**
+ * Some amount was burned from an account.
+ **/
+ Burned: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some amount was deposited (e.g. for transaction fees).
+ **/
+ Deposit: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * An account was removed whose balance was non-zero but below ExistentialDeposit,
+ * resulting in an outright loss.
+ **/
+ DustLost: AugmentedEvent<ApiType, [account: AccountId32, amount: u128], { account: AccountId32, amount: u128 }>;
+ /**
+ * An account was created with some free balance.
+ **/
+ Endowed: AugmentedEvent<ApiType, [account: AccountId32, freeBalance: u128], { account: AccountId32, freeBalance: u128 }>;
+ /**
+ * Some balance was frozen.
+ **/
+ Frozen: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Total issuance was increased by `amount`, creating a credit to be balanced.
+ **/
+ Issued: AugmentedEvent<ApiType, [amount: u128], { amount: u128 }>;
+ /**
+ * Some balance was locked.
+ **/
+ Locked: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some amount was minted into an account.
+ **/
+ Minted: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Total issuance was decreased by `amount`, creating a debt to be balanced.
+ **/
+ Rescinded: AugmentedEvent<ApiType, [amount: u128], { amount: u128 }>;
+ /**
+ * Some balance was reserved (moved from free to reserved).
+ **/
+ Reserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some balance was moved from the reserve of the first account to the second account.
+ * Final argument indicates the destination balance type.
+ **/
+ ReserveRepatriated: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus], { from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus }>;
+ /**
+ * Some amount was restored into an account.
+ **/
+ Restored: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some amount was removed from the account (e.g. for misbehavior).
+ **/
+ Slashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some amount was suspended from an account (it can be restored later).
+ **/
+ Suspended: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some balance was thawed.
+ **/
+ Thawed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Transfer succeeded.
+ **/
+ Transfer: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128], { from: AccountId32, to: AccountId32, amount: u128 }>;
+ /**
+ * Some balance was unlocked.
+ **/
+ Unlocked: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Some balance was unreserved (moved from reserved to free).
+ **/
+ Unreserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * An account was upgraded.
+ **/
+ Upgraded: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
+ /**
+ * Some amount was withdrawn from the account (e.g. for transaction fees).
+ **/
+ Withdraw: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ collatorSelection: {
+ CandidateAdded: AugmentedEvent<ApiType, [accountId: AccountId32], { accountId: AccountId32 }>;
+ CandidateRemoved: AugmentedEvent<ApiType, [accountId: AccountId32], { accountId: AccountId32 }>;
+ InvulnerableAdded: AugmentedEvent<ApiType, [invulnerable: AccountId32], { invulnerable: AccountId32 }>;
+ InvulnerableRemoved: AugmentedEvent<ApiType, [invulnerable: AccountId32], { invulnerable: AccountId32 }>;
+ LicenseObtained: AugmentedEvent<ApiType, [accountId: AccountId32, deposit: u128], { accountId: AccountId32, deposit: u128 }>;
+ LicenseReleased: AugmentedEvent<ApiType, [accountId: AccountId32, depositReturned: u128], { accountId: AccountId32, depositReturned: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ common: {
+ /**
+ * Address was added to the allow list.
+ **/
+ AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Address was removed from the allow list.
+ **/
+ AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Amount pieces of token owned by `sender` was approved for `spender`.
+ **/
+ Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ /**
+ * A `sender` approves operations on all owned tokens for `spender`.
+ **/
+ ApprovedForAll: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
+ /**
+ * Collection admin was added.
+ **/
+ CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Collection admin was removed.
+ **/
+ CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * New collection was created
+ **/
+ CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;
+ /**
+ * New collection was destroyed
+ **/
+ CollectionDestroyed: AugmentedEvent<ApiType, [u32]>;
+ /**
+ * Collection limits were set.
+ **/
+ CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;
+ /**
+ * Collection owned was changed.
+ **/
+ CollectionOwnerChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;
+ /**
+ * Collection permissions were set.
+ **/
+ CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;
+ /**
+ * The property has been deleted.
+ **/
+ CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;
+ /**
+ * The colletion property has been added or edited.
+ **/
+ CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;
+ /**
+ * Collection sponsor was removed.
+ **/
+ CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;
+ /**
+ * Collection sponsor was set.
+ **/
+ CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;
+ /**
+ * New item was created.
+ **/
+ ItemCreated: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ /**
+ * Collection item was burned.
+ **/
+ ItemDestroyed: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ /**
+ * The token property permission of a collection has been set.
+ **/
+ PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;
+ /**
+ * New sponsor was confirm.
+ **/
+ SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;
+ /**
+ * The token property has been deleted.
+ **/
+ TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
+ /**
+ * The token property has been added or edited.
+ **/
+ TokenPropertySet: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
+ /**
+ * Item was transferred
+ **/
+ Transfer: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ configuration: {
+ NewCollatorKickThreshold: AugmentedEvent<ApiType, [lengthInBlocks: Option<u32>], { lengthInBlocks: Option<u32> }>;
+ NewCollatorLicenseBond: AugmentedEvent<ApiType, [bondCost: Option<u128>], { bondCost: Option<u128> }>;
+ NewDesiredCollators: AugmentedEvent<ApiType, [desiredCollators: Option<u32>], { desiredCollators: Option<u32> }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ council: {
+ /**
+ * A motion was approved by the required threshold.
+ **/
+ Approved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
+ /**
+ * A proposal was closed because its threshold was reached or after its duration was up.
+ **/
+ Closed: AugmentedEvent<ApiType, [proposalHash: H256, yes: u32, no: u32], { proposalHash: H256, yes: u32, no: u32 }>;
+ /**
+ * A motion was not approved by the required threshold.
+ **/
+ Disapproved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
+ /**
+ * A motion was executed; result will be `Ok` if it returned without error.
+ **/
+ Executed: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * A single member did some action; result will be `Ok` if it returned without error.
+ **/
+ MemberExecuted: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * A motion (given hash) has been proposed (by given account) with a threshold (given
+ * `MemberCount`).
+ **/
+ Proposed: AugmentedEvent<ApiType, [account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32], { account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32 }>;
+ /**
+ * A motion (given hash) has been voted on by given account, leaving
+ * a tally (yes votes and no votes given respectively as `MemberCount`).
+ **/
+ Voted: AugmentedEvent<ApiType, [account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32], { account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ councilMembership: {
+ /**
+ * Phantom member, never used.
+ **/
+ Dummy: AugmentedEvent<ApiType, []>;
+ /**
+ * One of the members' keys changed.
+ **/
+ KeyChanged: AugmentedEvent<ApiType, []>;
+ /**
+ * The given member was added; see the transaction for who.
+ **/
+ MemberAdded: AugmentedEvent<ApiType, []>;
+ /**
+ * The given member was removed; see the transaction for who.
+ **/
+ MemberRemoved: AugmentedEvent<ApiType, []>;
+ /**
+ * The membership was reset; see the transaction for who the new set is.
+ **/
+ MembersReset: AugmentedEvent<ApiType, []>;
+ /**
+ * Two members were swapped; see the transaction for who.
+ **/
+ MembersSwapped: AugmentedEvent<ApiType, []>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ cumulusXcm: {
+ /**
+ * Downward message executed with the given outcome.
+ * \[ id, outcome \]
+ **/
+ ExecutedDownward: AugmentedEvent<ApiType, [U8aFixed, StagingXcmV3TraitsOutcome]>;
+ /**
+ * Downward message is invalid XCM.
+ * \[ id \]
+ **/
+ InvalidFormat: AugmentedEvent<ApiType, [U8aFixed]>;
+ /**
+ * Downward message is unsupported version of XCM.
+ * \[ id \]
+ **/
+ UnsupportedVersion: AugmentedEvent<ApiType, [U8aFixed]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ democracy: {
+ /**
+ * A proposal_hash has been blacklisted permanently.
+ **/
+ Blacklisted: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
+ /**
+ * A referendum has been cancelled.
+ **/
+ Cancelled: AugmentedEvent<ApiType, [refIndex: u32], { refIndex: u32 }>;
+ /**
+ * An account has delegated their vote to another account.
+ **/
+ Delegated: AugmentedEvent<ApiType, [who: AccountId32, target: AccountId32], { who: AccountId32, target: AccountId32 }>;
+ /**
+ * An external proposal has been tabled.
+ **/
+ ExternalTabled: AugmentedEvent<ApiType, []>;
+ /**
+ * Metadata for a proposal or a referendum has been cleared.
+ **/
+ MetadataCleared: AugmentedEvent<ApiType, [owner: PalletDemocracyMetadataOwner, hash_: H256], { owner: PalletDemocracyMetadataOwner, hash_: H256 }>;
+ /**
+ * Metadata for a proposal or a referendum has been set.
+ **/
+ MetadataSet: AugmentedEvent<ApiType, [owner: PalletDemocracyMetadataOwner, hash_: H256], { owner: PalletDemocracyMetadataOwner, hash_: H256 }>;
+ /**
+ * Metadata has been transferred to new owner.
+ **/
+ MetadataTransferred: AugmentedEvent<ApiType, [prevOwner: PalletDemocracyMetadataOwner, owner: PalletDemocracyMetadataOwner, hash_: H256], { prevOwner: PalletDemocracyMetadataOwner, owner: PalletDemocracyMetadataOwner, hash_: H256 }>;
+ /**
+ * A proposal has been rejected by referendum.
+ **/
+ NotPassed: AugmentedEvent<ApiType, [refIndex: u32], { refIndex: u32 }>;
+ /**
+ * A proposal has been approved by referendum.
+ **/
+ Passed: AugmentedEvent<ApiType, [refIndex: u32], { refIndex: u32 }>;
+ /**
+ * A proposal got canceled.
+ **/
+ ProposalCanceled: AugmentedEvent<ApiType, [propIndex: u32], { propIndex: u32 }>;
+ /**
+ * A motion has been proposed by a public account.
+ **/
+ Proposed: AugmentedEvent<ApiType, [proposalIndex: u32, deposit: u128], { proposalIndex: u32, deposit: u128 }>;
+ /**
+ * An account has secconded a proposal
+ **/
+ Seconded: AugmentedEvent<ApiType, [seconder: AccountId32, propIndex: u32], { seconder: AccountId32, propIndex: u32 }>;
+ /**
+ * A referendum has begun.
+ **/
+ Started: AugmentedEvent<ApiType, [refIndex: u32, threshold: PalletDemocracyVoteThreshold], { refIndex: u32, threshold: PalletDemocracyVoteThreshold }>;
+ /**
+ * A public proposal has been tabled for referendum vote.
+ **/
+ Tabled: AugmentedEvent<ApiType, [proposalIndex: u32, deposit: u128], { proposalIndex: u32, deposit: u128 }>;
+ /**
+ * An account has cancelled a previous delegation operation.
+ **/
+ Undelegated: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;
+ /**
+ * An external proposal has been vetoed.
+ **/
+ Vetoed: AugmentedEvent<ApiType, [who: AccountId32, proposalHash: H256, until: u32], { who: AccountId32, proposalHash: H256, until: u32 }>;
+ /**
+ * An account has voted in a referendum
+ **/
+ Voted: AugmentedEvent<ApiType, [voter: AccountId32, refIndex: u32, vote: PalletDemocracyVoteAccountVote], { voter: AccountId32, refIndex: u32, vote: PalletDemocracyVoteAccountVote }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ dmpQueue: {
+ /**
+ * Downward message executed with the given outcome.
+ **/
+ ExecutedDownward: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, outcome: StagingXcmV3TraitsOutcome], { messageHash: U8aFixed, messageId: U8aFixed, outcome: StagingXcmV3TraitsOutcome }>;
+ /**
+ * Downward message is invalid XCM.
+ **/
+ InvalidFormat: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
+ /**
+ * The maximum number of downward messages was reached.
+ **/
+ MaxMessagesExhausted: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
+ /**
+ * Downward message is overweight and was placed in the overweight queue.
+ **/
+ OverweightEnqueued: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, overweightIndex: u64, requiredWeight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, overweightIndex: u64, requiredWeight: SpWeightsWeightV2Weight }>;
+ /**
+ * Downward message from the overweight queue was executed.
+ **/
+ OverweightServiced: AugmentedEvent<ApiType, [overweightIndex: u64, weightUsed: SpWeightsWeightV2Weight], { overweightIndex: u64, weightUsed: SpWeightsWeightV2Weight }>;
+ /**
+ * Downward message is unsupported version of XCM.
+ **/
+ UnsupportedVersion: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
+ /**
+ * The weight limit for handling downward messages was reached.
+ **/
+ WeightExhausted: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, remainingWeight: SpWeightsWeightV2Weight, requiredWeight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, remainingWeight: SpWeightsWeightV2Weight, requiredWeight: SpWeightsWeightV2Weight }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ ethereum: {
+ /**
+ * An ethereum transaction was successfully executed.
+ **/
+ Executed: AugmentedEvent<ApiType, [from: H160, to: H160, transactionHash: H256, exitReason: EvmCoreErrorExitReason, extraData: Bytes], { from: H160, to: H160, transactionHash: H256, exitReason: EvmCoreErrorExitReason, extraData: Bytes }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ evm: {
+ /**
+ * A contract has been created at given address.
+ **/
+ Created: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
+ /**
+ * A contract was attempted to be created, but the execution failed.
+ **/
+ CreatedFailed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
+ /**
+ * A contract has been executed successfully with states applied.
+ **/
+ Executed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
+ /**
+ * A contract has been executed with errors. States are reverted with only gas fees applied.
+ **/
+ ExecutedFailed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
+ /**
+ * Ethereum events from contracts.
+ **/
+ Log: AugmentedEvent<ApiType, [log: EthereumLog], { log: EthereumLog }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ evmContractHelpers: {
+ /**
+ * Collection sponsor was removed.
+ **/
+ ContractSponsorRemoved: AugmentedEvent<ApiType, [H160]>;
+ /**
+ * Contract sponsor was set.
+ **/
+ ContractSponsorSet: AugmentedEvent<ApiType, [H160, AccountId32]>;
+ /**
+ * New sponsor was confirm.
+ **/
+ ContractSponsorshipConfirmed: AugmentedEvent<ApiType, [H160, AccountId32]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ evmMigration: {
+ /**
+ * This event is used in benchmarking and can be used for tests
+ **/
+ TestEvent: AugmentedEvent<ApiType, []>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ fellowshipCollective: {
+ /**
+ * A member `who` has been added.
+ **/
+ MemberAdded: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
+ /**
+ * The member `who` of given `rank` has been removed from the collective.
+ **/
+ MemberRemoved: AugmentedEvent<ApiType, [who: AccountId32, rank: u16], { who: AccountId32, rank: u16 }>;
+ /**
+ * The member `who`se rank has been changed to the given `rank`.
+ **/
+ RankChanged: AugmentedEvent<ApiType, [who: AccountId32, rank: u16], { who: AccountId32, rank: u16 }>;
+ /**
+ * The member `who` has voted for the `poll` with the given `vote` leading to an updated
+ * `tally`.
+ **/
+ Voted: AugmentedEvent<ApiType, [who: AccountId32, poll: u32, vote: PalletRankedCollectiveVoteRecord, tally: PalletRankedCollectiveTally], { who: AccountId32, poll: u32, vote: PalletRankedCollectiveVoteRecord, tally: PalletRankedCollectiveTally }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ fellowshipReferenda: {
+ /**
+ * A referendum has been approved and its proposal has been scheduled.
+ **/
+ Approved: AugmentedEvent<ApiType, [index: u32], { index: u32 }>;
+ /**
+ * A referendum has been cancelled.
+ **/
+ Cancelled: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
+ ConfirmAborted: AugmentedEvent<ApiType, [index: u32], { index: u32 }>;
+ /**
+ * A referendum has ended its confirmation phase and is ready for approval.
+ **/
+ Confirmed: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
+ ConfirmStarted: AugmentedEvent<ApiType, [index: u32], { index: u32 }>;
+ /**
+ * The decision deposit has been placed.
+ **/
+ DecisionDepositPlaced: AugmentedEvent<ApiType, [index: u32, who: AccountId32, amount: u128], { index: u32, who: AccountId32, amount: u128 }>;
+ /**
+ * The decision deposit has been refunded.
+ **/
+ DecisionDepositRefunded: AugmentedEvent<ApiType, [index: u32, who: AccountId32, amount: u128], { index: u32, who: AccountId32, amount: u128 }>;
+ /**
+ * A referendum has moved into the deciding phase.
+ **/
+ DecisionStarted: AugmentedEvent<ApiType, [index: u32, track: u16, proposal: FrameSupportPreimagesBounded, tally: PalletRankedCollectiveTally], { index: u32, track: u16, proposal: FrameSupportPreimagesBounded, tally: PalletRankedCollectiveTally }>;
+ /**
+ * A deposit has been slashaed.
+ **/
+ DepositSlashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * A referendum has been killed.
+ **/
+ Killed: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
+ /**
+ * Metadata for a referendum has been cleared.
+ **/
+ MetadataCleared: AugmentedEvent<ApiType, [index: u32, hash_: H256], { index: u32, hash_: H256 }>;
+ /**
+ * Metadata for a referendum has been set.
+ **/
+ MetadataSet: AugmentedEvent<ApiType, [index: u32, hash_: H256], { index: u32, hash_: H256 }>;
+ /**
+ * A proposal has been rejected by referendum.
+ **/
+ Rejected: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
+ /**
+ * The submission deposit has been refunded.
+ **/
+ SubmissionDepositRefunded: AugmentedEvent<ApiType, [index: u32, who: AccountId32, amount: u128], { index: u32, who: AccountId32, amount: u128 }>;
+ /**
+ * A referendum has been submitted.
+ **/
+ Submitted: AugmentedEvent<ApiType, [index: u32, track: u16, proposal: FrameSupportPreimagesBounded], { index: u32, track: u16, proposal: FrameSupportPreimagesBounded }>;
+ /**
+ * A referendum has been timed out without being decided.
+ **/
+ TimedOut: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ foreignAssets: {
+ /**
+ * The asset registered.
+ **/
+ AssetRegistered: AugmentedEvent<ApiType, [assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata }>;
+ /**
+ * The asset updated.
+ **/
+ AssetUpdated: AugmentedEvent<ApiType, [assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata }>;
+ /**
+ * The foreign asset registered.
+ **/
+ ForeignAssetRegistered: AugmentedEvent<ApiType, [assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata }>;
+ /**
+ * The foreign asset updated.
+ **/
+ ForeignAssetUpdated: AugmentedEvent<ApiType, [assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ identity: {
+ /**
+ * A number of identities and associated info were forcibly inserted.
+ **/
+ IdentitiesInserted: AugmentedEvent<ApiType, [amount: u32], { amount: u32 }>;
+ /**
+ * A number of identities and all associated info were forcibly removed.
+ **/
+ IdentitiesRemoved: AugmentedEvent<ApiType, [amount: u32], { amount: u32 }>;
+ /**
+ * A name was cleared, and the given balance returned.
+ **/
+ IdentityCleared: AugmentedEvent<ApiType, [who: AccountId32, deposit: u128], { who: AccountId32, deposit: u128 }>;
+ /**
+ * A name was removed and the given balance slashed.
+ **/
+ IdentityKilled: AugmentedEvent<ApiType, [who: AccountId32, deposit: u128], { who: AccountId32, deposit: u128 }>;
+ /**
+ * A name was set or reset (which will remove all judgements).
+ **/
+ IdentitySet: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
+ /**
+ * A judgement was given by a registrar.
+ **/
+ JudgementGiven: AugmentedEvent<ApiType, [target: AccountId32, registrarIndex: u32], { target: AccountId32, registrarIndex: u32 }>;
+ /**
+ * A judgement was asked from a registrar.
+ **/
+ JudgementRequested: AugmentedEvent<ApiType, [who: AccountId32, registrarIndex: u32], { who: AccountId32, registrarIndex: u32 }>;
+ /**
+ * A judgement request was retracted.
+ **/
+ JudgementUnrequested: AugmentedEvent<ApiType, [who: AccountId32, registrarIndex: u32], { who: AccountId32, registrarIndex: u32 }>;
+ /**
+ * A registrar was added.
+ **/
+ RegistrarAdded: AugmentedEvent<ApiType, [registrarIndex: u32], { registrarIndex: u32 }>;
+ /**
+ * A number of identities were forcibly updated with new sub-identities.
+ **/
+ SubIdentitiesInserted: AugmentedEvent<ApiType, [amount: u32], { amount: u32 }>;
+ /**
+ * A sub-identity was added to an identity and the deposit paid.
+ **/
+ SubIdentityAdded: AugmentedEvent<ApiType, [sub: AccountId32, main: AccountId32, deposit: u128], { sub: AccountId32, main: AccountId32, deposit: u128 }>;
+ /**
+ * A sub-identity was removed from an identity and the deposit freed.
+ **/
+ SubIdentityRemoved: AugmentedEvent<ApiType, [sub: AccountId32, main: AccountId32, deposit: u128], { sub: AccountId32, main: AccountId32, deposit: u128 }>;
+ /**
+ * A sub-identity was cleared, and the given deposit repatriated from the
+ * main identity account to the sub-identity account.
+ **/
+ SubIdentityRevoked: AugmentedEvent<ApiType, [sub: AccountId32, main: AccountId32, deposit: u128], { sub: AccountId32, main: AccountId32, deposit: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ maintenance: {
+ MaintenanceDisabled: AugmentedEvent<ApiType, []>;
+ MaintenanceEnabled: AugmentedEvent<ApiType, []>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ parachainSystem: {
+ /**
+ * Downward messages were processed using the given weight.
+ **/
+ DownwardMessagesProcessed: AugmentedEvent<ApiType, [weightUsed: SpWeightsWeightV2Weight, dmqHead: H256], { weightUsed: SpWeightsWeightV2Weight, dmqHead: H256 }>;
+ /**
+ * Some downward messages have been received and will be processed.
+ **/
+ DownwardMessagesReceived: AugmentedEvent<ApiType, [count: u32], { count: u32 }>;
+ /**
+ * An upgrade has been authorized.
+ **/
+ UpgradeAuthorized: AugmentedEvent<ApiType, [codeHash: H256], { codeHash: H256 }>;
+ /**
+ * An upward message was sent to the relay chain.
+ **/
+ UpwardMessageSent: AugmentedEvent<ApiType, [messageHash: Option<U8aFixed>], { messageHash: Option<U8aFixed> }>;
+ /**
+ * The validation function was applied as of the contained relay chain block number.
+ **/
+ ValidationFunctionApplied: AugmentedEvent<ApiType, [relayChainBlockNum: u32], { relayChainBlockNum: u32 }>;
+ /**
+ * The relay-chain aborted the upgrade process.
+ **/
+ ValidationFunctionDiscarded: AugmentedEvent<ApiType, []>;
+ /**
+ * The validation function has been scheduled to apply.
+ **/
+ ValidationFunctionStored: AugmentedEvent<ApiType, []>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ polkadotXcm: {
+ /**
+ * Some assets have been claimed from an asset trap
+ **/
+ AssetsClaimed: AugmentedEvent<ApiType, [hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets], { hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets }>;
+ /**
+ * Some assets have been placed in an asset trap.
+ **/
+ AssetsTrapped: AugmentedEvent<ApiType, [hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets], { hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets }>;
+ /**
+ * Execution of an XCM message was attempted.
+ **/
+ Attempted: AugmentedEvent<ApiType, [outcome: StagingXcmV3TraitsOutcome], { outcome: StagingXcmV3TraitsOutcome }>;
+ /**
+ * Fees were paid from a location for an operation (often for using `SendXcm`).
+ **/
+ FeesPaid: AugmentedEvent<ApiType, [paying: StagingXcmV3MultiLocation, fees: StagingXcmV3MultiassetMultiAssets], { paying: StagingXcmV3MultiLocation, fees: StagingXcmV3MultiassetMultiAssets }>;
+ /**
+ * Expected query response has been received but the querier location of the response does
+ * not match the expected. The query remains registered for a later, valid, response to
+ * be received and acted upon.
+ **/
+ InvalidQuerier: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64, expectedQuerier: StagingXcmV3MultiLocation, maybeActualQuerier: Option<StagingXcmV3MultiLocation>], { origin: StagingXcmV3MultiLocation, queryId: u64, expectedQuerier: StagingXcmV3MultiLocation, maybeActualQuerier: Option<StagingXcmV3MultiLocation> }>;
+ /**
+ * Expected query response has been received but the expected querier location placed in
+ * storage by this runtime previously cannot be decoded. The query remains registered.
+ *
+ * This is unexpected (since a location placed in storage in a previously executing
+ * runtime should be readable prior to query timeout) and dangerous since the possibly
+ * valid response will be dropped. Manual governance intervention is probably going to be
+ * needed.
+ **/
+ InvalidQuerierVersion: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64], { origin: StagingXcmV3MultiLocation, queryId: u64 }>;
+ /**
+ * Expected query response has been received but the origin location of the response does
+ * not match that expected. The query remains registered for a later, valid, response to
+ * be received and acted upon.
+ **/
+ InvalidResponder: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64, expectedLocation: Option<StagingXcmV3MultiLocation>], { origin: StagingXcmV3MultiLocation, queryId: u64, expectedLocation: Option<StagingXcmV3MultiLocation> }>;
+ /**
+ * Expected query response has been received but the expected origin location placed in
+ * storage by this runtime previously cannot be decoded. The query remains registered.
+ *
+ * This is unexpected (since a location placed in storage in a previously executing
+ * runtime should be readable prior to query timeout) and dangerous since the possibly
+ * valid response will be dropped. Manual governance intervention is probably going to be
+ * needed.
+ **/
+ InvalidResponderVersion: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64], { origin: StagingXcmV3MultiLocation, queryId: u64 }>;
+ /**
+ * Query response has been received and query is removed. The registered notification has
+ * been dispatched and executed successfully.
+ **/
+ Notified: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8], { queryId: u64, palletIndex: u8, callIndex: u8 }>;
+ /**
+ * Query response has been received and query is removed. The dispatch was unable to be
+ * decoded into a `Call`; this might be due to dispatch function having a signature which
+ * is not `(origin, QueryId, Response)`.
+ **/
+ NotifyDecodeFailed: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8], { queryId: u64, palletIndex: u8, callIndex: u8 }>;
+ /**
+ * Query response has been received and query is removed. There was a general error with
+ * dispatching the notification call.
+ **/
+ NotifyDispatchError: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8], { queryId: u64, palletIndex: u8, callIndex: u8 }>;
+ /**
+ * Query response has been received and query is removed. The registered notification
+ * could not be dispatched because the dispatch weight is greater than the maximum weight
+ * originally budgeted by this runtime for the query result.
+ **/
+ NotifyOverweight: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8, actualWeight: SpWeightsWeightV2Weight, maxBudgetedWeight: SpWeightsWeightV2Weight], { queryId: u64, palletIndex: u8, callIndex: u8, actualWeight: SpWeightsWeightV2Weight, maxBudgetedWeight: SpWeightsWeightV2Weight }>;
+ /**
+ * A given location which had a version change subscription was dropped owing to an error
+ * migrating the location to our new XCM format.
+ **/
+ NotifyTargetMigrationFail: AugmentedEvent<ApiType, [location: StagingXcmVersionedMultiLocation, queryId: u64], { location: StagingXcmVersionedMultiLocation, queryId: u64 }>;
+ /**
+ * A given location which had a version change subscription was dropped owing to an error
+ * sending the notification to it.
+ **/
+ NotifyTargetSendFail: AugmentedEvent<ApiType, [location: StagingXcmV3MultiLocation, queryId: u64, error: StagingXcmV3TraitsError], { location: StagingXcmV3MultiLocation, queryId: u64, error: StagingXcmV3TraitsError }>;
+ /**
+ * Query response has been received and is ready for taking with `take_response`. There is
+ * no registered notification call.
+ **/
+ ResponseReady: AugmentedEvent<ApiType, [queryId: u64, response: StagingXcmV3Response], { queryId: u64, response: StagingXcmV3Response }>;
+ /**
+ * Received query response has been read and removed.
+ **/
+ ResponseTaken: AugmentedEvent<ApiType, [queryId: u64], { queryId: u64 }>;
+ /**
+ * A XCM message was sent.
+ **/
+ Sent: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, destination: StagingXcmV3MultiLocation, message: StagingXcmV3Xcm, messageId: U8aFixed], { origin: StagingXcmV3MultiLocation, destination: StagingXcmV3MultiLocation, message: StagingXcmV3Xcm, messageId: U8aFixed }>;
+ /**
+ * The supported version of a location has been changed. This might be through an
+ * automatic notification or a manual intervention.
+ **/
+ SupportedVersionChanged: AugmentedEvent<ApiType, [location: StagingXcmV3MultiLocation, version: u32], { location: StagingXcmV3MultiLocation, version: u32 }>;
+ /**
+ * Query response received which does not match a registered query. This may be because a
+ * matching query was never registered, it may be because it is a duplicate response, or
+ * because the query timed out.
+ **/
+ UnexpectedResponse: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64], { origin: StagingXcmV3MultiLocation, queryId: u64 }>;
+ /**
+ * An XCM version change notification message has been attempted to be sent.
+ *
+ * The cost of sending it (borne by the chain) is included.
+ **/
+ VersionChangeNotified: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, result: u32, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, result: u32, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
+ /**
+ * We have requested that a remote chain send us XCM version change notifications.
+ **/
+ VersionNotifyRequested: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
+ /**
+ * A remote has requested XCM version change notification from us and we have honored it.
+ * A version information message is sent to them and its cost is included.
+ **/
+ VersionNotifyStarted: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
+ /**
+ * We have requested that a remote chain stops sending us XCM version change
+ * notifications.
+ **/
+ VersionNotifyUnrequested: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ preimage: {
+ /**
+ * A preimage has ben cleared.
+ **/
+ Cleared: AugmentedEvent<ApiType, [hash_: H256], { hash_: H256 }>;
+ /**
+ * A preimage has been noted.
+ **/
+ Noted: AugmentedEvent<ApiType, [hash_: H256], { hash_: H256 }>;
+ /**
+ * A preimage has been requested.
+ **/
+ Requested: AugmentedEvent<ApiType, [hash_: H256], { hash_: H256 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ scheduler: {
+ /**
+ * The call for the provided hash was not found so the task has been aborted.
+ **/
+ CallUnavailable: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
+ /**
+ * Canceled some task.
+ **/
+ Canceled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;
+ /**
+ * Dispatched some task.
+ **/
+ Dispatched: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * The given task was unable to be renewed since the agenda is full at that block.
+ **/
+ PeriodicFailed: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
+ /**
+ * The given task can never be executed since it is overweight.
+ **/
+ PermanentlyOverweight: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
+ /**
+ * Scheduled some task.
+ **/
+ Scheduled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ session: {
+ /**
+ * New session has happened. Note that the argument is the session index, not the
+ * block number as the type might suggest.
+ **/
+ NewSession: AugmentedEvent<ApiType, [sessionIndex: u32], { sessionIndex: u32 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ stateTrieMigration: {
+ /**
+ * The auto migration task finished.
+ **/
+ AutoMigrationFinished: AugmentedEvent<ApiType, []>;
+ /**
+ * Migration got halted due to an error or miss-configuration.
+ **/
+ Halted: AugmentedEvent<ApiType, [error: PalletStateTrieMigrationError], { error: PalletStateTrieMigrationError }>;
+ /**
+ * Given number of `(top, child)` keys were migrated respectively, with the given
+ * `compute`.
+ **/
+ Migrated: AugmentedEvent<ApiType, [top: u32, child: u32, compute: PalletStateTrieMigrationMigrationCompute], { top: u32, child: u32, compute: PalletStateTrieMigrationMigrationCompute }>;
+ /**
+ * Some account got slashed by the given amount.
+ **/
+ Slashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ structure: {
+ /**
+ * Executed call on behalf of the token.
+ **/
+ Executed: AugmentedEvent<ApiType, [Result<Null, SpRuntimeDispatchError>]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ sudo: {
+ /**
+ * The \[sudoer\] just switched identity; the old key is supplied if one existed.
+ **/
+ KeyChanged: AugmentedEvent<ApiType, [oldSudoer: Option<AccountId32>], { oldSudoer: Option<AccountId32> }>;
+ /**
+ * A sudo just took place. \[result\]
+ **/
+ Sudid: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * A sudo just took place. \[result\]
+ **/
+ SudoAsDone: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ system: {
+ /**
+ * `:code` was updated.
+ **/
+ CodeUpdated: AugmentedEvent<ApiType, []>;
+ /**
+ * An extrinsic failed.
+ **/
+ ExtrinsicFailed: AugmentedEvent<ApiType, [dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportDispatchDispatchInfo], { dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportDispatchDispatchInfo }>;
+ /**
+ * An extrinsic completed successfully.
+ **/
+ ExtrinsicSuccess: AugmentedEvent<ApiType, [dispatchInfo: FrameSupportDispatchDispatchInfo], { dispatchInfo: FrameSupportDispatchDispatchInfo }>;
+ /**
+ * An account was reaped.
+ **/
+ KilledAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;
+ /**
+ * A new account was created.
+ **/
+ NewAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;
+ /**
+ * On on-chain remark happened.
+ **/
+ Remarked: AugmentedEvent<ApiType, [sender: AccountId32, hash_: H256], { sender: AccountId32, hash_: H256 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ technicalCommittee: {
+ /**
+ * A motion was approved by the required threshold.
+ **/
+ Approved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
+ /**
+ * A proposal was closed because its threshold was reached or after its duration was up.
+ **/
+ Closed: AugmentedEvent<ApiType, [proposalHash: H256, yes: u32, no: u32], { proposalHash: H256, yes: u32, no: u32 }>;
+ /**
+ * A motion was not approved by the required threshold.
+ **/
+ Disapproved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
+ /**
+ * A motion was executed; result will be `Ok` if it returned without error.
+ **/
+ Executed: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * A single member did some action; result will be `Ok` if it returned without error.
+ **/
+ MemberExecuted: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * A motion (given hash) has been proposed (by given account) with a threshold (given
+ * `MemberCount`).
+ **/
+ Proposed: AugmentedEvent<ApiType, [account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32], { account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32 }>;
+ /**
+ * A motion (given hash) has been voted on by given account, leaving
+ * a tally (yes votes and no votes given respectively as `MemberCount`).
+ **/
+ Voted: AugmentedEvent<ApiType, [account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32], { account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ technicalCommitteeMembership: {
+ /**
+ * Phantom member, never used.
+ **/
+ Dummy: AugmentedEvent<ApiType, []>;
+ /**
+ * One of the members' keys changed.
+ **/
+ KeyChanged: AugmentedEvent<ApiType, []>;
+ /**
+ * The given member was added; see the transaction for who.
+ **/
+ MemberAdded: AugmentedEvent<ApiType, []>;
+ /**
+ * The given member was removed; see the transaction for who.
+ **/
+ MemberRemoved: AugmentedEvent<ApiType, []>;
+ /**
+ * The membership was reset; see the transaction for who the new set is.
+ **/
+ MembersReset: AugmentedEvent<ApiType, []>;
+ /**
+ * Two members were swapped; see the transaction for who.
+ **/
+ MembersSwapped: AugmentedEvent<ApiType, []>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ testUtils: {
+ BatchCompleted: AugmentedEvent<ApiType, []>;
+ ShouldRollback: AugmentedEvent<ApiType, []>;
+ ValueIsSet: AugmentedEvent<ApiType, []>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ tokens: {
+ /**
+ * A balance was set by root.
+ **/
+ BalanceSet: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, free: u128, reserved: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, free: u128, reserved: u128 }>;
+ /**
+ * Deposited some balance into an account
+ **/
+ Deposited: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * An account was removed whose balance was non-zero but below
+ * ExistentialDeposit, resulting in an outright loss.
+ **/
+ DustLost: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * An account was created with some free balance.
+ **/
+ Endowed: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ Issued: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, amount: u128], { currencyId: PalletForeignAssetsAssetId, amount: u128 }>;
+ /**
+ * Some free balance was locked.
+ **/
+ Locked: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * Some locked funds were unlocked
+ **/
+ LockRemoved: AugmentedEvent<ApiType, [lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32], { lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32 }>;
+ /**
+ * Some funds are locked
+ **/
+ LockSet: AugmentedEvent<ApiType, [lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ Rescinded: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, amount: u128], { currencyId: PalletForeignAssetsAssetId, amount: u128 }>;
+ /**
+ * Some balance was reserved (moved from free to reserved).
+ **/
+ Reserved: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * Some reserved balance was repatriated (moved from reserved to
+ * another account).
+ **/
+ ReserveRepatriated: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128, status: FrameSupportTokensMiscBalanceStatus], { currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128, status: FrameSupportTokensMiscBalanceStatus }>;
+ /**
+ * Some balances were slashed (e.g. due to mis-behavior)
+ **/
+ Slashed: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, freeAmount: u128, reservedAmount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, freeAmount: u128, reservedAmount: u128 }>;
+ /**
+ * The total issuance of an currency has been set
+ **/
+ TotalIssuanceSet: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, amount: u128], { currencyId: PalletForeignAssetsAssetId, amount: u128 }>;
+ /**
+ * Transfer succeeded.
+ **/
+ Transfer: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128 }>;
+ /**
+ * Some locked balance was freed.
+ **/
+ Unlocked: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * Some balance was unreserved (moved from reserved to free).
+ **/
+ Unreserved: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * Some balances were withdrawn (e.g. pay for transaction fee)
+ **/
+ Withdrawn: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ transactionPayment: {
+ /**
+ * A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,
+ * has been paid by `who`.
+ **/
+ TransactionFeePaid: AugmentedEvent<ApiType, [who: AccountId32, actualFee: u128, tip: u128], { who: AccountId32, actualFee: u128, tip: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ treasury: {
+ /**
+ * Some funds have been allocated.
+ **/
+ Awarded: AugmentedEvent<ApiType, [proposalIndex: u32, award: u128, account: AccountId32], { proposalIndex: u32, award: u128, account: AccountId32 }>;
+ /**
+ * Some of our funds have been burnt.
+ **/
+ Burnt: AugmentedEvent<ApiType, [burntFunds: u128], { burntFunds: u128 }>;
+ /**
+ * Some funds have been deposited.
+ **/
+ Deposit: AugmentedEvent<ApiType, [value: u128], { value: u128 }>;
+ /**
+ * New proposal.
+ **/
+ Proposed: AugmentedEvent<ApiType, [proposalIndex: u32], { proposalIndex: u32 }>;
+ /**
+ * A proposal was rejected; funds were slashed.
+ **/
+ Rejected: AugmentedEvent<ApiType, [proposalIndex: u32, slashed: u128], { proposalIndex: u32, slashed: u128 }>;
+ /**
+ * Spending has finished; this is the amount that rolls over until next spend.
+ **/
+ Rollover: AugmentedEvent<ApiType, [rolloverBalance: u128], { rolloverBalance: u128 }>;
+ /**
+ * A new spend proposal has been approved.
+ **/
+ SpendApproved: AugmentedEvent<ApiType, [proposalIndex: u32, amount: u128, beneficiary: AccountId32], { proposalIndex: u32, amount: u128, beneficiary: AccountId32 }>;
+ /**
+ * We have ended a spend period and will now allocate funds.
+ **/
+ Spending: AugmentedEvent<ApiType, [budgetRemaining: u128], { budgetRemaining: u128 }>;
+ /**
+ * The inactive funds of the pallet have been updated.
+ **/
+ UpdatedInactive: AugmentedEvent<ApiType, [reactivated: u128, deactivated: u128], { reactivated: u128, deactivated: u128 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ utility: {
+ /**
+ * Batch of dispatches completed fully with no error.
+ **/
+ BatchCompleted: AugmentedEvent<ApiType, []>;
+ /**
+ * Batch of dispatches completed but has errors.
+ **/
+ BatchCompletedWithErrors: AugmentedEvent<ApiType, []>;
+ /**
+ * Batch of dispatches did not complete fully. Index of first failing dispatch given, as
+ * well as the error.
+ **/
+ BatchInterrupted: AugmentedEvent<ApiType, [index: u32, error: SpRuntimeDispatchError], { index: u32, error: SpRuntimeDispatchError }>;
+ /**
+ * A call was dispatched.
+ **/
+ DispatchedAs: AugmentedEvent<ApiType, [result: Result<Null, SpRuntimeDispatchError>], { result: Result<Null, SpRuntimeDispatchError> }>;
+ /**
+ * A single item within a Batch of dispatches has completed with no error.
+ **/
+ ItemCompleted: AugmentedEvent<ApiType, []>;
+ /**
+ * A single item within a Batch of dispatches has completed with error.
+ **/
+ ItemFailed: AugmentedEvent<ApiType, [error: SpRuntimeDispatchError], { error: SpRuntimeDispatchError }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ vesting: {
+ /**
+ * Claimed vesting.
+ **/
+ Claimed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
+ /**
+ * Added new vesting schedule.
+ **/
+ VestingScheduleAdded: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule], { from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule }>;
+ /**
+ * Updated vesting schedules.
+ **/
+ VestingSchedulesUpdated: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ xcmpQueue: {
+ /**
+ * Bad XCM format used.
+ **/
+ BadFormat: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
+ /**
+ * Bad XCM version used.
+ **/
+ BadVersion: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
+ /**
+ * Some XCM failed.
+ **/
+ Fail: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, error: StagingXcmV3TraitsError, weight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, error: StagingXcmV3TraitsError, weight: SpWeightsWeightV2Weight }>;
+ /**
+ * An XCM exceeded the individual message weight budget.
+ **/
+ OverweightEnqueued: AugmentedEvent<ApiType, [sender: u32, sentAt: u32, index: u64, required: SpWeightsWeightV2Weight], { sender: u32, sentAt: u32, index: u64, required: SpWeightsWeightV2Weight }>;
+ /**
+ * An XCM from the overweight queue was executed with the given actual weight used.
+ **/
+ OverweightServiced: AugmentedEvent<ApiType, [index: u64, used: SpWeightsWeightV2Weight], { index: u64, used: SpWeightsWeightV2Weight }>;
+ /**
+ * Some XCM was executed ok.
+ **/
+ Success: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, weight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, weight: SpWeightsWeightV2Weight }>;
+ /**
+ * An HRMP message was sent to a sibling parachain.
+ **/
+ XcmpMessageSent: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ xTokens: {
+ /**
+ * Transferred `MultiAsset` with fee.
+ **/
+ TransferredMultiAssets: AugmentedEvent<ApiType, [sender: AccountId32, assets: StagingXcmV3MultiassetMultiAssets, fee: StagingXcmV3MultiAsset, dest: StagingXcmV3MultiLocation], { sender: AccountId32, assets: StagingXcmV3MultiassetMultiAssets, fee: StagingXcmV3MultiAsset, dest: StagingXcmV3MultiLocation }>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
+ } // AugmentedEvents
+} // declare module
js-packages/types/augment-api-query.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-query.ts
@@ -0,0 +1,1442 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/api-base/types/storage';
+
+import type { ApiTypes, AugmentedQuery, QueryableStorageEntry } from '@polkadot/api-base/types';
+import type { Data } from '@polkadot/types';
+import type { BTreeMap, Bytes, Option, Struct, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
+import type { AccountId32, Call, H160, H256 } from '@polkadot/types/interfaces/runtime';
+import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCodeUpgradeAuthorization, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletParachainSystemUnincludedSegmentAncestor, CumulusPalletParachainSystemUnincludedSegmentSegmentTracker, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportDispatchPerDispatchClassWeight, FrameSupportPreimagesBounded, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OpalRuntimeRuntimeCommonSessionKeys, OpalRuntimeRuntimeHoldReason, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensReserveData, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesIdAmount, PalletBalancesReserveData, PalletCollectiveVotes, PalletConfigurationAppPromotionConfiguration, PalletDemocracyMetadataOwner, PalletDemocracyReferendumInfo, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCodeMetadata, PalletEvmContractHelpersSponsoringModeT, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletNonfungibleItemData, PalletPreimageRequestStatus, PalletRankedCollectiveMemberRecord, PalletRankedCollectiveVoteRecord, PalletReferendaReferendumInfo, PalletSchedulerScheduled, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletTransactionPaymentReleases, PalletTreasuryProposal, PalletXcmQueryStatus, PalletXcmRemoteLockedFungibleRecord, PalletXcmVersionMigrationStage, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV5AbridgedHostConfiguration, PolkadotPrimitivesV5PersistedValidationData, PolkadotPrimitivesV5UpgradeGoAhead, PolkadotPrimitivesV5UpgradeRestriction, SpConsensusAuraSr25519AppSr25519Public, SpCoreCryptoKeyTypeId, SpRuntimeDigest, SpTrieStorageProof, SpWeightsWeightV2Weight, StagingXcmV3MultiLocation, StagingXcmVersionedAssetId, StagingXcmVersionedMultiLocation, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild } from '@polkadot/types/lookup';
+import type { Observable } from '@polkadot/types/types';
+
+export type __AugmentedQuery<ApiType extends ApiTypes> = AugmentedQuery<ApiType, () => unknown>;
+export type __QueryableStorageEntry<ApiType extends ApiTypes> = QueryableStorageEntry<ApiType>;
+
+declare module '@polkadot/api-base/types/storage' {
+ interface AugmentedQueries<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * Stores the `admin` account. Some extrinsics can only be executed if they were signed by `admin`.
+ **/
+ admin: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Pending unstake records for an `Account`.
+ *
+ * * **Key** - Staker account.
+ * * **Value** - Amount of stakes.
+ **/
+ pendingUnstake: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[AccountId32, u128]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Stores a key for record for which the revenue recalculation was performed.
+ * If `None`, then recalculation has not yet been performed or calculations have been completed for all stakers.
+ **/
+ previousCalculatedRecord: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[AccountId32, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Stores the amount of tokens staked by account in the blocknumber.
+ *
+ * * **Key1** - Staker account.
+ * * **Key2** - Relay block number when the stake was made.
+ * * **(Balance, BlockNumber)** - Balance of the stake.
+ * The number of the relay block in which we must perform the interest recalculation
+ **/
+ staked: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<ITuple<[u128, u32]>>, [AccountId32, u32]> & QueryableStorageEntry<ApiType, [AccountId32, u32]>;
+ /**
+ * Stores number of stake records for an `Account`.
+ *
+ * * **Key** - Staker account.
+ * * **Value** - Amount of stakes.
+ **/
+ stakesPerAccount: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u8>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Stores the total staked amount.
+ **/
+ totalStaked: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ aura: {
+ /**
+ * The current authority set.
+ **/
+ authorities: AugmentedQuery<ApiType, () => Observable<Vec<SpConsensusAuraSr25519AppSr25519Public>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current slot of this block.
+ *
+ * This will be set in `on_initialize`.
+ **/
+ currentSlot: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ auraExt: {
+ /**
+ * Serves as cache for the authorities.
+ *
+ * The authorities in AuRa are overwritten in `on_initialize` when we switch to a new session,
+ * but we require the old authorities to verify the seal when validating a PoV. This will
+ * always be updated to the latest AuRa authorities in `on_finalize`.
+ **/
+ authorities: AugmentedQuery<ApiType, () => Observable<Vec<SpConsensusAuraSr25519AppSr25519Public>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Current slot paired with a number of authored blocks.
+ *
+ * Updated on each block initialization.
+ **/
+ slotInfo: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[u64, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ authorship: {
+ /**
+ * Author of current block.
+ **/
+ author: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ balances: {
+ /**
+ * The Balances pallet example of storing the balance of an account.
+ *
+ * # Example
+ *
+ * ```nocompile
+ * impl pallet_balances::Config for Runtime {
+ * type AccountStore = StorageMapShim<Self::Account<Runtime>, frame_system::Provider<Runtime>, AccountId, Self::AccountData<Balance>>
+ * }
+ * ```
+ *
+ * You can also store the balance of an account in the `System` pallet.
+ *
+ * # Example
+ *
+ * ```nocompile
+ * impl pallet_balances::Config for Runtime {
+ * type AccountStore = System
+ * }
+ * ```
+ *
+ * But this comes with tradeoffs, storing account balances in the system pallet stores
+ * `frame_system` data alongside the account data contrary to storing account balances in the
+ * `Balances` pallet, which uses a `StorageMap` to store balances data only.
+ * NOTE: This is only used in the case that this pallet is used to store balances.
+ **/
+ account: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<PalletBalancesAccountData>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Freeze locks on account balances.
+ **/
+ freezes: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<PalletBalancesIdAmount>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Holds on account balances.
+ **/
+ holds: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<{
+ readonly id: OpalRuntimeRuntimeHoldReason;
+ readonly amount: u128;
+ } & Struct>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * The total units of outstanding deactivated balance in the system.
+ **/
+ inactiveIssuance: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Any liquidity locks on some account balances.
+ * NOTE: Should only be accessed when setting, changing and freeing a lock.
+ **/
+ locks: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<PalletBalancesBalanceLock>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Named reserves on some account balances.
+ **/
+ reserves: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<PalletBalancesReserveData>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * The total units issued in the system.
+ **/
+ totalIssuance: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ collatorSelection: {
+ /**
+ * The (community, limited) collation candidates.
+ **/
+ candidates: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The invulnerable, fixed collators.
+ **/
+ invulnerables: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Last block authored by collator.
+ **/
+ lastAuthoredBlock: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u32>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * The (community) collation license holders.
+ **/
+ licenseDepositOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u128>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ common: {
+ /**
+ * Storage of the amount of collection admins.
+ **/
+ adminAmount: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Allowlisted collection users.
+ **/
+ allowlist: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Storage of collection info.
+ **/
+ collectionById: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsCollection>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Storage of collection properties.
+ **/
+ collectionProperties: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Storage of token property permissions of a collection.
+ **/
+ collectionPropertyPermissions: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsPropertiesMapPropertyPermission>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Storage of the count of created collections. Essentially contains the last collection ID.
+ **/
+ createdCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Storage of the count of deleted collections.
+ **/
+ destroyedCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Not used by code, exists only to provide some types to metadata.
+ **/
+ dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, UpDataStructsTokenChild, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * List of collection admins.
+ **/
+ isAdmin: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ configuration: {
+ appPromomotionConfigurationOverride: AugmentedQuery<ApiType, () => Observable<PalletConfigurationAppPromotionConfiguration>, []> & QueryableStorageEntry<ApiType, []>;
+ collatorSelectionDesiredCollatorsOverride: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ collatorSelectionKickThresholdOverride: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ collatorSelectionLicenseBondOverride: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ minGasPriceOverride: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ weightToFeeCoefficientOverride: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ council: {
+ /**
+ * The current members of the collective. This is stored sorted (just by value).
+ **/
+ members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The prime member that helps determine the default vote behavior in case of absentations.
+ **/
+ prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Proposals so far.
+ **/
+ proposalCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Actual proposal for a given hash, if it's current.
+ **/
+ proposalOf: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<Call>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * The hashes of the active proposals.
+ **/
+ proposals: AugmentedQuery<ApiType, () => Observable<Vec<H256>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Votes on a given proposal, if it is ongoing.
+ **/
+ voting: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<PalletCollectiveVotes>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ councilMembership: {
+ /**
+ * The current membership, stored as an ordered Vec.
+ **/
+ members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current prime member, if one exists.
+ **/
+ prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ democracy: {
+ /**
+ * A record of who vetoed what. Maps proposal hash to a possible existent block number
+ * (until when it may not be resubmitted) and who vetoed it.
+ **/
+ blacklist: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<ITuple<[u32, Vec<AccountId32>]>>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * Record of all proposals that have been subject to emergency cancellation.
+ **/
+ cancellations: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<bool>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * Those who have locked a deposit.
+ *
+ * TWOX-NOTE: Safe, as increasing integer keys are safe.
+ **/
+ depositOf: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<ITuple<[Vec<AccountId32>, u128]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * True if the last referendum tabled was submitted externally. False if it was a public
+ * proposal.
+ **/
+ lastTabledWasExternal: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The lowest referendum index representing an unbaked referendum. Equal to
+ * `ReferendumCount` if there isn't a unbaked referendum.
+ **/
+ lowestUnbaked: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * General information concerning any proposal or referendum.
+ * The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON
+ * dump or IPFS hash of a JSON file.
+ *
+ * Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove)
+ * large preimages.
+ **/
+ metadataOf: AugmentedQuery<ApiType, (arg: PalletDemocracyMetadataOwner | { External: any } | { Proposal: any } | { Referendum: any } | string | Uint8Array) => Observable<Option<H256>>, [PalletDemocracyMetadataOwner]> & QueryableStorageEntry<ApiType, [PalletDemocracyMetadataOwner]>;
+ /**
+ * The referendum to be tabled whenever it would be valid to table an external proposal.
+ * This happens when a referendum needs to be tabled and one of two conditions are met:
+ * - `LastTabledWasExternal` is `false`; or
+ * - `PublicProps` is empty.
+ **/
+ nextExternal: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[FrameSupportPreimagesBounded, PalletDemocracyVoteThreshold]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The number of (public) proposals that have been made so far.
+ **/
+ publicPropCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The public proposals. Unsorted. The second item is the proposal.
+ **/
+ publicProps: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[u32, FrameSupportPreimagesBounded, AccountId32]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The next free referendum index, aka the number of referenda started so far.
+ **/
+ referendumCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Information concerning any given referendum.
+ *
+ * TWOX-NOTE: SAFE as indexes are not under an attacker’s control.
+ **/
+ referendumInfoOf: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletDemocracyReferendumInfo>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * All votes for a particular voter. We store the balance for the number of votes that we
+ * have recorded. The second item is the total amount of delegations, that will be added.
+ *
+ * TWOX-NOTE: SAFE as `AccountId`s are crypto hashes anyway.
+ **/
+ votingOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<PalletDemocracyVoteVoting>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ dmpQueue: {
+ /**
+ * The configuration.
+ **/
+ configuration: AugmentedQuery<ApiType, () => Observable<CumulusPalletDmpQueueConfigData>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Counter for the related counted storage map
+ **/
+ counterForOverweight: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The overweight messages.
+ **/
+ overweight: AugmentedQuery<ApiType, (arg: u64 | AnyNumber | Uint8Array) => Observable<Option<ITuple<[u32, Bytes]>>>, [u64]> & QueryableStorageEntry<ApiType, [u64]>;
+ /**
+ * The page index.
+ **/
+ pageIndex: AugmentedQuery<ApiType, () => Observable<CumulusPalletDmpQueuePageIndexData>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The queue pages.
+ **/
+ pages: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[u32, Bytes]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ ethereum: {
+ blockHash: AugmentedQuery<ApiType, (arg: U256 | AnyNumber | Uint8Array) => Observable<H256>, [U256]> & QueryableStorageEntry<ApiType, [U256]>;
+ /**
+ * The current Ethereum block.
+ **/
+ currentBlock: AugmentedQuery<ApiType, () => Observable<Option<EthereumBlock>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current Ethereum receipts.
+ **/
+ currentReceipts: AugmentedQuery<ApiType, () => Observable<Option<Vec<EthereumReceiptReceiptV3>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current transaction statuses.
+ **/
+ currentTransactionStatuses: AugmentedQuery<ApiType, () => Observable<Option<Vec<FpRpcTransactionStatus>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Injected transactions should have unique nonce, here we store current
+ **/
+ injectedNonce: AugmentedQuery<ApiType, () => Observable<U256>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Current building block's transactions and receipts.
+ **/
+ pending: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[EthereumTransactionTransactionV2, FpRpcTransactionStatus, EthereumReceiptReceiptV3]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ evm: {
+ accountCodes: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Bytes>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ accountCodesMetadata: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Option<PalletEvmCodeMetadata>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ accountStorages: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H256 | string | Uint8Array) => Observable<H256>, [H160, H256]> & QueryableStorageEntry<ApiType, [H160, H256]>;
+ /**
+ * Written on log, reset after transaction
+ * Should be empty between transactions
+ **/
+ currentLogs: AugmentedQuery<ApiType, () => Observable<Vec<EthereumLog>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ evmContractHelpers: {
+ /**
+ * Storage for users that allowed for sponsorship.
+ *
+ * ### Usage
+ * Prefer to delete record from storage if user no more allowed for sponsorship.
+ *
+ * * **Key1** - contract address.
+ * * **Key2** - user that allowed for sponsorship.
+ * * **Value** - allowance for sponsorship.
+ **/
+ allowlist: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H160 | string | Uint8Array) => Observable<bool>, [H160, H160]> & QueryableStorageEntry<ApiType, [H160, H160]>;
+ /**
+ * Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.
+ *
+ * ### Usage
+ * Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.
+ *
+ * * **Key** - contract address.
+ * * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.
+ **/
+ allowlistEnabled: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Store owner for contract.
+ *
+ * * **Key** - contract address.
+ * * **Value** - owner for contract.
+ **/
+ owner: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<H160>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Deprecated: this storage is deprecated
+ **/
+ selfSponsoring: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ sponsorBasket: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H160 | string | Uint8Array) => Observable<Option<u32>>, [H160, H160]> & QueryableStorageEntry<ApiType, [H160, H160]>;
+ /**
+ * Store for contract sponsorship state.
+ *
+ * * **Key** - contract address.
+ * * **Value** - sponsorship state.
+ **/
+ sponsoring: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<UpDataStructsSponsorshipStateBasicCrossAccountIdRepr>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Storage for last sponsored block.
+ *
+ * * **Key1** - contract address.
+ * * **Key2** - sponsored user address.
+ * * **Value** - last sponsored block number.
+ **/
+ sponsoringFeeLimit: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<BTreeMap<u32, U256>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Store for sponsoring mode.
+ *
+ * ### Usage
+ * Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).
+ *
+ * * **Key** - contract address.
+ * * **Value** - [`sponsoring mode`](SponsoringModeT).
+ **/
+ sponsoringMode: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Option<PalletEvmContractHelpersSponsoringModeT>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Storage for sponsoring rate limit in blocks.
+ *
+ * * **Key** - contract address.
+ * * **Value** - amount of sponsored blocks.
+ **/
+ sponsoringRateLimit: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<u32>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ evmMigration: {
+ migrationPending: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ fellowshipCollective: {
+ /**
+ * The index of each ranks's member into the group of members who have at least that rank.
+ **/
+ idToIndex: AugmentedQuery<ApiType, (arg1: u16 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u16, AccountId32]> & QueryableStorageEntry<ApiType, [u16, AccountId32]>;
+ /**
+ * The members in the collective by index. All indices in the range `0..MemberCount` will
+ * return `Some`, however a member's index is not guaranteed to remain unchanged over time.
+ **/
+ indexToId: AugmentedQuery<ApiType, (arg1: u16 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<AccountId32>>, [u16, u32]> & QueryableStorageEntry<ApiType, [u16, u32]>;
+ /**
+ * The number of members in the collective who have at least the rank according to the index
+ * of the vec.
+ **/
+ memberCount: AugmentedQuery<ApiType, (arg: u16 | AnyNumber | Uint8Array) => Observable<u32>, [u16]> & QueryableStorageEntry<ApiType, [u16]>;
+ /**
+ * The current members of the collective.
+ **/
+ members: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<PalletRankedCollectiveMemberRecord>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Votes on a given proposal, if it is ongoing.
+ **/
+ voting: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<PalletRankedCollectiveVoteRecord>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
+ votingCleanup: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<Bytes>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ fellowshipReferenda: {
+ /**
+ * The number of referenda being decided currently.
+ **/
+ decidingCount: AugmentedQuery<ApiType, (arg: u16 | AnyNumber | Uint8Array) => Observable<u32>, [u16]> & QueryableStorageEntry<ApiType, [u16]>;
+ /**
+ * The metadata is a general information concerning the referendum.
+ * The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON
+ * dump or IPFS hash of a JSON file.
+ *
+ * Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove)
+ * large preimages.
+ **/
+ metadataOf: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<H256>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * The next free referendum index, aka the number of referenda started so far.
+ **/
+ referendumCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Information concerning any given referendum.
+ **/
+ referendumInfoFor: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletReferendaReferendumInfo>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * The sorted list of referenda ready to be decided but not yet being decided, ordered by
+ * conviction-weighted approvals.
+ *
+ * This should be empty if `DecidingCount` is less than `TrackInfo::max_deciding`.
+ **/
+ trackQueue: AugmentedQuery<ApiType, (arg: u16 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[u32, u32]>>>, [u16]> & QueryableStorageEntry<ApiType, [u16]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ foreignAssets: {
+ /**
+ * The storages for assets to fungible collection binding
+ *
+ **/
+ assetBinding: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * The storages for AssetMetadatas.
+ *
+ * AssetMetadatas: map AssetIds => Option<AssetMetadata>
+ **/
+ assetMetadatas: AugmentedQuery<ApiType, (arg: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<Option<PalletForeignAssetsModuleAssetMetadata>>, [PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [PalletForeignAssetsAssetId]>;
+ /**
+ * The storages for MultiLocations.
+ *
+ * ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>
+ **/
+ foreignAssetLocations: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<StagingXcmV3MultiLocation>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * The storages for CurrencyIds.
+ *
+ * LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>
+ **/
+ locationToCurrencyIds: AugmentedQuery<ApiType, (arg: StagingXcmV3MultiLocation | { parents?: any; interior?: any } | string | Uint8Array) => Observable<Option<u32>>, [StagingXcmV3MultiLocation]> & QueryableStorageEntry<ApiType, [StagingXcmV3MultiLocation]>;
+ /**
+ * Next available Foreign AssetId ID.
+ *
+ * NextForeignAssetId: ForeignAssetId
+ **/
+ nextForeignAssetId: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ fungible: {
+ /**
+ * Storage for assets delegated to a limited extent to other users.
+ **/
+ allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Amount of tokens owned by an account inside a collection.
+ **/
+ balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Total amount of fungible tokens inside a collection.
+ **/
+ totalSupply: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ identity: {
+ /**
+ * Information that is pertinent to identify the entity behind an account.
+ *
+ * TWOX-NOTE: OK ― `AccountId` is a secure hash.
+ **/
+ identityOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<PalletIdentityRegistration>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * The set of registrars. Not expected to get very big as can only be added through a
+ * special origin (likely a council motion).
+ *
+ * The index into this can be cast to `RegistrarIndex` to get a valid value.
+ **/
+ registrars: AugmentedQuery<ApiType, () => Observable<Vec<Option<PalletIdentityRegistrarInfo>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Alternative "sub" identities of this account.
+ *
+ * The first item is the deposit, the second is a vector of the accounts.
+ *
+ * TWOX-NOTE: OK ― `AccountId` is a secure hash.
+ **/
+ subsOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<ITuple<[u128, Vec<AccountId32>]>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * The super-identity of an alternative "sub" identity together with its name, within that
+ * context. If the account is not some other account's sub-identity, then just `None`.
+ **/
+ superOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<ITuple<[AccountId32, Data]>>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ inflation: {
+ /**
+ * Current inflation for `InflationBlockInterval` number of blocks
+ **/
+ blockInflation: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Next target (relay) block when inflation will be applied
+ **/
+ nextInflationBlock: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Next target (relay) block when inflation is recalculated
+ **/
+ nextRecalculationBlock: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Relay block when inflation has started
+ **/
+ startBlock: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * starting year total issuance
+ **/
+ startingYearTotalIssuance: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ maintenance: {
+ enabled: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ nonfungible: {
+ /**
+ * Amount of tokens owned by an account in a collection.
+ **/
+ accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Allowance set by a token owner for another user to perform one of certain transactions on a token.
+ **/
+ allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
+ **/
+ collectionAllowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Used to enumerate tokens owned by account.
+ **/
+ owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
+ /**
+ * Custom data of a token that is serialized to bytes,
+ * primarily reserved for on-chain operations,
+ * normally obscured from the external users.
+ *
+ * Auxiliary properties are slightly different from
+ * usual [`TokenProperties`] due to an unlimited number
+ * and separately stored and written-to key-value pairs.
+ *
+ * Currently unused.
+ **/
+ tokenAuxProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: UpDataStructsPropertyScope | 'None' | 'Rmrk' | number | Uint8Array, arg4: Bytes | string | Uint8Array) => Observable<Option<Bytes>>, [u32, u32, UpDataStructsPropertyScope, Bytes]> & QueryableStorageEntry<ApiType, [u32, u32, UpDataStructsPropertyScope, Bytes]>;
+ /**
+ * Used to enumerate token's children.
+ **/
+ tokenChildren: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array]) => Observable<bool>, [u32, u32, ITuple<[u32, u32]>]> & QueryableStorageEntry<ApiType, [u32, u32, ITuple<[u32, u32]>]>;
+ /**
+ * Token data, used to partially describe a token.
+ **/
+ tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletNonfungibleItemData>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Map of key-value pairs, describing the metadata of a token.
+ **/
+ tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsProperties>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Amount of burnt tokens in a collection.
+ **/
+ tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Total amount of minted tokens in a collection.
+ **/
+ tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ parachainInfo: {
+ parachainId: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ parachainSystem: {
+ /**
+ * Storage field that keeps track of bandwidth used by the unincluded segment along with the
+ * latest the latest HRMP watermark. Used for limiting the acceptance of new blocks with
+ * respect to relay chain constraints.
+ **/
+ aggregatedUnincludedSegment: AugmentedQuery<ApiType, () => Observable<Option<CumulusPalletParachainSystemUnincludedSegmentSegmentTracker>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The number of HRMP messages we observed in `on_initialize` and thus used that number for
+ * announcing the weight of `on_initialize` and `on_finalize`.
+ **/
+ announcedHrmpMessagesPerCandidate: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The next authorized upgrade, if there is one.
+ **/
+ authorizedUpgrade: AugmentedQuery<ApiType, () => Observable<Option<CumulusPalletParachainSystemCodeUpgradeAuthorization>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * A custom head data that should be returned as result of `validate_block`.
+ *
+ * See `Pallet::set_custom_validation_head_data` for more information.
+ **/
+ customValidationHeadData: AugmentedQuery<ApiType, () => Observable<Option<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Were the validation data set to notify the relay chain?
+ **/
+ didSetValidationCode: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The parachain host configuration that was obtained from the relay parent.
+ *
+ * This field is meant to be updated each block with the validation data inherent. Therefore,
+ * before processing of the inherent, e.g. in `on_initialize` this data may be stale.
+ *
+ * This data is also absent from the genesis.
+ **/
+ hostConfiguration: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5AbridgedHostConfiguration>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * HRMP messages that were sent in a block.
+ *
+ * This will be cleared in `on_initialize` of each new block.
+ **/
+ hrmpOutboundMessages: AugmentedQuery<ApiType, () => Observable<Vec<PolkadotCorePrimitivesOutboundHrmpMessage>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * HRMP watermark that was set in a block.
+ *
+ * This will be cleared in `on_initialize` of each new block.
+ **/
+ hrmpWatermark: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The last downward message queue chain head we have observed.
+ *
+ * This value is loaded before and saved after processing inbound downward messages carried
+ * by the system inherent.
+ **/
+ lastDmqMqcHead: AugmentedQuery<ApiType, () => Observable<H256>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The message queue chain heads we have observed per each channel incoming channel.
+ *
+ * This value is loaded before and saved after processing inbound downward messages carried
+ * by the system inherent.
+ **/
+ lastHrmpMqcHeads: AugmentedQuery<ApiType, () => Observable<BTreeMap<u32, H256>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The relay chain block number associated with the last parachain block.
+ **/
+ lastRelayChainBlockNumber: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Validation code that is set by the parachain and is to be communicated to collator and
+ * consequently the relay-chain.
+ *
+ * This will be cleared in `on_initialize` of each new block if no other pallet already set
+ * the value.
+ **/
+ newValidationCode: AugmentedQuery<ApiType, () => Observable<Option<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Upward messages that are still pending and not yet send to the relay chain.
+ **/
+ pendingUpwardMessages: AugmentedQuery<ApiType, () => Observable<Vec<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * In case of a scheduled upgrade, this storage field contains the validation code to be
+ * applied.
+ *
+ * As soon as the relay chain gives us the go-ahead signal, we will overwrite the
+ * [`:code`][sp_core::storage::well_known_keys::CODE] which will result the next block process
+ * with the new validation code. This concludes the upgrade process.
+ **/
+ pendingValidationCode: AugmentedQuery<ApiType, () => Observable<Bytes>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Number of downward messages processed in a block.
+ *
+ * This will be cleared in `on_initialize` of each new block.
+ **/
+ processedDownwardMessages: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The state proof for the last relay parent block.
+ *
+ * This field is meant to be updated each block with the validation data inherent. Therefore,
+ * before processing of the inherent, e.g. in `on_initialize` this data may be stale.
+ *
+ * This data is also absent from the genesis.
+ **/
+ relayStateProof: AugmentedQuery<ApiType, () => Observable<Option<SpTrieStorageProof>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The snapshot of some state related to messaging relevant to the current parachain as per
+ * the relay parent.
+ *
+ * This field is meant to be updated each block with the validation data inherent. Therefore,
+ * before processing of the inherent, e.g. in `on_initialize` this data may be stale.
+ *
+ * This data is also absent from the genesis.
+ **/
+ relevantMessagingState: AugmentedQuery<ApiType, () => Observable<Option<CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The weight we reserve at the beginning of the block for processing DMP messages. This
+ * overrides the amount set in the Config trait.
+ **/
+ reservedDmpWeightOverride: AugmentedQuery<ApiType, () => Observable<Option<SpWeightsWeightV2Weight>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The weight we reserve at the beginning of the block for processing XCMP messages. This
+ * overrides the amount set in the Config trait.
+ **/
+ reservedXcmpWeightOverride: AugmentedQuery<ApiType, () => Observable<Option<SpWeightsWeightV2Weight>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Latest included block descendants the runtime accepted. In other words, these are
+ * ancestors of the currently executing block which have not been included in the observed
+ * relay-chain state.
+ *
+ * The segment length is limited by the capacity returned from the [`ConsensusHook`] configured
+ * in the pallet.
+ **/
+ unincludedSegment: AugmentedQuery<ApiType, () => Observable<Vec<CumulusPalletParachainSystemUnincludedSegmentAncestor>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Optional upgrade go-ahead signal from the relay-chain.
+ *
+ * This storage item is a mirror of the corresponding value for the current parachain from the
+ * relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is
+ * set after the inherent.
+ **/
+ upgradeGoAhead: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5UpgradeGoAhead>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * An option which indicates if the relay-chain restricts signalling a validation code upgrade.
+ * In other words, if this is `Some` and [`NewValidationCode`] is `Some` then the produced
+ * candidate will be invalid.
+ *
+ * This storage item is a mirror of the corresponding value for the current parachain from the
+ * relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is
+ * set after the inherent.
+ **/
+ upgradeRestrictionSignal: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5UpgradeRestriction>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Upward messages that were sent in a block.
+ *
+ * This will be cleared in `on_initialize` of each new block.
+ **/
+ upwardMessages: AugmentedQuery<ApiType, () => Observable<Vec<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The [`PersistedValidationData`] set for this block.
+ * This value is expected to be set only once per block and it's never stored
+ * in the trie.
+ **/
+ validationData: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5PersistedValidationData>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ polkadotXcm: {
+ /**
+ * The existing asset traps.
+ *
+ * Key is the blake2 256 hash of (origin, versioned `MultiAssets`) pair. Value is the number of
+ * times this pair has been trapped (usually just 1 if it exists at all).
+ **/
+ assetTraps: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<u32>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * The current migration's stage, if any.
+ **/
+ currentMigration: AugmentedQuery<ApiType, () => Observable<Option<PalletXcmVersionMigrationStage>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Fungible assets which we know are locked on this chain.
+ **/
+ lockedFungibles: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<Vec<ITuple<[u128, StagingXcmVersionedMultiLocation]>>>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * The ongoing queries.
+ **/
+ queries: AugmentedQuery<ApiType, (arg: u64 | AnyNumber | Uint8Array) => Observable<Option<PalletXcmQueryStatus>>, [u64]> & QueryableStorageEntry<ApiType, [u64]>;
+ /**
+ * The latest available query index.
+ **/
+ queryCounter: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Fungible assets which we know are locked on a remote chain.
+ **/
+ remoteLockedFungibles: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array, arg3: StagingXcmVersionedAssetId | { V3: any } | string | Uint8Array) => Observable<Option<PalletXcmRemoteLockedFungibleRecord>>, [u32, AccountId32, StagingXcmVersionedAssetId]> & QueryableStorageEntry<ApiType, [u32, AccountId32, StagingXcmVersionedAssetId]>;
+ /**
+ * Default version to encode XCM when latest version of destination is unknown. If `None`,
+ * then the destinations whose XCM version is unknown are considered unreachable.
+ **/
+ safeXcmVersion: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The Latest versions that we know various locations support.
+ **/
+ supportedVersion: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => Observable<Option<u32>>, [u32, StagingXcmVersionedMultiLocation]> & QueryableStorageEntry<ApiType, [u32, StagingXcmVersionedMultiLocation]>;
+ /**
+ * Destinations whose latest XCM version we would like to know. Duplicates not allowed, and
+ * the `u32` counter is the number of times that a send to the destination has been attempted,
+ * which is used as a prioritization.
+ **/
+ versionDiscoveryQueue: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[StagingXcmVersionedMultiLocation, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * All locations that we have requested version notifications from.
+ **/
+ versionNotifiers: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => Observable<Option<u64>>, [u32, StagingXcmVersionedMultiLocation]> & QueryableStorageEntry<ApiType, [u32, StagingXcmVersionedMultiLocation]>;
+ /**
+ * The target locations that are subscribed to our version changes, as well as the most recent
+ * of our versions we informed them of.
+ **/
+ versionNotifyTargets: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => Observable<Option<ITuple<[u64, SpWeightsWeightV2Weight, u32]>>>, [u32, StagingXcmVersionedMultiLocation]> & QueryableStorageEntry<ApiType, [u32, StagingXcmVersionedMultiLocation]>;
+ /**
+ * Global suspension state of the XCM executor.
+ **/
+ xcmExecutionSuspended: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ preimage: {
+ preimageFor: AugmentedQuery<ApiType, (arg: ITuple<[H256, u32]> | [H256 | string | Uint8Array, u32 | AnyNumber | Uint8Array]) => Observable<Option<Bytes>>, [ITuple<[H256, u32]>]> & QueryableStorageEntry<ApiType, [ITuple<[H256, u32]>]>;
+ /**
+ * The request status of a given hash.
+ **/
+ statusFor: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<PalletPreimageRequestStatus>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ refungible: {
+ /**
+ * Amount of tokens (not pieces) partially owned by an account within a collection.
+ **/
+ accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.
+ **/
+ allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg4: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Amount of token pieces owned by account.
+ **/
+ balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Spender set by a wallet owner that could perform certain transactions on all tokens in the wallet.
+ **/
+ collectionAllowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * Used to enumerate tokens owned by account.
+ **/
+ owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
+ /**
+ * Amount of pieces a refungible token is split into.
+ **/
+ tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsProperties>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Amount of tokens burnt in a collection.
+ **/
+ tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Total amount of minted tokens in a collection.
+ **/
+ tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Total amount of pieces for token
+ **/
+ totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ scheduler: {
+ /**
+ * Items to be executed, indexed by the block number that they should be executed on.
+ **/
+ agenda: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<Option<PalletSchedulerScheduled>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ incompleteSince: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Lookup from a name to the block number and index of the task.
+ *
+ * For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4
+ * identities.
+ **/
+ lookup: AugmentedQuery<ApiType, (arg: U8aFixed | string | Uint8Array) => Observable<Option<ITuple<[u32, u32]>>>, [U8aFixed]> & QueryableStorageEntry<ApiType, [U8aFixed]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ session: {
+ /**
+ * Current index of the session.
+ **/
+ currentIndex: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Indices of disabled validators.
+ *
+ * The vec is always kept sorted so that we can find whether a given validator is
+ * disabled using binary search. It gets cleared when `on_session_ending` returns
+ * a new set of identities.
+ **/
+ disabledValidators: AugmentedQuery<ApiType, () => Observable<Vec<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The owner of a key. The key is the `KeyTypeId` + the encoded key.
+ **/
+ keyOwner: AugmentedQuery<ApiType, (arg: ITuple<[SpCoreCryptoKeyTypeId, Bytes]> | [SpCoreCryptoKeyTypeId | string | Uint8Array, Bytes | string | Uint8Array]) => Observable<Option<AccountId32>>, [ITuple<[SpCoreCryptoKeyTypeId, Bytes]>]> & QueryableStorageEntry<ApiType, [ITuple<[SpCoreCryptoKeyTypeId, Bytes]>]>;
+ /**
+ * The next session keys for a validator.
+ **/
+ nextKeys: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<OpalRuntimeRuntimeCommonSessionKeys>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * True if the underlying economic identities or weighting behind the validators
+ * has changed in the queued validator set.
+ **/
+ queuedChanged: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The queued keys for the next session. When the next session begins, these keys
+ * will be used to determine the validator's session keys.
+ **/
+ queuedKeys: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[AccountId32, OpalRuntimeRuntimeCommonSessionKeys]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current set of validators.
+ **/
+ validators: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ stateTrieMigration: {
+ /**
+ * The limits that are imposed on automatic migrations.
+ *
+ * If set to None, then no automatic migration happens.
+ **/
+ autoLimits: AugmentedQuery<ApiType, () => Observable<Option<PalletStateTrieMigrationMigrationLimits>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Migration progress.
+ *
+ * This stores the snapshot of the last migrated keys. It can be set into motion and move
+ * forward by any of the means provided by this pallet.
+ **/
+ migrationProcess: AugmentedQuery<ApiType, () => Observable<PalletStateTrieMigrationMigrationTask>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The maximum limits that the signed migration could use.
+ *
+ * If not set, no signed submission is allowed.
+ **/
+ signedMigrationMaxLimits: AugmentedQuery<ApiType, () => Observable<Option<PalletStateTrieMigrationMigrationLimits>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ sudo: {
+ /**
+ * The `AccountId` of the sudo key.
+ **/
+ key: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ system: {
+ /**
+ * The full account information for a particular account ID.
+ **/
+ account: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<FrameSystemAccountInfo>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Total length (in bytes) for all extrinsics put together, for the current block.
+ **/
+ allExtrinsicsLen: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Map of block numbers to block hashes.
+ **/
+ blockHash: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<H256>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * The current weight for the block.
+ **/
+ blockWeight: AugmentedQuery<ApiType, () => Observable<FrameSupportDispatchPerDispatchClassWeight>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Digest of the current block, also part of the block header.
+ **/
+ digest: AugmentedQuery<ApiType, () => Observable<SpRuntimeDigest>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The number of events in the `Events<T>` list.
+ **/
+ eventCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Events deposited for the current block.
+ *
+ * NOTE: The item is unbound and should therefore never be read on chain.
+ * It could otherwise inflate the PoV size of a block.
+ *
+ * Events have a large in-memory size. Box the events to not go out-of-memory
+ * just in case someone still reads them from within the runtime.
+ **/
+ events: AugmentedQuery<ApiType, () => Observable<Vec<FrameSystemEventRecord>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Mapping between a topic (represented by T::Hash) and a vector of indexes
+ * of events in the `<Events<T>>` list.
+ *
+ * All topic vectors have deterministic storage locations depending on the topic. This
+ * allows light-clients to leverage the changes trie storage tracking mechanism and
+ * in case of changes fetch the list of events of interest.
+ *
+ * The value has the type `(BlockNumberFor<T>, EventIndex)` because if we used only just
+ * the `EventIndex` then in case if the topic has the same contents on the next block
+ * no notification will be triggered thus the event might be lost.
+ **/
+ eventTopics: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Vec<ITuple<[u32, u32]>>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * The execution phase of the block.
+ **/
+ executionPhase: AugmentedQuery<ApiType, () => Observable<Option<FrameSystemPhase>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Total extrinsics count for the current block.
+ **/
+ extrinsicCount: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Extrinsics data for the current block (maps an extrinsic's index to its data).
+ **/
+ extrinsicData: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened.
+ **/
+ lastRuntimeUpgrade: AugmentedQuery<ApiType, () => Observable<Option<FrameSystemLastRuntimeUpgradeInfo>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current block number being processed. Set by `execute_block`.
+ **/
+ number: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Hash of the previous block.
+ **/
+ parentHash: AugmentedQuery<ApiType, () => Observable<H256>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * True if we have upgraded so that AccountInfo contains three types of `RefCount`. False
+ * (default) if not.
+ **/
+ upgradedToTripleRefCount: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * True if we have upgraded so that `type RefCount` is `u32`. False (default) if not.
+ **/
+ upgradedToU32RefCount: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ technicalCommittee: {
+ /**
+ * The current members of the collective. This is stored sorted (just by value).
+ **/
+ members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The prime member that helps determine the default vote behavior in case of absentations.
+ **/
+ prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Proposals so far.
+ **/
+ proposalCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Actual proposal for a given hash, if it's current.
+ **/
+ proposalOf: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<Call>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * The hashes of the active proposals.
+ **/
+ proposals: AugmentedQuery<ApiType, () => Observable<Vec<H256>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Votes on a given proposal, if it is ongoing.
+ **/
+ voting: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<PalletCollectiveVotes>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ technicalCommitteeMembership: {
+ /**
+ * The current membership, stored as an ordered Vec.
+ **/
+ members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The current prime member, if one exists.
+ **/
+ prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ testUtils: {
+ enabled: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ testValue: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ timestamp: {
+ /**
+ * Did the timestamp get updated in this block?
+ **/
+ didUpdate: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Current time for the current block.
+ **/
+ now: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ tokens: {
+ /**
+ * The balance of a token type under an account.
+ *
+ * NOTE: If the total is ever zero, decrease account ref account.
+ *
+ * NOTE: This is only used in the case that this module is used to store
+ * balances.
+ **/
+ accounts: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<OrmlTokensAccountData>, [AccountId32, PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [AccountId32, PalletForeignAssetsAssetId]>;
+ /**
+ * Any liquidity locks of a token type under an account.
+ * NOTE: Should only be accessed when setting, changing and freeing a lock.
+ **/
+ locks: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<Vec<OrmlTokensBalanceLock>>, [AccountId32, PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [AccountId32, PalletForeignAssetsAssetId]>;
+ /**
+ * Named reserves on some account balances.
+ **/
+ reserves: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<Vec<OrmlTokensReserveData>>, [AccountId32, PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [AccountId32, PalletForeignAssetsAssetId]>;
+ /**
+ * The total issuance of a token type.
+ **/
+ totalIssuance: AugmentedQuery<ApiType, (arg: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<u128>, [PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [PalletForeignAssetsAssetId]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ transactionPayment: {
+ nextFeeMultiplier: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ storageVersion: AugmentedQuery<ApiType, () => Observable<PalletTransactionPaymentReleases>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ treasury: {
+ /**
+ * Proposal indices that have been approved but not yet awarded.
+ **/
+ approvals: AugmentedQuery<ApiType, () => Observable<Vec<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The amount which has been reported as inactive to Currency.
+ **/
+ deactivated: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Number of proposals that have been made.
+ **/
+ proposalCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Proposals that have been made.
+ **/
+ proposals: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletTreasuryProposal>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ unique: {
+ /**
+ * Used for migrations
+ **/
+ chainVersion: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * (Collection id (controlled?2), who created (real))
+ * TODO: Off chain worker should remove from this map when collection gets removed
+ **/
+ createItemBasket: AugmentedQuery<ApiType, (arg: ITuple<[u32, AccountId32]> | [u32 | AnyNumber | Uint8Array, AccountId32 | string | Uint8Array]) => Observable<Option<u32>>, [ITuple<[u32, AccountId32]>]> & QueryableStorageEntry<ApiType, [ITuple<[u32, AccountId32]>]>;
+ /**
+ * Last sponsoring of fungible tokens approval in a collection
+ **/
+ fungibleApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
+ /**
+ * Collection id (controlled?2), owning user (real)
+ **/
+ fungibleTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
+ /**
+ * Last sponsoring of NFT approval in a collection
+ **/
+ nftApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Collection id (controlled?2), token id (controlled?2)
+ **/
+ nftTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Last sponsoring of RFT approval in a collection
+ **/
+ refungibleApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, u32, AccountId32]>;
+ /**
+ * Collection id (controlled?2), token id (controlled?2)
+ **/
+ reFungibleTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, u32, AccountId32]>;
+ /**
+ * Last sponsoring of token property setting // todo:doc rephrase this and the following
+ **/
+ tokenPropertyBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ vesting: {
+ /**
+ * Vesting schedules of an account.
+ *
+ * VestingSchedules: map AccountId => Vec<VestingSchedule>
+ **/
+ vestingSchedules: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<OrmlVestingVestingSchedule>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ xcmpQueue: {
+ /**
+ * Counter for the related counted storage map
+ **/
+ counterForOverweight: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Inbound aggregate XCMP messages. It can only be one per ParaId/block.
+ **/
+ inboundXcmpMessages: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+ /**
+ * Status of the inbound XCMP channels.
+ **/
+ inboundXcmpStatus: AugmentedQuery<ApiType, () => Observable<Vec<CumulusPalletXcmpQueueInboundChannelDetails>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The messages outbound in a given XCMP channel.
+ **/
+ outboundXcmpMessages: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u16 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32, u16]> & QueryableStorageEntry<ApiType, [u32, u16]>;
+ /**
+ * The non-empty XCMP channels in order of becoming non-empty, and the index of the first
+ * and last outbound message. If the two indices are equal, then it indicates an empty
+ * queue and there must be a non-`Ok` `OutboundStatus`. We assume queues grow no greater
+ * than 65535 items. Queue indices for normal messages begin at one; zero is reserved in
+ * case of the need to send a high-priority signal message this block.
+ * The bool is true if there is a signal message waiting to be sent.
+ **/
+ outboundXcmpStatus: AugmentedQuery<ApiType, () => Observable<Vec<CumulusPalletXcmpQueueOutboundChannelDetails>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The messages that exceeded max individual message weight budget.
+ *
+ * These message stay in this storage map until they are manually dispatched via
+ * `service_overweight`.
+ **/
+ overweight: AugmentedQuery<ApiType, (arg: u64 | AnyNumber | Uint8Array) => Observable<Option<ITuple<[u32, u32, Bytes]>>>, [u64]> & QueryableStorageEntry<ApiType, [u64]>;
+ /**
+ * The number of overweight messages ever recorded in `Overweight`. Also doubles as the next
+ * available free overweight index.
+ **/
+ overweightCount: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * The configuration which controls the dynamics of the outbound queue.
+ **/
+ queueConfig: AugmentedQuery<ApiType, () => Observable<CumulusPalletXcmpQueueQueueConfigData>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Whether or not the XCMP queue is suspended from executing incoming XCMs or not.
+ **/
+ queueSuspended: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Any signal messages waiting to be sent.
+ **/
+ signalMessages: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
+ } // AugmentedQueries
+} // declare module
js-packages/types/augment-api-rpc.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-rpc.ts
@@ -0,0 +1,752 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/rpc-core/types/jsonrpc';
+
+import type { PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo } from './default';
+import type { AugmentedRpc } from '@polkadot/rpc-core/types';
+import type { Metadata, StorageKey } from '@polkadot/types';
+import type { Bytes, HashMap, Json, Null, Option, Text, U256, U64, Vec, bool, f64, u128, u32, u64 } from '@polkadot/types-codec';
+import type { AnyNumber, Codec, ITuple } from '@polkadot/types-codec/types';
+import type { ExtrinsicOrHash, ExtrinsicStatus } from '@polkadot/types/interfaces/author';
+import type { EpochAuthorship } from '@polkadot/types/interfaces/babe';
+import type { BeefySignedCommitment } from '@polkadot/types/interfaces/beefy';
+import type { BlockHash } from '@polkadot/types/interfaces/chain';
+import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';
+import type { AuthorityId } from '@polkadot/types/interfaces/consensus';
+import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequestV1 } from '@polkadot/types/interfaces/contracts';
+import type { BlockStats } from '@polkadot/types/interfaces/dev';
+import type { CreatedBlock } from '@polkadot/types/interfaces/engine';
+import type { EthAccount, EthCallRequest, EthFeeHistory, EthFilter, EthFilterChanges, EthLog, EthReceipt, EthRichBlock, EthSubKind, EthSubParams, EthSyncStatus, EthTransaction, EthTransactionRequest, EthWork } from '@polkadot/types/interfaces/eth';
+import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
+import type { EncodedFinalityProofs, JustificationNotification, ReportedRoundStates } from '@polkadot/types/interfaces/grandpa';
+import type { MmrHash, MmrLeafBatchProof } from '@polkadot/types/interfaces/mmr';
+import type { StorageKind } from '@polkadot/types/interfaces/offchain';
+import type { FeeDetails, RuntimeDispatchInfoV1 } from '@polkadot/types/interfaces/payment';
+import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
+import type { AccountId, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';
+import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';
+import type { ApplyExtrinsicResult, ChainProperties, ChainType, Health, NetworkState, NodeRole, PeerInfo, SyncState } from '@polkadot/types/interfaces/system';
+import type { IExtrinsic, Observable } from '@polkadot/types/types';
+
+export type __AugmentedRpc = AugmentedRpc<() => unknown>;
+
+declare module '@polkadot/rpc-core/types/jsonrpc' {
+ interface RpcInterface {
+ appPromotion: {
+ /**
+ * Returns the total amount of unstaked tokens
+ **/
+ pendingUnstake: AugmentedRpc<(staker?: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
+ /**
+ * Returns the total amount of unstaked tokens per block
+ **/
+ pendingUnstakePerBlock: AugmentedRpc<(staker: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<ITuple<[u32, u128]>>>>;
+ /**
+ * Returns the total amount of staked tokens
+ **/
+ totalStaked: AugmentedRpc<(staker?: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
+ /**
+ * Returns the total amount of staked tokens per block when staked
+ **/
+ totalStakedPerBlock: AugmentedRpc<(staker: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<ITuple<[u32, u128]>>>>;
+ };
+ author: {
+ /**
+ * Returns true if the keystore has private keys for the given public key and key type.
+ **/
+ hasKey: AugmentedRpc<(publicKey: Bytes | string | Uint8Array, keyType: Text | string) => Observable<bool>>;
+ /**
+ * Returns true if the keystore has private keys for the given session public keys.
+ **/
+ hasSessionKeys: AugmentedRpc<(sessionKeys: Bytes | string | Uint8Array) => Observable<bool>>;
+ /**
+ * Insert a key into the keystore.
+ **/
+ insertKey: AugmentedRpc<(keyType: Text | string, suri: Text | string, publicKey: Bytes | string | Uint8Array) => Observable<Bytes>>;
+ /**
+ * Returns all pending extrinsics, potentially grouped by sender
+ **/
+ pendingExtrinsics: AugmentedRpc<() => Observable<Vec<Extrinsic>>>;
+ /**
+ * Remove given extrinsic from the pool and temporarily ban it to prevent reimporting
+ **/
+ removeExtrinsic: AugmentedRpc<(bytesOrHash: Vec<ExtrinsicOrHash> | (ExtrinsicOrHash | { Hash: any } | { Extrinsic: any } | string | Uint8Array)[]) => Observable<Vec<Hash>>>;
+ /**
+ * Generate new session keys and returns the corresponding public keys
+ **/
+ rotateKeys: AugmentedRpc<() => Observable<Bytes>>;
+ /**
+ * Submit and subscribe to watch an extrinsic until unsubscribed
+ **/
+ submitAndWatchExtrinsic: AugmentedRpc<(extrinsic: Extrinsic | IExtrinsic | string | Uint8Array) => Observable<ExtrinsicStatus>>;
+ /**
+ * Submit a fully formatted extrinsic for block inclusion
+ **/
+ submitExtrinsic: AugmentedRpc<(extrinsic: Extrinsic | IExtrinsic | string | Uint8Array) => Observable<Hash>>;
+ };
+ babe: {
+ /**
+ * Returns data about which slots (primary or secondary) can be claimed in the current epoch with the keys in the keystore
+ **/
+ epochAuthorship: AugmentedRpc<() => Observable<HashMap<AuthorityId, EpochAuthorship>>>;
+ };
+ beefy: {
+ /**
+ * Returns hash of the latest BEEFY finalized block as seen by this client.
+ **/
+ getFinalizedHead: AugmentedRpc<() => Observable<H256>>;
+ /**
+ * Returns the block most recently finalized by BEEFY, alongside side its justification.
+ **/
+ subscribeJustifications: AugmentedRpc<() => Observable<BeefySignedCommitment>>;
+ };
+ chain: {
+ /**
+ * Get header and body of a relay chain block
+ **/
+ getBlock: AugmentedRpc<(hash?: BlockHash | string | Uint8Array) => Observable<SignedBlock>>;
+ /**
+ * Get the block hash for a specific block
+ **/
+ getBlockHash: AugmentedRpc<(blockNumber?: BlockNumber | AnyNumber | Uint8Array) => Observable<BlockHash>>;
+ /**
+ * Get hash of the last finalized block in the canon chain
+ **/
+ getFinalizedHead: AugmentedRpc<() => Observable<BlockHash>>;
+ /**
+ * Retrieves the header for a specific block
+ **/
+ getHeader: AugmentedRpc<(hash?: BlockHash | string | Uint8Array) => Observable<Header>>;
+ /**
+ * Retrieves the newest header via subscription
+ **/
+ subscribeAllHeads: AugmentedRpc<() => Observable<Header>>;
+ /**
+ * Retrieves the best finalized header via subscription
+ **/
+ subscribeFinalizedHeads: AugmentedRpc<() => Observable<Header>>;
+ /**
+ * Retrieves the best header via subscription
+ **/
+ subscribeNewHeads: AugmentedRpc<() => Observable<Header>>;
+ };
+ childstate: {
+ /**
+ * Returns the keys with prefix from a child storage, leave empty to get all the keys
+ **/
+ getKeys: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, prefix: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
+ /**
+ * Returns the keys with prefix from a child storage with pagination support
+ **/
+ getKeysPaged: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, prefix: StorageKey | string | Uint8Array | any, count: u32 | AnyNumber | Uint8Array, startKey?: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
+ /**
+ * Returns a child storage entry at a specific block state
+ **/
+ getStorage: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Option<StorageData>>>;
+ /**
+ * Returns child storage entries for multiple keys at a specific block state
+ **/
+ getStorageEntries: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: Hash | string | Uint8Array) => Observable<Vec<Option<StorageData>>>>;
+ /**
+ * Returns the hash of a child storage entry at a block state
+ **/
+ getStorageHash: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Option<Hash>>>;
+ /**
+ * Returns the size of a child storage entry at a block state
+ **/
+ getStorageSize: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Option<u64>>>;
+ };
+ contracts: {
+ /**
+ * @deprecated Use the runtime interface `api.call.contractsApi.call` instead
+ * Executes a call to a contract
+ **/
+ call: AugmentedRpc<(callRequest: ContractCallRequest | { origin?: any; dest?: any; value?: any; gasLimit?: any; storageDepositLimit?: any; inputData?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractExecResult>>;
+ /**
+ * @deprecated Use the runtime interface `api.call.contractsApi.getStorage` instead
+ * Returns the value under a specified storage key in a contract
+ **/
+ getStorage: AugmentedRpc<(address: AccountId | string | Uint8Array, key: H256 | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Option<Bytes>>>;
+ /**
+ * @deprecated Use the runtime interface `api.call.contractsApi.instantiate` instead
+ * Instantiate a new contract
+ **/
+ instantiate: AugmentedRpc<(request: InstantiateRequestV1 | { origin?: any; value?: any; gasLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;
+ /**
+ * @deprecated Not available in newer versions of the contracts interfaces
+ * Returns the projected time a given contract will be able to sustain paying its rent
+ **/
+ rentProjection: AugmentedRpc<(address: AccountId | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Option<BlockNumber>>>;
+ /**
+ * @deprecated Use the runtime interface `api.call.contractsApi.uploadCode` instead
+ * Upload new code without instantiating a contract from it
+ **/
+ uploadCode: AugmentedRpc<(uploadRequest: CodeUploadRequest | { origin?: any; code?: any; storageDepositLimit?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<CodeUploadResult>>;
+ };
+ dev: {
+ /**
+ * Reexecute the specified `block_hash` and gather statistics while doing so
+ **/
+ getBlockStats: AugmentedRpc<(at: Hash | string | Uint8Array) => Observable<Option<BlockStats>>>;
+ };
+ engine: {
+ /**
+ * Instructs the manual-seal authorship task to create a new block
+ **/
+ createBlock: AugmentedRpc<(createEmpty: bool | boolean | Uint8Array, finalize: bool | boolean | Uint8Array, parentHash?: BlockHash | string | Uint8Array) => Observable<CreatedBlock>>;
+ /**
+ * Instructs the manual-seal authorship task to finalize a block
+ **/
+ finalizeBlock: AugmentedRpc<(hash: BlockHash | string | Uint8Array, justification?: Justification) => Observable<bool>>;
+ };
+ eth: {
+ /**
+ * Returns accounts list.
+ **/
+ accounts: AugmentedRpc<() => Observable<Vec<H160>>>;
+ /**
+ * Returns the blockNumber
+ **/
+ blockNumber: AugmentedRpc<() => Observable<U256>>;
+ /**
+ * Call contract, returning the output data.
+ **/
+ call: AugmentedRpc<(request: EthCallRequest | { from?: any; to?: any; gasPrice?: any; gas?: any; value?: any; data?: any; nonce?: any } | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<Bytes>>;
+ /**
+ * Returns the chain ID used for transaction signing at the current best block. None is returned if not available.
+ **/
+ chainId: AugmentedRpc<() => Observable<U64>>;
+ /**
+ * Returns block author.
+ **/
+ coinbase: AugmentedRpc<() => Observable<H160>>;
+ /**
+ * Estimate gas needed for execution of given contract.
+ **/
+ estimateGas: AugmentedRpc<(request: EthCallRequest | { from?: any; to?: any; gasPrice?: any; gas?: any; value?: any; data?: any; nonce?: any } | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns fee history for given block count & reward percentiles
+ **/
+ feeHistory: AugmentedRpc<(blockCount: U256 | AnyNumber | Uint8Array, newestBlock: BlockNumber | AnyNumber | Uint8Array, rewardPercentiles: Option<Vec<f64>> | null | Uint8Array | Vec<f64> | (f64)[]) => Observable<EthFeeHistory>>;
+ /**
+ * Returns current gas price.
+ **/
+ gasPrice: AugmentedRpc<() => Observable<U256>>;
+ /**
+ * Returns balance of the given account.
+ **/
+ getBalance: AugmentedRpc<(address: H160 | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns block with given hash.
+ **/
+ getBlockByHash: AugmentedRpc<(hash: H256 | string | Uint8Array, full: bool | boolean | Uint8Array) => Observable<Option<EthRichBlock>>>;
+ /**
+ * Returns block with given number.
+ **/
+ getBlockByNumber: AugmentedRpc<(block: BlockNumber | AnyNumber | Uint8Array, full: bool | boolean | Uint8Array) => Observable<Option<EthRichBlock>>>;
+ /**
+ * Returns the number of transactions in a block with given hash.
+ **/
+ getBlockTransactionCountByHash: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns the number of transactions in a block with given block number.
+ **/
+ getBlockTransactionCountByNumber: AugmentedRpc<(block: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns the code at given address at given time (block number).
+ **/
+ getCode: AugmentedRpc<(address: H160 | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<Bytes>>;
+ /**
+ * Returns filter changes since last poll.
+ **/
+ getFilterChanges: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array) => Observable<EthFilterChanges>>;
+ /**
+ * Returns all logs matching given filter (in a range 'from' - 'to').
+ **/
+ getFilterLogs: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array) => Observable<Vec<EthLog>>>;
+ /**
+ * Returns logs matching given filter object.
+ **/
+ getLogs: AugmentedRpc<(filter: EthFilter | { fromBlock?: any; toBlock?: any; blockHash?: any; address?: any; topics?: any } | string | Uint8Array) => Observable<Vec<EthLog>>>;
+ /**
+ * Returns proof for account and storage.
+ **/
+ getProof: AugmentedRpc<(address: H160 | string | Uint8Array, storageKeys: Vec<H256> | (H256 | string | Uint8Array)[], number: BlockNumber | AnyNumber | Uint8Array) => Observable<EthAccount>>;
+ /**
+ * Returns content of the storage at given address.
+ **/
+ getStorageAt: AugmentedRpc<(address: H160 | string | Uint8Array, index: U256 | AnyNumber | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<H256>>;
+ /**
+ * Returns transaction at given block hash and index.
+ **/
+ getTransactionByBlockHashAndIndex: AugmentedRpc<(hash: H256 | string | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthTransaction>>;
+ /**
+ * Returns transaction by given block number and index.
+ **/
+ getTransactionByBlockNumberAndIndex: AugmentedRpc<(number: BlockNumber | AnyNumber | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthTransaction>>;
+ /**
+ * Get transaction by its hash.
+ **/
+ getTransactionByHash: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<EthTransaction>>;
+ /**
+ * Returns the number of transactions sent from given address at given time (block number).
+ **/
+ getTransactionCount: AugmentedRpc<(address: H160 | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns transaction receipt by transaction hash.
+ **/
+ getTransactionReceipt: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<EthReceipt>>;
+ /**
+ * Returns an uncles at given block and index.
+ **/
+ getUncleByBlockHashAndIndex: AugmentedRpc<(hash: H256 | string | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthRichBlock>>;
+ /**
+ * Returns an uncles at given block and index.
+ **/
+ getUncleByBlockNumberAndIndex: AugmentedRpc<(number: BlockNumber | AnyNumber | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthRichBlock>>;
+ /**
+ * Returns the number of uncles in a block with given hash.
+ **/
+ getUncleCountByBlockHash: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns the number of uncles in a block with given block number.
+ **/
+ getUncleCountByBlockNumber: AugmentedRpc<(number: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns the hash of the current block, the seedHash, and the boundary condition to be met.
+ **/
+ getWork: AugmentedRpc<() => Observable<EthWork>>;
+ /**
+ * Returns the number of hashes per second that the node is mining with.
+ **/
+ hashrate: AugmentedRpc<() => Observable<U256>>;
+ /**
+ * Returns max priority fee per gas
+ **/
+ maxPriorityFeePerGas: AugmentedRpc<() => Observable<U256>>;
+ /**
+ * Returns true if client is actively mining new blocks.
+ **/
+ mining: AugmentedRpc<() => Observable<bool>>;
+ /**
+ * Returns id of new block filter.
+ **/
+ newBlockFilter: AugmentedRpc<() => Observable<U256>>;
+ /**
+ * Returns id of new filter.
+ **/
+ newFilter: AugmentedRpc<(filter: EthFilter | { fromBlock?: any; toBlock?: any; blockHash?: any; address?: any; topics?: any } | string | Uint8Array) => Observable<U256>>;
+ /**
+ * Returns id of new block filter.
+ **/
+ newPendingTransactionFilter: AugmentedRpc<() => Observable<U256>>;
+ /**
+ * Returns protocol version encoded as a string (quotes are necessary).
+ **/
+ protocolVersion: AugmentedRpc<() => Observable<u64>>;
+ /**
+ * Sends signed transaction, returning its hash.
+ **/
+ sendRawTransaction: AugmentedRpc<(bytes: Bytes | string | Uint8Array) => Observable<H256>>;
+ /**
+ * Sends transaction; will block waiting for signer to return the transaction hash
+ **/
+ sendTransaction: AugmentedRpc<(tx: EthTransactionRequest | { from?: any; to?: any; gasPrice?: any; gas?: any; value?: any; data?: any; nonce?: any } | string | Uint8Array) => Observable<H256>>;
+ /**
+ * Used for submitting mining hashrate.
+ **/
+ submitHashrate: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array, hash: H256 | string | Uint8Array) => Observable<bool>>;
+ /**
+ * Used for submitting a proof-of-work solution.
+ **/
+ submitWork: AugmentedRpc<(nonce: H64 | string | Uint8Array, headerHash: H256 | string | Uint8Array, mixDigest: H256 | string | Uint8Array) => Observable<bool>>;
+ /**
+ * Subscribe to Eth subscription.
+ **/
+ subscribe: AugmentedRpc<(kind: EthSubKind | 'newHeads' | 'logs' | 'newPendingTransactions' | 'syncing' | number | Uint8Array, params?: EthSubParams | { None: any } | { Logs: any } | string | Uint8Array) => Observable<Null>>;
+ /**
+ * Returns an object with data about the sync status or false.
+ **/
+ syncing: AugmentedRpc<() => Observable<EthSyncStatus>>;
+ /**
+ * Uninstalls filter.
+ **/
+ uninstallFilter: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array) => Observable<bool>>;
+ };
+ grandpa: {
+ /**
+ * Prove finality for the given block number, returning the Justification for the last block in the set.
+ **/
+ proveFinality: AugmentedRpc<(blockNumber: BlockNumber | AnyNumber | Uint8Array) => Observable<Option<EncodedFinalityProofs>>>;
+ /**
+ * Returns the state of the current best round state as well as the ongoing background rounds
+ **/
+ roundState: AugmentedRpc<() => Observable<ReportedRoundStates>>;
+ /**
+ * Subscribes to grandpa justifications
+ **/
+ subscribeJustifications: AugmentedRpc<() => Observable<JustificationNotification>>;
+ };
+ mmr: {
+ /**
+ * Generate MMR proof for the given block numbers.
+ **/
+ generateProof: AugmentedRpc<(blockNumbers: Vec<u64> | (u64 | AnyNumber | Uint8Array)[], bestKnownBlockNumber?: u64 | AnyNumber | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<MmrLeafBatchProof>>;
+ /**
+ * Get the MMR root hash for the current best block.
+ **/
+ root: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<MmrHash>>;
+ /**
+ * Verify an MMR proof
+ **/
+ verifyProof: AugmentedRpc<(proof: MmrLeafBatchProof | { blockHash?: any; leaves?: any; proof?: any } | string | Uint8Array) => Observable<bool>>;
+ /**
+ * Verify an MMR proof statelessly given an mmr_root
+ **/
+ verifyProofStateless: AugmentedRpc<(root: MmrHash | string | Uint8Array, proof: MmrLeafBatchProof | { blockHash?: any; leaves?: any; proof?: any } | string | Uint8Array) => Observable<bool>>;
+ };
+ net: {
+ /**
+ * Returns true if client is actively listening for network connections. Otherwise false.
+ **/
+ listening: AugmentedRpc<() => Observable<bool>>;
+ /**
+ * Returns number of peers connected to node.
+ **/
+ peerCount: AugmentedRpc<() => Observable<Text>>;
+ /**
+ * Returns protocol version.
+ **/
+ version: AugmentedRpc<() => Observable<Text>>;
+ };
+ offchain: {
+ /**
+ * Get offchain local storage under given key and prefix
+ **/
+ localStorageGet: AugmentedRpc<(kind: StorageKind | 'PERSISTENT' | 'LOCAL' | number | Uint8Array, key: Bytes | string | Uint8Array) => Observable<Option<Bytes>>>;
+ /**
+ * Set offchain local storage under given key and prefix
+ **/
+ localStorageSet: AugmentedRpc<(kind: StorageKind | 'PERSISTENT' | 'LOCAL' | number | Uint8Array, key: Bytes | string | Uint8Array, value: Bytes | string | Uint8Array) => Observable<Null>>;
+ };
+ payment: {
+ /**
+ * @deprecated Use `api.call.transactionPaymentApi.queryFeeDetails` instead
+ * Query the detailed fee of a given encoded extrinsic
+ **/
+ queryFeeDetails: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<FeeDetails>>;
+ /**
+ * @deprecated Use `api.call.transactionPaymentApi.queryInfo` instead
+ * Retrieves the fee information for an encoded extrinsic
+ **/
+ queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfoV1>>;
+ };
+ povinfo: {
+ /**
+ * Estimate PoV size of encoded signed extrinsics
+ **/
+ estimateExtrinsicPoV: AugmentedRpc<(encodedXt: Vec<Bytes> | (Bytes | string | Uint8Array)[], at?: Hash | string | Uint8Array) => Observable<UpPovEstimateRpcPovInfo>>;
+ };
+ rpc: {
+ /**
+ * Retrieves the list of RPC methods that are exposed by the node
+ **/
+ methods: AugmentedRpc<() => Observable<RpcMethods>>;
+ };
+ state: {
+ /**
+ * Perform a call to a builtin on the chain
+ **/
+ call: AugmentedRpc<(method: Text | string, data: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Bytes>>;
+ /**
+ * Retrieves the keys with prefix of a specific child storage
+ **/
+ getChildKeys: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
+ /**
+ * Returns proof of storage for child key entries at a specific block state.
+ **/
+ getChildReadProof: AugmentedRpc<(childStorageKey: PrefixedStorageKey | string | Uint8Array, keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: BlockHash | string | Uint8Array) => Observable<ReadProof>>;
+ /**
+ * Retrieves the child storage for a key
+ **/
+ getChildStorage: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<StorageData>>;
+ /**
+ * Retrieves the child storage hash
+ **/
+ getChildStorageHash: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Hash>>;
+ /**
+ * Retrieves the child storage size
+ **/
+ getChildStorageSize: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<u64>>;
+ /**
+ * @deprecated Use `api.rpc.state.getKeysPaged` to retrieve keys
+ * Retrieves the keys with a certain prefix
+ **/
+ getKeys: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
+ /**
+ * Returns the keys with prefix with pagination support.
+ **/
+ getKeysPaged: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, count: u32 | AnyNumber | Uint8Array, startKey?: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
+ /**
+ * Returns the runtime metadata
+ **/
+ getMetadata: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<Metadata>>;
+ /**
+ * @deprecated Use `api.rpc.state.getKeysPaged` to retrieve keys
+ * Returns the keys with prefix, leave empty to get all the keys (deprecated: Use getKeysPaged)
+ **/
+ getPairs: AugmentedRpc<(prefix: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<KeyValue>>>;
+ /**
+ * Returns proof of storage entries at a specific block state
+ **/
+ getReadProof: AugmentedRpc<(keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: BlockHash | string | Uint8Array) => Observable<ReadProof>>;
+ /**
+ * Get the runtime version
+ **/
+ getRuntimeVersion: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<RuntimeVersion>>;
+ /**
+ * Retrieves the storage for a key
+ **/
+ getStorage: AugmentedRpc<<T = Codec>(key: StorageKey | string | Uint8Array | any, block?: Hash | Uint8Array | string) => Observable<T>>;
+ /**
+ * Retrieves the storage hash
+ **/
+ getStorageHash: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Hash>>;
+ /**
+ * Retrieves the storage size
+ **/
+ getStorageSize: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<u64>>;
+ /**
+ * Query historical storage entries (by key) starting from a start block
+ **/
+ queryStorage: AugmentedRpc<<T = Codec[]>(keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], fromBlock?: Hash | Uint8Array | string, toBlock?: Hash | Uint8Array | string) => Observable<[Hash, T][]>>;
+ /**
+ * Query storage entries (by key) starting at block hash given as the second parameter
+ **/
+ queryStorageAt: AugmentedRpc<<T = Codec[]>(keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: Hash | Uint8Array | string) => Observable<T>>;
+ /**
+ * Retrieves the runtime version via subscription
+ **/
+ subscribeRuntimeVersion: AugmentedRpc<() => Observable<RuntimeVersion>>;
+ /**
+ * Subscribes to storage changes for the provided keys
+ **/
+ subscribeStorage: AugmentedRpc<<T = Codec[]>(keys?: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[]) => Observable<T>>;
+ /**
+ * Provides a way to trace the re-execution of a single block
+ **/
+ traceBlock: AugmentedRpc<(block: Hash | string | Uint8Array, targets: Option<Text> | null | Uint8Array | Text | string, storageKeys: Option<Text> | null | Uint8Array | Text | string, methods: Option<Text> | null | Uint8Array | Text | string) => Observable<TraceBlockResponse>>;
+ /**
+ * Check current migration state
+ **/
+ trieMigrationStatus: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<MigrationStatusResult>>;
+ };
+ syncstate: {
+ /**
+ * Returns the json-serialized chainspec running the node, with a sync state.
+ **/
+ genSyncSpec: AugmentedRpc<(raw: bool | boolean | Uint8Array) => Observable<Json>>;
+ };
+ system: {
+ /**
+ * Retrieves the next accountIndex as available on the node
+ **/
+ accountNextIndex: AugmentedRpc<(accountId: AccountId | string | Uint8Array) => Observable<Index>>;
+ /**
+ * Adds the supplied directives to the current log filter
+ **/
+ addLogFilter: AugmentedRpc<(directives: Text | string) => Observable<Null>>;
+ /**
+ * Adds a reserved peer
+ **/
+ addReservedPeer: AugmentedRpc<(peer: Text | string) => Observable<Text>>;
+ /**
+ * Retrieves the chain
+ **/
+ chain: AugmentedRpc<() => Observable<Text>>;
+ /**
+ * Retrieves the chain type
+ **/
+ chainType: AugmentedRpc<() => Observable<ChainType>>;
+ /**
+ * Dry run an extrinsic at a given block
+ **/
+ dryRun: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ApplyExtrinsicResult>>;
+ /**
+ * Return health status of the node
+ **/
+ health: AugmentedRpc<() => Observable<Health>>;
+ /**
+ * The addresses include a trailing /p2p/ with the local PeerId, and are thus suitable to be passed to addReservedPeer or as a bootnode address for example
+ **/
+ localListenAddresses: AugmentedRpc<() => Observable<Vec<Text>>>;
+ /**
+ * Returns the base58-encoded PeerId of the node
+ **/
+ localPeerId: AugmentedRpc<() => Observable<Text>>;
+ /**
+ * Retrieves the node name
+ **/
+ name: AugmentedRpc<() => Observable<Text>>;
+ /**
+ * Returns current state of the network
+ **/
+ networkState: AugmentedRpc<() => Observable<NetworkState>>;
+ /**
+ * Returns the roles the node is running as
+ **/
+ nodeRoles: AugmentedRpc<() => Observable<Vec<NodeRole>>>;
+ /**
+ * Returns the currently connected peers
+ **/
+ peers: AugmentedRpc<() => Observable<Vec<PeerInfo>>>;
+ /**
+ * Get a custom set of properties as a JSON object, defined in the chain spec
+ **/
+ properties: AugmentedRpc<() => Observable<ChainProperties>>;
+ /**
+ * Remove a reserved peer
+ **/
+ removeReservedPeer: AugmentedRpc<(peerId: Text | string) => Observable<Text>>;
+ /**
+ * Returns the list of reserved peers
+ **/
+ reservedPeers: AugmentedRpc<() => Observable<Vec<Text>>>;
+ /**
+ * Resets the log filter to Substrate defaults
+ **/
+ resetLogFilter: AugmentedRpc<() => Observable<Null>>;
+ /**
+ * Returns the state of the syncing of the node
+ **/
+ syncState: AugmentedRpc<() => Observable<SyncState>>;
+ /**
+ * Retrieves the version of the node
+ **/
+ version: AugmentedRpc<() => Observable<Text>>;
+ };
+ unique: {
+ /**
+ * Get the amount of any user tokens owned by an account
+ **/
+ accountBalance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
+ /**
+ * Get tokens owned by an account in a collection
+ **/
+ accountTokens: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<u32>>>;
+ /**
+ * Get the list of admin accounts of a collection
+ **/
+ adminlist: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+ /**
+ * Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor
+ **/
+ allowance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, sender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
+ /**
+ * Tells whether the given `owner` approves the `operator`.
+ **/
+ allowanceForAll: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<bool>>>;
+ /**
+ * Check if a user is allowed to operate within a collection
+ **/
+ allowed: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<bool>>;
+ /**
+ * Get the list of accounts allowed to operate within a collection
+ **/
+ allowlist: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+ /**
+ * Get the amount of a specific token owned by an account
+ **/
+ balance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
+ /**
+ * Get a collection by the specified ID
+ **/
+ collectionById: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsRpcCollection>>>;
+ /**
+ * Get collection properties, optionally limited to the provided keys
+ **/
+ collectionProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Option<Vec<Text>> | null | Uint8Array | Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
+ /**
+ * Get chain stats about collections
+ **/
+ collectionStats: AugmentedRpc<(at?: Hash | string | Uint8Array) => Observable<UpDataStructsCollectionStats>>;
+ /**
+ * Get tokens contained within a collection
+ **/
+ collectionTokens: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<u32>>>;
+ /**
+ * Get token constant metadata
+ **/
+ constMetadata: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Bytes>>;
+ /**
+ * Get effective collection limits
+ **/
+ effectiveCollectionLimits: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsCollectionLimits>>>;
+ /**
+ * Get the last token ID created in a collection
+ **/
+ lastTokenId: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
+ /**
+ * Get the number of blocks until sponsoring a transaction is available
+ **/
+ nextSponsored: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<u64>>>;
+ /**
+ * Get property permissions, optionally limited to the provided keys
+ **/
+ propertyPermissions: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Option<Vec<Text>> | null | Uint8Array | Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsPropertyKeyPermission>>>;
+ /**
+ * Get tokens nested directly into the token
+ **/
+ tokenChildren: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsTokenChild>>>;
+ /**
+ * Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT
+ **/
+ tokenData: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Option<Vec<Text>> | null | Uint8Array | Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<UpDataStructsTokenData>>;
+ /**
+ * Check if the token exists
+ **/
+ tokenExists: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<bool>>;
+ /**
+ * Get the token owner
+ **/
+ tokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+ /**
+ * Returns 10 tokens owners in no particular order
+ **/
+ tokenOwners: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+ /**
+ * Get token properties, optionally limited to the provided keys
+ **/
+ tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Option<Vec<Text>> | null | Uint8Array | Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
+ /**
+ * Get the topmost token owner in the hierarchy of a possibly nested token
+ **/
+ topmostTokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+ /**
+ * Get the total amount of pieces of an RFT
+ **/
+ totalPieces: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<u128>>>;
+ /**
+ * Get the amount of distinctive tokens present in a collection
+ **/
+ totalSupply: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
+ /**
+ * Get token variable metadata
+ **/
+ variableMetadata: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Bytes>>;
+ };
+ web3: {
+ /**
+ * Returns current client version.
+ **/
+ clientVersion: AugmentedRpc<() => Observable<Text>>;
+ /**
+ * Returns sha3 of the given data
+ **/
+ sha3: AugmentedRpc<(data: Bytes | string | Uint8Array) => Observable<H256>>;
+ };
+ } // RpcInterface
+} // declare module
js-packages/types/augment-api-runtime.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-runtime.ts
@@ -0,0 +1,264 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/api-base/types/calls';
+
+import type { ApiTypes, AugmentedCall, DecoratedCallBase } from '@polkadot/api-base/types';
+import type { Bytes, Null, Option, Result, U256, Vec, bool, u256, u32, u64 } from '@polkadot/types-codec';
+import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
+import type { CheckInherentsResult, InherentData } from '@polkadot/types/interfaces/blockbuilder';
+import type { BlockHash } from '@polkadot/types/interfaces/chain';
+import type { AuthorityId } from '@polkadot/types/interfaces/consensus';
+import type { CollationInfo } from '@polkadot/types/interfaces/cumulus';
+import type { BlockV2, EthReceiptV3, EthTransactionStatus, TransactionV2 } from '@polkadot/types/interfaces/eth';
+import type { EvmAccount, EvmCallInfoV2, EvmCreateInfoV2 } from '@polkadot/types/interfaces/evm';
+import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
+import type { OpaqueMetadata } from '@polkadot/types/interfaces/metadata';
+import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
+import type { AccountId, Balance, Block, H160, H256, Header, Index, KeyTypeId, Permill, SlotDuration, Weight } from '@polkadot/types/interfaces/runtime';
+import type { RuntimeVersion } from '@polkadot/types/interfaces/state';
+import type { ApplyExtrinsicResult, DispatchError } from '@polkadot/types/interfaces/system';
+import type { TransactionSource, TransactionValidity } from '@polkadot/types/interfaces/txqueue';
+import type { IExtrinsic, Observable } from '@polkadot/types/types';
+
+export type __AugmentedCall<ApiType extends ApiTypes> = AugmentedCall<ApiType>;
+export type __DecoratedCallBase<ApiType extends ApiTypes> = DecoratedCallBase<ApiType>;
+
+declare module '@polkadot/api-base/types/calls' {
+ interface AugmentedCalls<ApiType extends ApiTypes> {
+ /** 0xbc9d89904f5b923f/1 */
+ accountNonceApi: {
+ /**
+ * The API to query account nonce (aka transaction index)
+ **/
+ accountNonce: AugmentedCall<ApiType, (accountId: AccountId | string | Uint8Array) => Observable<Index>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xdd718d5cc53262d4/1 */
+ auraApi: {
+ /**
+ * Return the current set of authorities.
+ **/
+ authorities: AugmentedCall<ApiType, () => Observable<Vec<AuthorityId>>>;
+ /**
+ * Returns the slot duration for Aura.
+ **/
+ slotDuration: AugmentedCall<ApiType, () => Observable<SlotDuration>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0x40fe3ad401f8959a/6 */
+ blockBuilder: {
+ /**
+ * Apply the given extrinsic.
+ **/
+ applyExtrinsic: AugmentedCall<ApiType, (extrinsic: Extrinsic | IExtrinsic | string | Uint8Array) => Observable<ApplyExtrinsicResult>>;
+ /**
+ * Check that the inherents are valid.
+ **/
+ checkInherents: AugmentedCall<ApiType, (block: Block | { header?: any; extrinsics?: any } | string | Uint8Array, data: InherentData | { data?: any } | string | Uint8Array) => Observable<CheckInherentsResult>>;
+ /**
+ * Finish the current block.
+ **/
+ finalizeBlock: AugmentedCall<ApiType, () => Observable<Header>>;
+ /**
+ * Generate inherent extrinsics.
+ **/
+ inherentExtrinsics: AugmentedCall<ApiType, (inherent: InherentData | { data?: any } | string | Uint8Array) => Observable<Vec<Extrinsic>>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xea93e3f16f3d6962/2 */
+ collectCollationInfo: {
+ /**
+ * Collect information about a collation.
+ **/
+ collectCollationInfo: AugmentedCall<ApiType, (header: Header | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array) => Observable<CollationInfo>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xe65b00e46cedd0aa/2 */
+ convertTransactionRuntimeApi: {
+ /**
+ * Converts an Ethereum-style transaction to Extrinsic
+ **/
+ convertTransaction: AugmentedCall<ApiType, (transaction: TransactionV2 | { Legacy: any } | { EIP2930: any } | { EIP1559: any } | string | Uint8Array) => Observable<Extrinsic>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xdf6acb689907609b/4 */
+ core: {
+ /**
+ * Execute the given block.
+ **/
+ executeBlock: AugmentedCall<ApiType, (block: Block | { header?: any; extrinsics?: any } | string | Uint8Array) => Observable<Null>>;
+ /**
+ * Initialize a block with the given header.
+ **/
+ initializeBlock: AugmentedCall<ApiType, (header: Header | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array) => Observable<Null>>;
+ /**
+ * Returns the version of the runtime.
+ **/
+ version: AugmentedCall<ApiType, () => Observable<RuntimeVersion>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0x582211f65bb14b89/5 */
+ ethereumRuntimeRPCApi: {
+ /**
+ * Returns pallet_evm::Accounts by address.
+ **/
+ accountBasic: AugmentedCall<ApiType, (address: H160 | string | Uint8Array) => Observable<EvmAccount>>;
+ /**
+ * For a given account address, returns pallet_evm::AccountCodes.
+ **/
+ accountCodeAt: AugmentedCall<ApiType, (address: H160 | string | Uint8Array) => Observable<Bytes>>;
+ /**
+ * Returns the converted FindAuthor::find_author authority id.
+ **/
+ author: AugmentedCall<ApiType, () => Observable<H160>>;
+ /**
+ * Returns a frame_ethereum::call response. If `estimate` is true,
+ **/
+ call: AugmentedCall<ApiType, (from: H160 | string | Uint8Array, to: H160 | string | Uint8Array, data: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: U256 | AnyNumber | Uint8Array, maxFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, estimate: bool | boolean | Uint8Array, accessList: Option<Vec<ITuple<[H160, Vec<H256>]>>> | null | Uint8Array | Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => Observable<Result<EvmCallInfoV2, DispatchError>>>;
+ /**
+ * Returns runtime defined pallet_evm::ChainId.
+ **/
+ chainId: AugmentedCall<ApiType, () => Observable<u64>>;
+ /**
+ * Returns a frame_ethereum::call response. If `estimate` is true,
+ **/
+ create: AugmentedCall<ApiType, (from: H160 | string | Uint8Array, data: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: U256 | AnyNumber | Uint8Array, maxFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, estimate: bool | boolean | Uint8Array, accessList: Option<Vec<ITuple<[H160, Vec<H256>]>>> | null | Uint8Array | Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => Observable<Result<EvmCreateInfoV2, DispatchError>>>;
+ /**
+ * Return all the current data for a block in a single runtime call.
+ **/
+ currentAll: AugmentedCall<ApiType, () => Observable<ITuple<[Option<BlockV2>, Option<Vec<EthReceiptV3>>, Option<Vec<EthTransactionStatus>>]>>>;
+ /**
+ * Return the current block.
+ **/
+ currentBlock: AugmentedCall<ApiType, () => Observable<BlockV2>>;
+ /**
+ * Return the current receipt.
+ **/
+ currentReceipts: AugmentedCall<ApiType, () => Observable<Option<Vec<EthReceiptV3>>>>;
+ /**
+ * Return the current transaction status.
+ **/
+ currentTransactionStatuses: AugmentedCall<ApiType, () => Observable<Option<Vec<EthTransactionStatus>>>>;
+ /**
+ * Return the elasticity multiplier.
+ **/
+ elasticity: AugmentedCall<ApiType, () => Observable<Option<Permill>>>;
+ /**
+ * Receives a `Vec<OpaqueExtrinsic>` and filters all the ethereum transactions.
+ **/
+ extrinsicFilter: AugmentedCall<ApiType, (xts: Vec<Extrinsic> | (Extrinsic | IExtrinsic | string | Uint8Array)[]) => Observable<Vec<TransactionV2>>>;
+ /**
+ * Returns FixedGasPrice::min_gas_price
+ **/
+ gasPrice: AugmentedCall<ApiType, () => Observable<u256>>;
+ /**
+ * For a given account address and index, returns pallet_evm::AccountStorages.
+ **/
+ storageAt: AugmentedCall<ApiType, (address: H160 | string | Uint8Array, index: u256 | AnyNumber | Uint8Array) => Observable<H256>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0x37e397fc7c91f5e4/2 */
+ metadata: {
+ /**
+ * Returns the metadata of a runtime
+ **/
+ metadata: AugmentedCall<ApiType, () => Observable<OpaqueMetadata>>;
+ /**
+ * Returns the metadata at a given version.
+ **/
+ metadataAtVersion: AugmentedCall<ApiType, (version: u32 | AnyNumber | Uint8Array) => Observable<Option<OpaqueMetadata>>>;
+ /**
+ * Returns the supported metadata versions.
+ **/
+ metadataVersions: AugmentedCall<ApiType, () => Observable<Vec<u32>>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xf78b278be53f454c/2 */
+ offchainWorkerApi: {
+ /**
+ * Starts the off-chain task for given block header.
+ **/
+ offchainWorker: AugmentedCall<ApiType, (header: Header | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array) => Observable<Null>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xab3c0572291feb8b/1 */
+ sessionKeys: {
+ /**
+ * Decode the given public session keys.
+ **/
+ decodeSessionKeys: AugmentedCall<ApiType, (encoded: Bytes | string | Uint8Array) => Observable<Option<Vec<ITuple<[Bytes, KeyTypeId]>>>>>;
+ /**
+ * Generate a set of session keys with optionally using the given seed.
+ **/
+ generateSessionKeys: AugmentedCall<ApiType, (seed: Option<Bytes> | null | Uint8Array | Bytes | string) => Observable<Bytes>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0xd2bc9897eed08f15/3 */
+ taggedTransactionQueue: {
+ /**
+ * Validate the transaction.
+ **/
+ validateTransaction: AugmentedCall<ApiType, (source: TransactionSource | 'InBlock' | 'Local' | 'External' | number | Uint8Array, tx: Extrinsic | IExtrinsic | string | Uint8Array, blockHash: BlockHash | string | Uint8Array) => Observable<TransactionValidity>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ /** 0x37c8bb1350a9a2a8/4 */
+ transactionPaymentApi: {
+ /**
+ * The transaction fee details
+ **/
+ queryFeeDetails: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<FeeDetails>>;
+ /**
+ * The transaction info
+ **/
+ queryInfo: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<RuntimeDispatchInfo>>;
+ /**
+ * Query the output of the current LengthToFee given some input
+ **/
+ queryLengthToFee: AugmentedCall<ApiType, (length: u32 | AnyNumber | Uint8Array) => Observable<Balance>>;
+ /**
+ * Query the output of the current WeightToFee given some input
+ **/
+ queryWeightToFee: AugmentedCall<ApiType, (weight: Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => Observable<Balance>>;
+ /**
+ * Generic call
+ **/
+ [key: string]: DecoratedCallBase<ApiType>;
+ };
+ } // AugmentedCalls
+} // declare module
js-packages/types/augment-api-tx.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api-tx.ts
@@ -0,0 +1,1250 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/api-base/types/submittable';
+
+import type { ApiTypes, AugmentedSubmittable, SubmittableExtrinsic, SubmittableExtrinsicFunction } from '@polkadot/api-base/types';
+import type { Data } from '@polkadot/types';
+import type { Bytes, Compact, Option, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { AnyNumber, IMethod, ITuple } from '@polkadot/types-codec/types';
+import type { AccountId32, Call, H160, H256, MultiAddress } from '@polkadot/types/interfaces/runtime';
+import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumLog, EthereumTransactionTransactionV2, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime, OpalRuntimeOriginCaller, OpalRuntimeRuntimeCommonSessionKeys, OrmlVestingVestingSchedule, PalletConfigurationAppPromotionConfiguration, PalletDemocracyConviction, PalletDemocracyMetadataOwner, PalletDemocracyVoteAccountVote, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletIdentityBitFlags, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletIdentityRegistration, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletStateTrieMigrationProgress, SpWeightsWeightV2Weight, StagingXcmV3MultiLocation, StagingXcmV3WeightLimit, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation, StagingXcmVersionedXcm, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission } from '@polkadot/types/lookup';
+
+export type __AugmentedSubmittable = AugmentedSubmittable<() => unknown>;
+export type __SubmittableExtrinsic<ApiType extends ApiTypes> = SubmittableExtrinsic<ApiType>;
+export type __SubmittableExtrinsicFunction<ApiType extends ApiTypes> = SubmittableExtrinsicFunction<ApiType>;
+
+declare module '@polkadot/api-base/types/submittable' {
+ interface AugmentedSubmittables<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * See [`Pallet::force_unstake`].
+ **/
+ forceUnstake: AugmentedSubmittable<(pendingBlocks: Vec<u32> | (u32 | AnyNumber | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<u32>]>;
+ /**
+ * See [`Pallet::payout_stakers`].
+ **/
+ payoutStakers: AugmentedSubmittable<(stakersNumber: Option<u8> | null | Uint8Array | u8 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u8>]>;
+ /**
+ * See [`Pallet::set_admin_address`].
+ **/
+ setAdminAddress: AugmentedSubmittable<(admin: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * See [`Pallet::sponsor_collection`].
+ **/
+ sponsorCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::sponsor_contract`].
+ **/
+ sponsorContract: AugmentedSubmittable<(contractId: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
+ /**
+ * See [`Pallet::stake`].
+ **/
+ stake: AugmentedSubmittable<(amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u128]>;
+ /**
+ * See [`Pallet::stop_sponsoring_collection`].
+ **/
+ stopSponsoringCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::stop_sponsoring_contract`].
+ **/
+ stopSponsoringContract: AugmentedSubmittable<(contractId: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
+ /**
+ * See [`Pallet::unstake_all`].
+ **/
+ unstakeAll: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::unstake_partial`].
+ **/
+ unstakePartial: AugmentedSubmittable<(amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u128]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ balances: {
+ /**
+ * See [`Pallet::force_set_balance`].
+ **/
+ forceSetBalance: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, newFree: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
+ /**
+ * See [`Pallet::force_transfer`].
+ **/
+ forceTransfer: AugmentedSubmittable<(source: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress, Compact<u128>]>;
+ /**
+ * See [`Pallet::force_unreserve`].
+ **/
+ forceUnreserve: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, u128]>;
+ /**
+ * See [`Pallet::set_balance_deprecated`].
+ **/
+ setBalanceDeprecated: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, newFree: Compact<u128> | AnyNumber | Uint8Array, oldReserved: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>, Compact<u128>]>;
+ /**
+ * See [`Pallet::transfer`].
+ **/
+ transfer: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
+ /**
+ * See [`Pallet::transfer_all`].
+ **/
+ transferAll: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, keepAlive: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, bool]>;
+ /**
+ * See [`Pallet::transfer_allow_death`].
+ **/
+ transferAllowDeath: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
+ /**
+ * See [`Pallet::transfer_keep_alive`].
+ **/
+ transferKeepAlive: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
+ /**
+ * See [`Pallet::upgrade_accounts`].
+ **/
+ upgradeAccounts: AugmentedSubmittable<(who: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ collatorSelection: {
+ /**
+ * See [`Pallet::add_invulnerable`].
+ **/
+ addInvulnerable: AugmentedSubmittable<(updated: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
+ /**
+ * See [`Pallet::force_release_license`].
+ **/
+ forceReleaseLicense: AugmentedSubmittable<(who: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
+ /**
+ * See [`Pallet::get_license`].
+ **/
+ getLicense: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::offboard`].
+ **/
+ offboard: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::onboard`].
+ **/
+ onboard: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::release_license`].
+ **/
+ releaseLicense: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::remove_invulnerable`].
+ **/
+ removeInvulnerable: AugmentedSubmittable<(who: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ configuration: {
+ /**
+ * See [`Pallet::set_app_promotion_configuration_override`].
+ **/
+ setAppPromotionConfigurationOverride: AugmentedSubmittable<(configuration: PalletConfigurationAppPromotionConfiguration | { recalculationInterval?: any; pendingInterval?: any; intervalIncome?: any; maxStakersPerCalculation?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletConfigurationAppPromotionConfiguration]>;
+ /**
+ * See [`Pallet::set_collator_selection_desired_collators`].
+ **/
+ setCollatorSelectionDesiredCollators: AugmentedSubmittable<(max: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
+ /**
+ * See [`Pallet::set_collator_selection_kick_threshold`].
+ **/
+ setCollatorSelectionKickThreshold: AugmentedSubmittable<(threshold: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
+ /**
+ * See [`Pallet::set_collator_selection_license_bond`].
+ **/
+ setCollatorSelectionLicenseBond: AugmentedSubmittable<(amount: Option<u128> | null | Uint8Array | u128 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u128>]>;
+ /**
+ * See [`Pallet::set_min_gas_price_override`].
+ **/
+ setMinGasPriceOverride: AugmentedSubmittable<(coeff: Option<u64> | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u64>]>;
+ /**
+ * See [`Pallet::set_weight_to_fee_coefficient_override`].
+ **/
+ setWeightToFeeCoefficientOverride: AugmentedSubmittable<(coeff: Option<u64> | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u64>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ council: {
+ /**
+ * See [`Pallet::close`].
+ **/
+ close: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, proposalWeightBound: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, SpWeightsWeightV2Weight, Compact<u32>]>;
+ /**
+ * See [`Pallet::disapprove_proposal`].
+ **/
+ disapproveProposal: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
+ /**
+ * See [`Pallet::execute`].
+ **/
+ execute: AugmentedSubmittable<(proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, Compact<u32>]>;
+ /**
+ * See [`Pallet::propose`].
+ **/
+ propose: AugmentedSubmittable<(threshold: Compact<u32> | AnyNumber | Uint8Array, proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Call, Compact<u32>]>;
+ /**
+ * See [`Pallet::set_members`].
+ **/
+ setMembers: AugmentedSubmittable<(newMembers: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[], prime: Option<AccountId32> | null | Uint8Array | AccountId32 | string, oldCount: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>, Option<AccountId32>, u32]>;
+ /**
+ * See [`Pallet::vote`].
+ **/
+ vote: AugmentedSubmittable<(proposal: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, bool]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ councilMembership: {
+ /**
+ * See [`Pallet::add_member`].
+ **/
+ addMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::change_key`].
+ **/
+ changeKey: AugmentedSubmittable<(updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::clear_prime`].
+ **/
+ clearPrime: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::remove_member`].
+ **/
+ removeMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::reset_members`].
+ **/
+ resetMembers: AugmentedSubmittable<(members: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
+ /**
+ * See [`Pallet::set_prime`].
+ **/
+ setPrime: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::swap_member`].
+ **/
+ swapMember: AugmentedSubmittable<(remove: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, add: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ cumulusXcm: {
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ democracy: {
+ /**
+ * See [`Pallet::blacklist`].
+ **/
+ blacklist: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, maybeRefIndex: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [H256, Option<u32>]>;
+ /**
+ * See [`Pallet::cancel_proposal`].
+ **/
+ cancelProposal: AugmentedSubmittable<(propIndex: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
+ /**
+ * See [`Pallet::cancel_referendum`].
+ **/
+ cancelReferendum: AugmentedSubmittable<(refIndex: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
+ /**
+ * See [`Pallet::clear_public_proposals`].
+ **/
+ clearPublicProposals: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::delegate`].
+ **/
+ delegate: AugmentedSubmittable<(to: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, conviction: PalletDemocracyConviction | 'None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x' | 'Locked6x' | number | Uint8Array, balance: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletDemocracyConviction, u128]>;
+ /**
+ * See [`Pallet::emergency_cancel`].
+ **/
+ emergencyCancel: AugmentedSubmittable<(refIndex: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::external_propose`].
+ **/
+ externalPropose: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded]>;
+ /**
+ * See [`Pallet::external_propose_default`].
+ **/
+ externalProposeDefault: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded]>;
+ /**
+ * See [`Pallet::external_propose_majority`].
+ **/
+ externalProposeMajority: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded]>;
+ /**
+ * See [`Pallet::fast_track`].
+ **/
+ fastTrack: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, votingPeriod: u32 | AnyNumber | Uint8Array, delay: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, u32, u32]>;
+ /**
+ * See [`Pallet::propose`].
+ **/
+ propose: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded, Compact<u128>]>;
+ /**
+ * See [`Pallet::remove_other_vote`].
+ **/
+ removeOtherVote: AugmentedSubmittable<(target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, u32]>;
+ /**
+ * See [`Pallet::remove_vote`].
+ **/
+ removeVote: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::second`].
+ **/
+ second: AugmentedSubmittable<(proposal: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
+ /**
+ * See [`Pallet::set_metadata`].
+ **/
+ setMetadata: AugmentedSubmittable<(owner: PalletDemocracyMetadataOwner | { External: any } | { Proposal: any } | { Referendum: any } | string | Uint8Array, maybeHash: Option<H256> | null | Uint8Array | H256 | string) => SubmittableExtrinsic<ApiType>, [PalletDemocracyMetadataOwner, Option<H256>]>;
+ /**
+ * See [`Pallet::undelegate`].
+ **/
+ undelegate: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::unlock`].
+ **/
+ unlock: AugmentedSubmittable<(target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::veto_external`].
+ **/
+ vetoExternal: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
+ /**
+ * See [`Pallet::vote`].
+ **/
+ vote: AugmentedSubmittable<(refIndex: Compact<u32> | AnyNumber | Uint8Array, vote: PalletDemocracyVoteAccountVote | { Standard: any } | { Split: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, PalletDemocracyVoteAccountVote]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ dmpQueue: {
+ /**
+ * See [`Pallet::service_overweight`].
+ **/
+ serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u64, SpWeightsWeightV2Weight]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ ethereum: {
+ /**
+ * See [`Pallet::transact`].
+ **/
+ transact: AugmentedSubmittable<(transaction: EthereumTransactionTransactionV2 | { Legacy: any } | { EIP2930: any } | { EIP1559: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [EthereumTransactionTransactionV2]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ evm: {
+ /**
+ * See [`Pallet::call`].
+ **/
+ call: AugmentedSubmittable<(source: H160 | string | Uint8Array, target: H160 | string | Uint8Array, input: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: u64 | AnyNumber | Uint8Array, maxFeePerGas: U256 | AnyNumber | Uint8Array, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, accessList: Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => SubmittableExtrinsic<ApiType>, [H160, H160, Bytes, U256, u64, U256, Option<U256>, Option<U256>, Vec<ITuple<[H160, Vec<H256>]>>]>;
+ /**
+ * See [`Pallet::create`].
+ **/
+ create: AugmentedSubmittable<(source: H160 | string | Uint8Array, init: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: u64 | AnyNumber | Uint8Array, maxFeePerGas: U256 | AnyNumber | Uint8Array, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, accessList: Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => SubmittableExtrinsic<ApiType>, [H160, Bytes, U256, u64, U256, Option<U256>, Option<U256>, Vec<ITuple<[H160, Vec<H256>]>>]>;
+ /**
+ * See [`Pallet::create2`].
+ **/
+ create2: AugmentedSubmittable<(source: H160 | string | Uint8Array, init: Bytes | string | Uint8Array, salt: H256 | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: u64 | AnyNumber | Uint8Array, maxFeePerGas: U256 | AnyNumber | Uint8Array, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, accessList: Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => SubmittableExtrinsic<ApiType>, [H160, Bytes, H256, U256, u64, U256, Option<U256>, Option<U256>, Vec<ITuple<[H160, Vec<H256>]>>]>;
+ /**
+ * See [`Pallet::withdraw`].
+ **/
+ withdraw: AugmentedSubmittable<(address: H160 | string | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160, u128]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ evmContractHelpers: {
+ /**
+ * See [`Pallet::migrate_from_self_sponsoring`].
+ **/
+ migrateFromSelfSponsoring: AugmentedSubmittable<(addresses: Vec<H160> | (H160 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<H160>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ evmMigration: {
+ /**
+ * See [`Pallet::begin`].
+ **/
+ begin: AugmentedSubmittable<(address: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
+ /**
+ * See [`Pallet::finish`].
+ **/
+ finish: AugmentedSubmittable<(address: H160 | string | Uint8Array, code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160, Bytes]>;
+ /**
+ * See [`Pallet::insert_eth_logs`].
+ **/
+ insertEthLogs: AugmentedSubmittable<(logs: Vec<EthereumLog> | (EthereumLog | { address?: any; topics?: any; data?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<EthereumLog>]>;
+ /**
+ * See [`Pallet::insert_events`].
+ **/
+ insertEvents: AugmentedSubmittable<(events: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>]>;
+ /**
+ * See [`Pallet::remove_rmrk_data`].
+ **/
+ removeRmrkData: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::set_data`].
+ **/
+ setData: AugmentedSubmittable<(address: H160 | string | Uint8Array, data: Vec<ITuple<[H256, H256]>> | ([H256 | string | Uint8Array, H256 | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [H160, Vec<ITuple<[H256, H256]>>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ fellowshipCollective: {
+ /**
+ * See [`Pallet::add_member`].
+ **/
+ addMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::cleanup_poll`].
+ **/
+ cleanupPoll: AugmentedSubmittable<(pollIndex: u32 | AnyNumber | Uint8Array, max: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
+ /**
+ * See [`Pallet::demote_member`].
+ **/
+ demoteMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::promote_member`].
+ **/
+ promoteMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::remove_member`].
+ **/
+ removeMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, minRank: u16 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, u16]>;
+ /**
+ * See [`Pallet::vote`].
+ **/
+ vote: AugmentedSubmittable<(poll: u32 | AnyNumber | Uint8Array, aye: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ fellowshipReferenda: {
+ /**
+ * See [`Pallet::cancel`].
+ **/
+ cancel: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::kill`].
+ **/
+ kill: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::nudge_referendum`].
+ **/
+ nudgeReferendum: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::one_fewer_deciding`].
+ **/
+ oneFewerDeciding: AugmentedSubmittable<(track: u16 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u16]>;
+ /**
+ * See [`Pallet::place_decision_deposit`].
+ **/
+ placeDecisionDeposit: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::refund_decision_deposit`].
+ **/
+ refundDecisionDeposit: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::refund_submission_deposit`].
+ **/
+ refundSubmissionDeposit: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::set_metadata`].
+ **/
+ setMetadata: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array, maybeHash: Option<H256> | null | Uint8Array | H256 | string) => SubmittableExtrinsic<ApiType>, [u32, Option<H256>]>;
+ /**
+ * See [`Pallet::submit`].
+ **/
+ submit: AugmentedSubmittable<(proposalOrigin: OpalRuntimeOriginCaller | { system: any } | { Void: any } | { Council: any } | { TechnicalCommittee: any } | { PolkadotXcm: any } | { CumulusXcm: any } | { Origins: any } | { Ethereum: any } | string | Uint8Array, proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array, enactmentMoment: FrameSupportScheduleDispatchTime | { At: any } | { After: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [OpalRuntimeOriginCaller, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ foreignAssets: {
+ /**
+ * See [`Pallet::register_foreign_asset`].
+ **/
+ registerForeignAsset: AugmentedSubmittable<(owner: AccountId32 | string | Uint8Array, location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, metadata: PalletForeignAssetsModuleAssetMetadata | { name?: any; symbol?: any; decimals?: any; minimalBalance?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32, StagingXcmVersionedMultiLocation, PalletForeignAssetsModuleAssetMetadata]>;
+ /**
+ * See [`Pallet::update_foreign_asset`].
+ **/
+ updateForeignAsset: AugmentedSubmittable<(foreignAssetId: u32 | AnyNumber | Uint8Array, location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, metadata: PalletForeignAssetsModuleAssetMetadata | { name?: any; symbol?: any; decimals?: any; minimalBalance?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, StagingXcmVersionedMultiLocation, PalletForeignAssetsModuleAssetMetadata]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ identity: {
+ /**
+ * See [`Pallet::add_registrar`].
+ **/
+ addRegistrar: AugmentedSubmittable<(account: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::add_sub`].
+ **/
+ addSub: AugmentedSubmittable<(sub: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, data: Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Data]>;
+ /**
+ * See [`Pallet::cancel_request`].
+ **/
+ cancelRequest: AugmentedSubmittable<(regIndex: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::clear_identity`].
+ **/
+ clearIdentity: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::force_insert_identities`].
+ **/
+ forceInsertIdentities: AugmentedSubmittable<(identities: Vec<ITuple<[AccountId32, PalletIdentityRegistration]>> | ([AccountId32 | string | Uint8Array, PalletIdentityRegistration | { judgements?: any; deposit?: any; info?: any } | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[AccountId32, PalletIdentityRegistration]>>]>;
+ /**
+ * See [`Pallet::force_remove_identities`].
+ **/
+ forceRemoveIdentities: AugmentedSubmittable<(identities: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
+ /**
+ * See [`Pallet::force_set_subs`].
+ **/
+ forceSetSubs: AugmentedSubmittable<(subs: Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>> | ([AccountId32 | string | Uint8Array, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]> | [u128 | AnyNumber | Uint8Array, Vec<ITuple<[AccountId32, Data]>> | ([AccountId32 | string | Uint8Array, Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array])[]]])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>>]>;
+ /**
+ * See [`Pallet::kill_identity`].
+ **/
+ killIdentity: AugmentedSubmittable<(target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::provide_judgement`].
+ **/
+ provideJudgement: AugmentedSubmittable<(regIndex: Compact<u32> | AnyNumber | Uint8Array, target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, judgement: PalletIdentityJudgement | { Unknown: any } | { FeePaid: any } | { Reasonable: any } | { KnownGood: any } | { OutOfDate: any } | { LowQuality: any } | { Erroneous: any } | string | Uint8Array, identity: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, MultiAddress, PalletIdentityJudgement, H256]>;
+ /**
+ * See [`Pallet::quit_sub`].
+ **/
+ quitSub: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::remove_sub`].
+ **/
+ removeSub: AugmentedSubmittable<(sub: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::rename_sub`].
+ **/
+ renameSub: AugmentedSubmittable<(sub: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, data: Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Data]>;
+ /**
+ * See [`Pallet::request_judgement`].
+ **/
+ requestJudgement: AugmentedSubmittable<(regIndex: Compact<u32> | AnyNumber | Uint8Array, maxFee: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Compact<u128>]>;
+ /**
+ * See [`Pallet::set_account_id`].
+ **/
+ setAccountId: AugmentedSubmittable<(index: Compact<u32> | AnyNumber | Uint8Array, updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, MultiAddress]>;
+ /**
+ * See [`Pallet::set_fee`].
+ **/
+ setFee: AugmentedSubmittable<(index: Compact<u32> | AnyNumber | Uint8Array, fee: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Compact<u128>]>;
+ /**
+ * See [`Pallet::set_fields`].
+ **/
+ setFields: AugmentedSubmittable<(index: Compact<u32> | AnyNumber | Uint8Array, fields: PalletIdentityBitFlags) => SubmittableExtrinsic<ApiType>, [Compact<u32>, PalletIdentityBitFlags]>;
+ /**
+ * See [`Pallet::set_identity`].
+ **/
+ setIdentity: AugmentedSubmittable<(info: PalletIdentityIdentityInfo | { additional?: any; display?: any; legal?: any; web?: any; riot?: any; email?: any; pgpFingerprint?: any; image?: any; twitter?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletIdentityIdentityInfo]>;
+ /**
+ * See [`Pallet::set_subs`].
+ **/
+ setSubs: AugmentedSubmittable<(subs: Vec<ITuple<[AccountId32, Data]>> | ([AccountId32 | string | Uint8Array, Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[AccountId32, Data]>>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ inflation: {
+ /**
+ * See [`Pallet::start_inflation`].
+ **/
+ startInflation: AugmentedSubmittable<(inflationStartRelayBlock: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ maintenance: {
+ /**
+ * See [`Pallet::disable`].
+ **/
+ disable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::enable`].
+ **/
+ enable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ parachainInfo: {
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ parachainSystem: {
+ /**
+ * See [`Pallet::authorize_upgrade`].
+ **/
+ authorizeUpgrade: AugmentedSubmittable<(codeHash: H256 | string | Uint8Array, checkVersion: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, bool]>;
+ /**
+ * See [`Pallet::enact_authorized_upgrade`].
+ **/
+ enactAuthorizedUpgrade: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * See [`Pallet::set_validation_data`].
+ **/
+ setValidationData: AugmentedSubmittable<(data: CumulusPrimitivesParachainInherentParachainInherentData | { validationData?: any; relayChainState?: any; downwardMessages?: any; horizontalMessages?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [CumulusPrimitivesParachainInherentParachainInherentData]>;
+ /**
+ * See [`Pallet::sudo_send_upward_message`].
+ **/
+ sudoSendUpwardMessage: AugmentedSubmittable<(message: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ polkadotXcm: {
+ /**
+ * See [`Pallet::execute`].
+ **/
+ execute: AugmentedSubmittable<(message: StagingXcmVersionedXcm | { V2: any } | { V3: any } | string | Uint8Array, maxWeight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedXcm, SpWeightsWeightV2Weight]>;
+ /**
+ * See [`Pallet::force_default_xcm_version`].
+ **/
+ forceDefaultXcmVersion: AugmentedSubmittable<(maybeXcmVersion: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
+ /**
+ * See [`Pallet::force_subscribe_version_notify`].
+ **/
+ forceSubscribeVersionNotify: AugmentedSubmittable<(location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation]>;
+ /**
+ * See [`Pallet::force_suspension`].
+ **/
+ forceSuspension: AugmentedSubmittable<(suspended: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [bool]>;
+ /**
+ * See [`Pallet::force_unsubscribe_version_notify`].
+ **/
+ forceUnsubscribeVersionNotify: AugmentedSubmittable<(location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation]>;
+ /**
+ * See [`Pallet::force_xcm_version`].
+ **/
+ forceXcmVersion: AugmentedSubmittable<(location: StagingXcmV3MultiLocation | { parents?: any; interior?: any } | string | Uint8Array, version: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmV3MultiLocation, u32]>;
+ /**
+ * See [`Pallet::limited_reserve_transfer_assets`].
+ **/
+ limitedReserveTransferAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array, weightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::limited_teleport_assets`].
+ **/
+ limitedTeleportAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array, weightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::reserve_transfer_assets`].
+ **/
+ reserveTransferAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32]>;
+ /**
+ * See [`Pallet::send`].
+ **/
+ send: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, message: StagingXcmVersionedXcm | { V2: any } | { V3: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedXcm]>;
+ /**
+ * See [`Pallet::teleport_assets`].
+ **/
+ teleportAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ preimage: {
+ /**
+ * See [`Pallet::note_preimage`].
+ **/
+ notePreimage: AugmentedSubmittable<(bytes: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * See [`Pallet::request_preimage`].
+ **/
+ requestPreimage: AugmentedSubmittable<(hash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
+ /**
+ * See [`Pallet::unnote_preimage`].
+ **/
+ unnotePreimage: AugmentedSubmittable<(hash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
+ /**
+ * See [`Pallet::unrequest_preimage`].
+ **/
+ unrequestPreimage: AugmentedSubmittable<(hash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ scheduler: {
+ /**
+ * See [`Pallet::cancel`].
+ **/
+ cancel: AugmentedSubmittable<(when: u32 | AnyNumber | Uint8Array, index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
+ /**
+ * See [`Pallet::cancel_named`].
+ **/
+ cancelNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed]>;
+ /**
+ * See [`Pallet::schedule`].
+ **/
+ schedule: AugmentedSubmittable<(when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
+ /**
+ * See [`Pallet::schedule_after`].
+ **/
+ scheduleAfter: AugmentedSubmittable<(after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
+ /**
+ * See [`Pallet::schedule_named`].
+ **/
+ scheduleNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
+ /**
+ * See [`Pallet::schedule_named_after`].
+ **/
+ scheduleNamedAfter: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ session: {
+ /**
+ * See [`Pallet::purge_keys`].
+ **/
+ purgeKeys: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::set_keys`].
+ **/
+ setKeys: AugmentedSubmittable<(keys: OpalRuntimeRuntimeCommonSessionKeys | { aura?: any } | string | Uint8Array, proof: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [OpalRuntimeRuntimeCommonSessionKeys, Bytes]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ stateTrieMigration: {
+ /**
+ * See [`Pallet::continue_migrate`].
+ **/
+ continueMigrate: AugmentedSubmittable<(limits: PalletStateTrieMigrationMigrationLimits | { size_?: any; item?: any } | string | Uint8Array, realSizeUpper: u32 | AnyNumber | Uint8Array, witnessTask: PalletStateTrieMigrationMigrationTask | { progressTop?: any; progressChild?: any; size_?: any; topItems?: any; childItems?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletStateTrieMigrationMigrationLimits, u32, PalletStateTrieMigrationMigrationTask]>;
+ /**
+ * See [`Pallet::control_auto_migration`].
+ **/
+ controlAutoMigration: AugmentedSubmittable<(maybeConfig: Option<PalletStateTrieMigrationMigrationLimits> | null | Uint8Array | PalletStateTrieMigrationMigrationLimits | { size_?: any; item?: any } | string) => SubmittableExtrinsic<ApiType>, [Option<PalletStateTrieMigrationMigrationLimits>]>;
+ /**
+ * See [`Pallet::force_set_progress`].
+ **/
+ forceSetProgress: AugmentedSubmittable<(progressTop: PalletStateTrieMigrationProgress | { ToStart: any } | { LastKey: any } | { Complete: any } | string | Uint8Array, progressChild: PalletStateTrieMigrationProgress | { ToStart: any } | { LastKey: any } | { Complete: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletStateTrieMigrationProgress, PalletStateTrieMigrationProgress]>;
+ /**
+ * See [`Pallet::migrate_custom_child`].
+ **/
+ migrateCustomChild: AugmentedSubmittable<(root: Bytes | string | Uint8Array, childKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[], totalSize: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes, Vec<Bytes>, u32]>;
+ /**
+ * See [`Pallet::migrate_custom_top`].
+ **/
+ migrateCustomTop: AugmentedSubmittable<(keys: Vec<Bytes> | (Bytes | string | Uint8Array)[], witnessSize: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>, u32]>;
+ /**
+ * See [`Pallet::set_signed_max_limits`].
+ **/
+ setSignedMaxLimits: AugmentedSubmittable<(limits: PalletStateTrieMigrationMigrationLimits | { size_?: any; item?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletStateTrieMigrationMigrationLimits]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ structure: {
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ sudo: {
+ /**
+ * See [`Pallet::set_key`].
+ **/
+ setKey: AugmentedSubmittable<(updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::sudo`].
+ **/
+ sudo: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call]>;
+ /**
+ * See [`Pallet::sudo_as`].
+ **/
+ sudoAs: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Call]>;
+ /**
+ * See [`Pallet::sudo_unchecked_weight`].
+ **/
+ sudoUncheckedWeight: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array, weight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, SpWeightsWeightV2Weight]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ system: {
+ /**
+ * See [`Pallet::kill_prefix`].
+ **/
+ killPrefix: AugmentedSubmittable<(prefix: Bytes | string | Uint8Array, subkeys: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes, u32]>;
+ /**
+ * See [`Pallet::kill_storage`].
+ **/
+ killStorage: AugmentedSubmittable<(keys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>]>;
+ /**
+ * See [`Pallet::remark`].
+ **/
+ remark: AugmentedSubmittable<(remark: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * See [`Pallet::remark_with_event`].
+ **/
+ remarkWithEvent: AugmentedSubmittable<(remark: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * See [`Pallet::set_code`].
+ **/
+ setCode: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * See [`Pallet::set_code_without_checks`].
+ **/
+ setCodeWithoutChecks: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
+ /**
+ * See [`Pallet::set_heap_pages`].
+ **/
+ setHeapPages: AugmentedSubmittable<(pages: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u64]>;
+ /**
+ * See [`Pallet::set_storage`].
+ **/
+ setStorage: AugmentedSubmittable<(items: Vec<ITuple<[Bytes, Bytes]>> | ([Bytes | string | Uint8Array, Bytes | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[Bytes, Bytes]>>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ technicalCommittee: {
+ /**
+ * See [`Pallet::close`].
+ **/
+ close: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, proposalWeightBound: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, SpWeightsWeightV2Weight, Compact<u32>]>;
+ /**
+ * See [`Pallet::disapprove_proposal`].
+ **/
+ disapproveProposal: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
+ /**
+ * See [`Pallet::execute`].
+ **/
+ execute: AugmentedSubmittable<(proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, Compact<u32>]>;
+ /**
+ * See [`Pallet::propose`].
+ **/
+ propose: AugmentedSubmittable<(threshold: Compact<u32> | AnyNumber | Uint8Array, proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Call, Compact<u32>]>;
+ /**
+ * See [`Pallet::set_members`].
+ **/
+ setMembers: AugmentedSubmittable<(newMembers: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[], prime: Option<AccountId32> | null | Uint8Array | AccountId32 | string, oldCount: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>, Option<AccountId32>, u32]>;
+ /**
+ * See [`Pallet::vote`].
+ **/
+ vote: AugmentedSubmittable<(proposal: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, bool]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ technicalCommitteeMembership: {
+ /**
+ * See [`Pallet::add_member`].
+ **/
+ addMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::change_key`].
+ **/
+ changeKey: AugmentedSubmittable<(updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::clear_prime`].
+ **/
+ clearPrime: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::remove_member`].
+ **/
+ removeMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::reset_members`].
+ **/
+ resetMembers: AugmentedSubmittable<(members: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
+ /**
+ * See [`Pallet::set_prime`].
+ **/
+ setPrime: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::swap_member`].
+ **/
+ swapMember: AugmentedSubmittable<(remove: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, add: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ testUtils: {
+ /**
+ * See `Pallet::batch_all`.
+ **/
+ batchAll: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
+ /**
+ * See `Pallet::enable`.
+ **/
+ enable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See `Pallet::inc_test_value`.
+ **/
+ incTestValue: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See `Pallet::just_take_fee`.
+ **/
+ justTakeFee: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See `Pallet::set_test_value`.
+ **/
+ setTestValue: AugmentedSubmittable<(value: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See `Pallet::set_test_value_and_rollback`.
+ **/
+ setTestValueAndRollback: AugmentedSubmittable<(value: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ timestamp: {
+ /**
+ * See [`Pallet::set`].
+ **/
+ set: AugmentedSubmittable<(now: Compact<u64> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u64>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ tokens: {
+ /**
+ * See [`Pallet::force_transfer`].
+ **/
+ forceTransfer: AugmentedSubmittable<(source: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress, PalletForeignAssetsAssetId, Compact<u128>]>;
+ /**
+ * See [`Pallet::set_balance`].
+ **/
+ setBalance: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, newFree: Compact<u128> | AnyNumber | Uint8Array, newReserved: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, Compact<u128>, Compact<u128>]>;
+ /**
+ * See [`Pallet::transfer`].
+ **/
+ transfer: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, Compact<u128>]>;
+ /**
+ * See [`Pallet::transfer_all`].
+ **/
+ transferAll: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, keepAlive: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, bool]>;
+ /**
+ * See [`Pallet::transfer_keep_alive`].
+ **/
+ transferKeepAlive: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, Compact<u128>]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ treasury: {
+ /**
+ * See [`Pallet::approve_proposal`].
+ **/
+ approveProposal: AugmentedSubmittable<(proposalId: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
+ /**
+ * See [`Pallet::propose_spend`].
+ **/
+ proposeSpend: AugmentedSubmittable<(value: Compact<u128> | AnyNumber | Uint8Array, beneficiary: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, MultiAddress]>;
+ /**
+ * See [`Pallet::reject_proposal`].
+ **/
+ rejectProposal: AugmentedSubmittable<(proposalId: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
+ /**
+ * See [`Pallet::remove_approval`].
+ **/
+ removeApproval: AugmentedSubmittable<(proposalId: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
+ /**
+ * See [`Pallet::spend`].
+ **/
+ spend: AugmentedSubmittable<(amount: Compact<u128> | AnyNumber | Uint8Array, beneficiary: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, MultiAddress]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ unique: {
+ /**
+ * See [`Pallet::add_collection_admin`].
+ **/
+ addCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newAdminId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * See [`Pallet::add_to_allow_list`].
+ **/
+ addToAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * See [`Pallet::approve`].
+ **/
+ approve: AugmentedSubmittable<(spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
+ /**
+ * See [`Pallet::approve_from`].
+ **/
+ approveFrom: AugmentedSubmittable<(from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, to: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
+ /**
+ * See [`Pallet::burn_from`].
+ **/
+ burnFrom: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32, u128]>;
+ /**
+ * See [`Pallet::burn_item`].
+ **/
+ burnItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
+ /**
+ * See [`Pallet::change_collection_owner`].
+ **/
+ changeCollectionOwner: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newOwner: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
+ /**
+ * See [`Pallet::confirm_sponsorship`].
+ **/
+ confirmSponsorship: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::create_collection`].
+ **/
+ createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;
+ /**
+ * See [`Pallet::create_collection_ex`].
+ **/
+ createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; limits?: any; permissions?: any; tokenPropertyPermissions?: any; properties?: any; adminList?: any; pendingSponsor?: any; flags?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
+ /**
+ * See [`Pallet::create_item`].
+ **/
+ createItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, data: UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCreateItemData]>;
+ /**
+ * See [`Pallet::create_multiple_items`].
+ **/
+ createMultipleItems: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemsData: Vec<UpDataStructsCreateItemData> | (UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, Vec<UpDataStructsCreateItemData>]>;
+ /**
+ * See [`Pallet::create_multiple_items_ex`].
+ **/
+ createMultipleItemsEx: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, data: UpDataStructsCreateItemExData | { NFT: any } | { Fungible: any } | { RefungibleMultipleItems: any } | { RefungibleMultipleOwners: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCreateItemExData]>;
+ /**
+ * See [`Pallet::delete_collection_properties`].
+ **/
+ deleteCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<Bytes>]>;
+ /**
+ * See [`Pallet::delete_token_properties`].
+ **/
+ deleteTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<Bytes>]>;
+ /**
+ * See [`Pallet::destroy_collection`].
+ **/
+ destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::force_repair_collection`].
+ **/
+ forceRepairCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::force_repair_item`].
+ **/
+ forceRepairItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
+ /**
+ * See [`Pallet::remove_collection_admin`].
+ **/
+ removeCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, accountId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * See [`Pallet::remove_collection_sponsor`].
+ **/
+ removeCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::remove_from_allow_list`].
+ **/
+ removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ /**
+ * See [`Pallet::repartition`].
+ **/
+ repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
+ /**
+ * See [`Pallet::set_allowance_for_all`].
+ **/
+ setAllowanceForAll: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
+ /**
+ * See [`Pallet::set_collection_limits`].
+ **/
+ setCollectionLimits: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newLimit: UpDataStructsCollectionLimits | { accountTokenOwnershipLimit?: any; sponsoredDataSize?: any; sponsoredDataRateLimit?: any; tokenLimit?: any; sponsorTransferTimeout?: any; sponsorApproveTimeout?: any; ownerCanTransfer?: any; ownerCanDestroy?: any; transfersEnabled?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionLimits]>;
+ /**
+ * See [`Pallet::set_collection_permissions`].
+ **/
+ setCollectionPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newPermission: UpDataStructsCollectionPermissions | { access?: any; mintMode?: any; nesting?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionPermissions]>;
+ /**
+ * See [`Pallet::set_collection_properties`].
+ **/
+ setCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsProperty>]>;
+ /**
+ * See [`Pallet::set_collection_sponsor`].
+ **/
+ setCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newSponsor: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
+ /**
+ * See [`Pallet::set_token_properties`].
+ **/
+ setTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<UpDataStructsProperty>]>;
+ /**
+ * See [`Pallet::set_token_property_permissions`].
+ **/
+ setTokenPropertyPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyPermissions: Vec<UpDataStructsPropertyKeyPermission> | (UpDataStructsPropertyKeyPermission | { key?: any; permission?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsPropertyKeyPermission>]>;
+ /**
+ * See [`Pallet::set_transfers_enabled_flag`].
+ **/
+ setTransfersEnabledFlag: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, value: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
+ /**
+ * See [`Pallet::transfer`].
+ **/
+ transfer: AugmentedSubmittable<(recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
+ /**
+ * See [`Pallet::transfer_from`].
+ **/
+ transferFrom: AugmentedSubmittable<(from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ utility: {
+ /**
+ * See [`Pallet::as_derivative`].
+ **/
+ asDerivative: AugmentedSubmittable<(index: u16 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u16, Call]>;
+ /**
+ * See [`Pallet::batch`].
+ **/
+ batch: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
+ /**
+ * See [`Pallet::batch_all`].
+ **/
+ batchAll: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
+ /**
+ * See [`Pallet::dispatch_as`].
+ **/
+ dispatchAs: AugmentedSubmittable<(asOrigin: OpalRuntimeOriginCaller | { system: any } | { Void: any } | { Council: any } | { TechnicalCommittee: any } | { PolkadotXcm: any } | { CumulusXcm: any } | { Origins: any } | { Ethereum: any } | string | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [OpalRuntimeOriginCaller, Call]>;
+ /**
+ * See [`Pallet::force_batch`].
+ **/
+ forceBatch: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
+ /**
+ * See [`Pallet::with_weight`].
+ **/
+ withWeight: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array, weight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, SpWeightsWeightV2Weight]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ vesting: {
+ /**
+ * See [`Pallet::claim`].
+ **/
+ claim: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::claim_for`].
+ **/
+ claimFor: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
+ /**
+ * See [`Pallet::update_vesting_schedules`].
+ **/
+ updateVestingSchedules: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, vestingSchedules: Vec<OrmlVestingVestingSchedule> | (OrmlVestingVestingSchedule | { start?: any; period?: any; periodCount?: any; perPeriod?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [MultiAddress, Vec<OrmlVestingVestingSchedule>]>;
+ /**
+ * See [`Pallet::vested_transfer`].
+ **/
+ vestedTransfer: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, schedule: OrmlVestingVestingSchedule | { start?: any; period?: any; periodCount?: any; perPeriod?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, OrmlVestingVestingSchedule]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ xcmpQueue: {
+ /**
+ * See [`Pallet::resume_xcm_execution`].
+ **/
+ resumeXcmExecution: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::service_overweight`].
+ **/
+ serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u64, SpWeightsWeightV2Weight]>;
+ /**
+ * See [`Pallet::suspend_xcm_execution`].
+ **/
+ suspendXcmExecution: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * See [`Pallet::update_drop_threshold`].
+ **/
+ updateDropThreshold: AugmentedSubmittable<(updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::update_resume_threshold`].
+ **/
+ updateResumeThreshold: AugmentedSubmittable<(updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::update_suspend_threshold`].
+ **/
+ updateSuspendThreshold: AugmentedSubmittable<(updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ /**
+ * See [`Pallet::update_threshold_weight`].
+ **/
+ updateThresholdWeight: AugmentedSubmittable<(updated: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [SpWeightsWeightV2Weight]>;
+ /**
+ * See [`Pallet::update_weight_restrict_decay`].
+ **/
+ updateWeightRestrictDecay: AugmentedSubmittable<(updated: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [SpWeightsWeightV2Weight]>;
+ /**
+ * See [`Pallet::update_xcmp_max_individual_weight`].
+ **/
+ updateXcmpMaxIndividualWeight: AugmentedSubmittable<(updated: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [SpWeightsWeightV2Weight]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ xTokens: {
+ /**
+ * See [`Pallet::transfer`].
+ **/
+ transfer: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletForeignAssetsAssetId, u128, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::transfer_multiasset`].
+ **/
+ transferMultiasset: AugmentedSubmittable<(asset: StagingXcmVersionedMultiAsset | { V2: any } | { V3: any } | string | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::transfer_multiassets`].
+ **/
+ transferMultiassets: AugmentedSubmittable<(assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeItem: u32 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiAssets, u32, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::transfer_multiasset_with_fee`].
+ **/
+ transferMultiassetWithFee: AugmentedSubmittable<(asset: StagingXcmVersionedMultiAsset | { V2: any } | { V3: any } | string | Uint8Array, fee: StagingXcmVersionedMultiAsset | { V2: any } | { V3: any } | string | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::transfer_multicurrencies`].
+ **/
+ transferMulticurrencies: AugmentedSubmittable<(currencies: Vec<ITuple<[PalletForeignAssetsAssetId, u128]>> | ([PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, u128 | AnyNumber | Uint8Array])[], feeItem: u32 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[PalletForeignAssetsAssetId, u128]>>, u32, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
+ /**
+ * See [`Pallet::transfer_with_fee`].
+ **/
+ transferWithFee: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, fee: u128 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletForeignAssetsAssetId, u128, u128, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
+ } // AugmentedSubmittables
+} // declare module
js-packages/types/augment-api.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-api.ts
@@ -0,0 +1,10 @@
+// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
+/* eslint-disable */
+
+import './augment-api-consts.js';
+import './augment-api-errors.js';
+import './augment-api-events.js';
+import './augment-api-query.js';
+import './augment-api-tx.js';
+import './augment-api-rpc.js';
+import './augment-api-runtime.js';
js-packages/types/augment-types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/augment-types.ts
@@ -0,0 +1,1587 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/types/types/registry';
+
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemCodeUpgradeAuthorization, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity, CumulusPalletParachainSystemUnincludedSegmentAncestor, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate, CumulusPalletParachainSystemUnincludedSegmentSegmentTracker, CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OpalRuntimeRuntimeCommonSessionKeys, OpalRuntimeRuntimeHoldReason, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesIdAmount, PalletBalancesReasons, PalletBalancesReserveData, PalletCollatorSelectionCall, PalletCollatorSelectionError, PalletCollatorSelectionEvent, PalletCollatorSelectionHoldReason, PalletCollectiveCall, PalletCollectiveError, PalletCollectiveEvent, PalletCollectiveRawOrigin, PalletCollectiveVotes, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletConfigurationEvent, PalletDemocracyCall, PalletDemocracyConviction, PalletDemocracyDelegations, PalletDemocracyError, PalletDemocracyEvent, PalletDemocracyMetadataOwner, PalletDemocracyReferendumInfo, PalletDemocracyReferendumStatus, PalletDemocracyTally, PalletDemocracyVoteAccountVote, PalletDemocracyVotePriorLock, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCodeMetadata, PalletEvmCoderSubstrateError, PalletEvmContractHelpersCall, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletGovOriginsOrigin, PalletIdentityBitFlags, PalletIdentityCall, PalletIdentityError, PalletIdentityEvent, PalletIdentityIdentityField, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletMembershipCall, PalletMembershipError, PalletMembershipEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletPreimageCall, PalletPreimageError, PalletPreimageEvent, PalletPreimageRequestStatus, PalletRankedCollectiveCall, PalletRankedCollectiveError, PalletRankedCollectiveEvent, PalletRankedCollectiveMemberRecord, PalletRankedCollectiveTally, PalletRankedCollectiveVoteRecord, PalletReferendaCall, PalletReferendaCurve, PalletReferendaDecidingStatus, PalletReferendaDeposit, PalletReferendaError, PalletReferendaEvent, PalletReferendaReferendumInfo, PalletReferendaReferendumStatus, PalletReferendaTrackInfo, PalletRefungibleError, PalletSchedulerCall, PalletSchedulerError, PalletSchedulerEvent, PalletSchedulerScheduled, PalletSessionCall, PalletSessionError, PalletSessionEvent, PalletStateTrieMigrationCall, PalletStateTrieMigrationError, PalletStateTrieMigrationEvent, PalletStateTrieMigrationMigrationCompute, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletStateTrieMigrationProgress, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUtilityCall, PalletUtilityError, PalletUtilityEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PalletXcmQueryStatus, PalletXcmRemoteLockedFungibleRecord, PalletXcmVersionMigrationStage, ParachainInfoCall, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat, PolkadotPrimitivesV5AbridgedHostConfiguration, PolkadotPrimitivesV5AbridgedHrmpChannel, PolkadotPrimitivesV5PersistedValidationData, PolkadotPrimitivesV5UpgradeGoAhead, PolkadotPrimitivesV5UpgradeRestriction, PolkadotPrimitivesVstagingAsyncBackingParams, SpArithmeticArithmeticError, SpConsensusAuraSr25519AppSr25519Public, SpCoreCryptoKeyTypeId, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Public, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, StagingXcmDoubleEncoded, StagingXcmV2BodyId, StagingXcmV2BodyPart, StagingXcmV2Instruction, StagingXcmV2Junction, StagingXcmV2MultiAsset, StagingXcmV2MultiLocation, StagingXcmV2MultiassetAssetId, StagingXcmV2MultiassetAssetInstance, StagingXcmV2MultiassetFungibility, StagingXcmV2MultiassetMultiAssetFilter, StagingXcmV2MultiassetMultiAssets, StagingXcmV2MultiassetWildFungibility, StagingXcmV2MultiassetWildMultiAsset, StagingXcmV2MultilocationJunctions, StagingXcmV2NetworkId, StagingXcmV2OriginKind, StagingXcmV2Response, StagingXcmV2TraitsError, StagingXcmV2WeightLimit, StagingXcmV2Xcm, StagingXcmV3Instruction, StagingXcmV3Junction, StagingXcmV3JunctionBodyId, StagingXcmV3JunctionBodyPart, StagingXcmV3JunctionNetworkId, StagingXcmV3Junctions, StagingXcmV3MaybeErrorCode, StagingXcmV3MultiAsset, StagingXcmV3MultiLocation, StagingXcmV3MultiassetAssetId, StagingXcmV3MultiassetAssetInstance, StagingXcmV3MultiassetFungibility, StagingXcmV3MultiassetMultiAssetFilter, StagingXcmV3MultiassetMultiAssets, StagingXcmV3MultiassetWildFungibility, StagingXcmV3MultiassetWildMultiAsset, StagingXcmV3PalletInfo, StagingXcmV3QueryResponseInfo, StagingXcmV3Response, StagingXcmV3TraitsError, StagingXcmV3TraitsOutcome, StagingXcmV3WeightLimit, StagingXcmV3Xcm, StagingXcmVersionedAssetId, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation, StagingXcmVersionedResponse, StagingXcmVersionedXcm, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue } from './default';
+import type { Data, StorageKey } from '@polkadot/types';
+import type { BitVec, Bool, Bytes, F32, F64, I128, I16, I256, I32, I64, I8, ISize, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, f32, f64, i128, i16, i256, i32, i64, i8, isize, 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';
+import type { BlockAttestations, IncludedBlocks, MoreAttestations } from '@polkadot/types/interfaces/attestations';
+import type { RawAuraPreDigest } from '@polkadot/types/interfaces/aura';
+import type { ExtrinsicOrHash, ExtrinsicStatus } from '@polkadot/types/interfaces/author';
+import type { UncleEntryItem } from '@polkadot/types/interfaces/authorship';
+import type { AllowedSlots, BabeAuthorityWeight, BabeBlockWeight, BabeEpochConfiguration, BabeEquivocationProof, BabeGenesisConfiguration, BabeGenesisConfigurationV1, BabeWeight, Epoch, EpochAuthorship, MaybeRandomness, MaybeVrf, NextConfigDescriptor, NextConfigDescriptorV1, OpaqueKeyOwnershipProof, Randomness, RawBabePreDigest, RawBabePreDigestCompat, RawBabePreDigestPrimary, RawBabePreDigestPrimaryTo159, RawBabePreDigestSecondaryPlain, RawBabePreDigestSecondaryTo159, RawBabePreDigestSecondaryVRF, RawBabePreDigestTo159, SlotNumber, VrfData, VrfOutput, VrfProof } from '@polkadot/types/interfaces/babe';
+import type { AccountData, BalanceLock, BalanceLockTo212, BalanceStatus, Reasons, ReserveData, ReserveIdentifier, VestingSchedule, WithdrawReasons } from '@polkadot/types/interfaces/balances';
+import type { BeefyAuthoritySet, BeefyCommitment, BeefyEquivocationProof, BeefyId, BeefyNextAuthoritySet, BeefyPayload, BeefyPayloadId, BeefySignedCommitment, BeefyVoteMessage, MmrRootHash, ValidatorSet, ValidatorSetId } from '@polkadot/types/interfaces/beefy';
+import type { BenchmarkBatch, BenchmarkConfig, BenchmarkList, BenchmarkMetadata, BenchmarkParameter, BenchmarkResult } from '@polkadot/types/interfaces/benchmark';
+import type { CheckInherentsResult, InherentData, InherentIdentifier } from '@polkadot/types/interfaces/blockbuilder';
+import type { BridgeMessageId, BridgedBlockHash, BridgedBlockNumber, BridgedHeader, CallOrigin, ChainId, DeliveredMessages, DispatchFeePayment, InboundLaneData, InboundRelayer, InitializationData, LaneId, MessageData, MessageKey, MessageNonce, MessagesDeliveryProofOf, MessagesProofOf, OperatingMode, OutboundLaneData, OutboundMessageFee, OutboundPayload, Parameter, RelayerId, UnrewardedRelayer, UnrewardedRelayersState } from '@polkadot/types/interfaces/bridges';
+import type { BlockHash } from '@polkadot/types/interfaces/chain';
+import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';
+import type { StatementKind } from '@polkadot/types/interfaces/claims';
+import type { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective';
+import type { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus';
+import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractExecResultU64, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractInstantiateResultU64, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts';
+import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractConstructorSpecV4, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEnvironmentV4, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMessageSpecV3, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractMetadataV4, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi';
+import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan';
+import type { CollationInfo, CollationInfoV1, ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus';
+import type { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy';
+import type { BlockStats } from '@polkadot/types/interfaces/dev';
+import type { ApprovalFlag, DefunctVoter, Renouncing, SetIndex, Vote, VoteIndex, VoteThreshold, VoterInfo } from '@polkadot/types/interfaces/elections';
+import type { CreatedBlock, ImportedAux } from '@polkadot/types/interfaces/engine';
+import type { BlockV0, BlockV1, BlockV2, EIP1559Transaction, EIP2930Transaction, EthAccessList, EthAccessListItem, EthAccount, EthAddress, EthBlock, EthBloom, EthCallRequest, EthFeeHistory, EthFilter, EthFilterAddress, EthFilterChanges, EthFilterTopic, EthFilterTopicEntry, EthFilterTopicInner, EthHeader, EthLog, EthReceipt, EthReceiptV0, EthReceiptV3, EthRichBlock, EthRichHeader, EthStorageProof, EthSubKind, EthSubParams, EthSubResult, EthSyncInfo, EthSyncStatus, EthTransaction, EthTransactionAction, EthTransactionCondition, EthTransactionRequest, EthTransactionSignature, EthTransactionStatus, EthWork, EthereumAccountId, EthereumAddress, EthereumLookupSource, EthereumSignature, LegacyTransaction, TransactionV0, TransactionV1, TransactionV2 } from '@polkadot/types/interfaces/eth';
+import type { EvmAccount, EvmCallInfo, EvmCallInfoV2, EvmCreateInfo, EvmCreateInfoV2, EvmLog, EvmVicinity, EvmWeightInfo, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed } from '@polkadot/types/interfaces/evm';
+import type { AnySignature, EcdsaSignature, Ed25519Signature, Era, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV4, ExtrinsicSignature, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV4, ImmortalEra, MortalEra, MultiSignature, Signature, SignerPayload, Sr25519Signature } from '@polkadot/types/interfaces/extrinsics';
+import type { FungiblesAccessError } from '@polkadot/types/interfaces/fungibles';
+import type { AssetOptions, Owner, PermissionLatest, PermissionVersions, PermissionsV1 } from '@polkadot/types/interfaces/genericAsset';
+import type { ActiveGilt, ActiveGiltsTotal, ActiveIndex, GiltBid } from '@polkadot/types/interfaces/gilt';
+import type { AuthorityIndex, AuthorityList, AuthoritySet, AuthoritySetChange, AuthoritySetChanges, AuthorityWeight, DelayKind, DelayKindBest, EncodedFinalityProofs, ForkTreePendingChange, ForkTreePendingChangeNode, GrandpaCommit, GrandpaEquivocation, GrandpaEquivocationProof, GrandpaEquivocationValue, GrandpaJustification, GrandpaPrecommit, GrandpaPrevote, GrandpaSignedPrecommit, JustificationNotification, KeyOwnerProof, NextAuthority, PendingChange, PendingPause, PendingResume, Precommits, Prevotes, ReportedRoundStates, RoundState, SetId, StoredPendingChange, StoredState } from '@polkadot/types/interfaces/grandpa';
+import type { IdentityFields, IdentityInfo, IdentityInfoAdditional, IdentityInfoTo198, IdentityJudgement, RegistrarIndex, RegistrarInfo, Registration, RegistrationJudgement, RegistrationTo198 } from '@polkadot/types/interfaces/identity';
+import type { AuthIndex, AuthoritySignature, Heartbeat, HeartbeatTo244, OpaqueMultiaddr, OpaqueNetworkState, OpaquePeerId } from '@polkadot/types/interfaces/imOnline';
+import type { CallIndex, LotteryConfig } from '@polkadot/types/interfaces/lottery';
+import type { CustomMetadata15, CustomValueMetadata15, ErrorMetadataLatest, ErrorMetadataV10, ErrorMetadataV11, ErrorMetadataV12, ErrorMetadataV13, ErrorMetadataV14, ErrorMetadataV9, EventMetadataLatest, EventMetadataV10, EventMetadataV11, EventMetadataV12, EventMetadataV13, EventMetadataV14, EventMetadataV9, ExtrinsicMetadataLatest, ExtrinsicMetadataV11, ExtrinsicMetadataV12, ExtrinsicMetadataV13, ExtrinsicMetadataV14, ExtrinsicMetadataV15, FunctionArgumentMetadataLatest, FunctionArgumentMetadataV10, FunctionArgumentMetadataV11, FunctionArgumentMetadataV12, FunctionArgumentMetadataV13, FunctionArgumentMetadataV14, FunctionArgumentMetadataV9, FunctionMetadataLatest, FunctionMetadataV10, FunctionMetadataV11, FunctionMetadataV12, FunctionMetadataV13, FunctionMetadataV14, FunctionMetadataV9, MetadataAll, MetadataLatest, MetadataV10, MetadataV11, MetadataV12, MetadataV13, MetadataV14, MetadataV15, MetadataV9, ModuleConstantMetadataV10, ModuleConstantMetadataV11, ModuleConstantMetadataV12, ModuleConstantMetadataV13, ModuleConstantMetadataV9, ModuleMetadataV10, ModuleMetadataV11, ModuleMetadataV12, ModuleMetadataV13, ModuleMetadataV9, OpaqueMetadata, OuterEnums15, PalletCallMetadataLatest, PalletCallMetadataV14, PalletConstantMetadataLatest, PalletConstantMetadataV14, PalletErrorMetadataLatest, PalletErrorMetadataV14, PalletEventMetadataLatest, PalletEventMetadataV14, PalletMetadataLatest, PalletMetadataV14, PalletMetadataV15, PalletStorageMetadataLatest, PalletStorageMetadataV14, PortableType, PortableTypeV14, RuntimeApiMetadataLatest, RuntimeApiMetadataV15, RuntimeApiMethodMetadataV15, RuntimeApiMethodParamMetadataV15, SignedExtensionMetadataLatest, SignedExtensionMetadataV14, StorageEntryMetadataLatest, StorageEntryMetadataV10, StorageEntryMetadataV11, StorageEntryMetadataV12, StorageEntryMetadataV13, StorageEntryMetadataV14, StorageEntryMetadataV9, StorageEntryModifierLatest, StorageEntryModifierV10, StorageEntryModifierV11, StorageEntryModifierV12, StorageEntryModifierV13, StorageEntryModifierV14, StorageEntryModifierV9, StorageEntryTypeLatest, StorageEntryTypeV10, StorageEntryTypeV11, StorageEntryTypeV12, StorageEntryTypeV13, StorageEntryTypeV14, StorageEntryTypeV9, StorageHasher, StorageHasherV10, StorageHasherV11, StorageHasherV12, StorageHasherV13, StorageHasherV14, StorageHasherV9, StorageMetadataV10, StorageMetadataV11, StorageMetadataV12, StorageMetadataV13, StorageMetadataV9 } from '@polkadot/types/interfaces/metadata';
+import type { MmrBatchProof, MmrEncodableOpaqueLeaf, MmrError, MmrHash, MmrLeafBatchProof, MmrLeafIndex, MmrLeafProof, MmrNodeIndex, MmrProof } from '@polkadot/types/interfaces/mmr';
+import type { NftCollectionId, NftItemId } from '@polkadot/types/interfaces/nfts';
+import type { NpApiError, NpPoolId } from '@polkadot/types/interfaces/nompools';
+import type { StorageKind } from '@polkadot/types/interfaces/offchain';
+import type { DeferredOffenceOf, Kind, OffenceDetails, Offender, OpaqueTimeSlot, ReportIdOf, Reporter } from '@polkadot/types/interfaces/offences';
+import type { AbridgedCandidateReceipt, AbridgedHostConfiguration, AbridgedHrmpChannel, AssignmentId, AssignmentKind, AttestedCandidate, AuctionIndex, AuthorityDiscoveryId, AvailabilityBitfield, AvailabilityBitfieldRecord, BackedCandidate, Bidder, BufferedSessionChange, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateInfo, CandidatePendingAvailability, CandidateReceipt, CollatorId, CollatorSignature, CommittedCandidateReceipt, CoreAssignment, CoreIndex, CoreOccupied, CoreState, DisputeLocation, DisputeProof, DisputeResult, DisputeState, DisputeStatement, DisputeStatementSet, DisputesTimeSlot, DoubleVoteReport, DownwardMessage, ExecutorParam, ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GlobalValidationData, GlobalValidationSchedule, GroupIndex, GroupRotationInfo, HeadData, HostConfiguration, HrmpChannel, HrmpChannelId, HrmpOpenChannelRequest, InboundDownwardMessage, InboundHrmpMessage, InboundHrmpMessages, IncomingParachain, IncomingParachainDeploy, IncomingParachainFixed, InvalidDisputeStatementKind, LeasePeriod, LeasePeriodOf, LocalValidationData, MessageIngestionType, MessageQueueChain, MessagingStateSnapshot, MessagingStateSnapshotEgressEntry, MultiDisputeStatementSet, NewBidder, OccupiedCore, OccupiedCoreAssumption, OldV1SessionInfo, OutboundHrmpMessage, ParaGenesisArgs, ParaId, ParaInfo, ParaLifecycle, ParaPastCodeMeta, ParaScheduling, ParaValidatorIndex, ParachainDispatchOrigin, ParachainInherentData, ParachainProposal, ParachainsInherentData, ParathreadClaim, ParathreadClaimQueue, ParathreadEntry, PendingSlashes, PersistedValidationData, PvfCheckStatement, PvfExecTimeoutKind, PvfPrepTimeoutKind, QueuedParathread, RegisteredParachainInfo, RelayBlockNumber, RelayChainBlockNumber, RelayChainHash, RelayHash, Remark, ReplacementTimes, Retriable, ScheduledCore, Scheduling, ScrapedOnChainVotes, ServiceQuality, SessionInfo, SessionInfoValidatorGroup, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, SlashingOffenceKind, SlotRange, SlotRange10, Statement, SubId, SystemInherentData, TransientValidationData, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidationData, ValidationDataType, ValidationFunctionParams, ValidatorSignature, ValidityAttestation, VecInboundHrmpMessage, WinnersData, WinnersData10, WinnersDataTuple, WinnersDataTuple10, WinningData, WinningData10, WinningDataEntry } from '@polkadot/types/interfaces/parachains';
+import type { FeeDetails, InclusionFee, RuntimeDispatchInfo, RuntimeDispatchInfoV1, RuntimeDispatchInfoV2 } from '@polkadot/types/interfaces/payment';
+import type { Approvals } from '@polkadot/types/interfaces/poll';
+import type { ProxyAnnouncement, ProxyDefinition, ProxyType } from '@polkadot/types/interfaces/proxy';
+import type { AccountStatus, AccountValidity } from '@polkadot/types/interfaces/purchase';
+import type { ActiveRecovery, RecoveryConfig } from '@polkadot/types/interfaces/recovery';
+import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
+import type { AccountId, AccountId20, AccountId32, AccountId33, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, BlockNumberFor, BlockNumberOf, Call, CallHash, CallHashOf, ChangesTrieConfiguration, ChangesTrieSignal, CodecHash, Consensus, ConsensusEngineId, CrateVersion, Digest, DigestItem, EncodedJustification, ExtrinsicsWeight, Fixed128, Fixed64, FixedI128, FixedI64, FixedU128, FixedU64, H1024, H128, H160, H2048, H256, H32, H512, H64, Hash, Header, HeaderPartial, I32F32, Index, IndicesLookupSource, Justification, Justifications, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, ModuleId, Moment, MultiAddress, MultiSigner, OpaqueCall, Origin, OriginCaller, PalletId, PalletVersion, PalletsOrigin, Pays, PerU16, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Releases, RuntimeCall, RuntimeDbWeight, RuntimeEvent, Seal, SealV0, SignedBlock, SignedBlockWithJustification, SignedBlockWithJustifications, Slot, SlotDuration, StorageData, StorageInfo, StorageProof, TransactionInfo, TransactionLongevity, TransactionPriority, TransactionStorageProof, TransactionTag, U32F32, ValidatorId, ValidatorIdOf, Weight, WeightMultiplier, WeightV0, WeightV1, WeightV2 } from '@polkadot/types/interfaces/runtime';
+import type { Si0Field, Si0LookupTypeId, Si0Path, Si0Type, Si0TypeDef, Si0TypeDefArray, Si0TypeDefBitSequence, Si0TypeDefCompact, Si0TypeDefComposite, Si0TypeDefPhantom, Si0TypeDefPrimitive, Si0TypeDefSequence, Si0TypeDefTuple, Si0TypeDefVariant, Si0TypeParameter, Si0Variant, Si1Field, Si1LookupTypeId, Si1Path, Si1Type, Si1TypeDef, Si1TypeDefArray, Si1TypeDefBitSequence, Si1TypeDefCompact, Si1TypeDefComposite, Si1TypeDefPrimitive, Si1TypeDefSequence, Si1TypeDefTuple, Si1TypeDefVariant, Si1TypeParameter, Si1Variant, SiField, SiLookupTypeId, SiPath, SiType, SiTypeDef, SiTypeDefArray, SiTypeDefBitSequence, SiTypeDefCompact, SiTypeDefComposite, SiTypeDefPrimitive, SiTypeDefSequence, SiTypeDefTuple, SiTypeDefVariant, SiTypeParameter, SiVariant } from '@polkadot/types/interfaces/scaleInfo';
+import type { Period, Priority, SchedulePeriod, SchedulePriority, Scheduled, ScheduledTo254, TaskAddress } from '@polkadot/types/interfaces/scheduler';
+import type { BeefyKey, FullIdentification, IdentificationTuple, Keys, MembershipProof, SessionIndex, SessionKeys1, SessionKeys10, SessionKeys10B, SessionKeys2, SessionKeys3, SessionKeys4, SessionKeys5, SessionKeys6, SessionKeys6B, SessionKeys7, SessionKeys7B, SessionKeys8, SessionKeys8B, SessionKeys9, SessionKeys9B, ValidatorCount } from '@polkadot/types/interfaces/session';
+import type { Bid, BidKind, SocietyJudgement, SocietyVote, StrikeCount, VouchingStatus } from '@polkadot/types/interfaces/society';
+import type { ActiveEraInfo, CompactAssignments, CompactAssignmentsTo257, CompactAssignmentsTo265, CompactAssignmentsWith16, CompactAssignmentsWith24, CompactScore, CompactScoreCompact, ElectionCompute, ElectionPhase, ElectionResult, ElectionScore, ElectionSize, ElectionStatus, EraIndex, EraPoints, EraRewardPoints, EraRewards, Exposure, ExtendedBalance, Forcing, IndividualExposure, KeyType, MomentOf, Nominations, NominatorIndex, NominatorIndexCompact, OffchainAccuracy, OffchainAccuracyCompact, PhragmenScore, Points, RawSolution, RawSolutionTo265, RawSolutionWith16, RawSolutionWith24, ReadySolution, RewardDestination, RewardPoint, RoundSnapshot, SeatHolder, SignedSubmission, SignedSubmissionOf, SignedSubmissionTo276, SlashJournalEntry, SlashingSpans, SlashingSpansTo204, SolutionOrSnapshotSize, SolutionSupport, SolutionSupports, SpanIndex, SpanRecord, StakingLedger, StakingLedgerTo223, StakingLedgerTo240, SubmissionIndicesOf, Supports, UnappliedSlash, UnappliedSlashOther, UnlockChunk, ValidatorIndex, ValidatorIndexCompact, ValidatorPrefs, ValidatorPrefsTo145, ValidatorPrefsTo196, ValidatorPrefsWithBlocked, ValidatorPrefsWithCommission, VoteWeight, Voter } from '@polkadot/types/interfaces/staking';
+import type { ApiId, BlockTrace, BlockTraceEvent, BlockTraceEventData, BlockTraceSpan, KeyValueOption, MigrationStatusResult, ReadProof, RuntimeVersion, RuntimeVersionApi, RuntimeVersionPartial, RuntimeVersionPre3, RuntimeVersionPre4, SpecVersion, StorageChangeSet, TraceBlockResponse, TraceError } from '@polkadot/types/interfaces/state';
+import type { WeightToFeeCoefficient } from '@polkadot/types/interfaces/support';
+import type { AccountInfo, AccountInfoWithDualRefCount, AccountInfoWithProviders, AccountInfoWithRefCount, AccountInfoWithRefCountU8, AccountInfoWithTripleRefCount, ApplyExtrinsicResult, ApplyExtrinsicResultPre6, ArithmeticError, BlockLength, BlockWeights, ChainProperties, ChainType, ConsumedWeight, DigestOf, DispatchClass, DispatchError, DispatchErrorModule, DispatchErrorModulePre6, DispatchErrorModuleU8, DispatchErrorModuleU8a, DispatchErrorPre6, DispatchErrorPre6First, DispatchErrorTo198, DispatchInfo, DispatchInfoTo190, DispatchInfoTo244, DispatchOutcome, DispatchOutcomePre6, DispatchResult, DispatchResultOf, DispatchResultTo198, Event, EventId, EventIndex, EventRecord, Health, InvalidTransaction, Key, LastRuntimeUpgradeInfo, NetworkState, NetworkStatePeerset, NetworkStatePeersetInfo, NodeRole, NotConnectedPeer, Peer, PeerEndpoint, PeerEndpointAddr, PeerInfo, PeerPing, PerDispatchClassU32, PerDispatchClassWeight, PerDispatchClassWeightsPerClass, Phase, RawOrigin, RefCount, RefCountTo259, SyncState, SystemOrigin, TokenError, TransactionValidityError, TransactionalError, UnknownTransaction, WeightPerClass } from '@polkadot/types/interfaces/system';
+import type { Bounty, BountyIndex, BountyStatus, BountyStatusActive, BountyStatusCuratorProposed, BountyStatusPendingPayout, OpenTip, OpenTipFinderTo225, OpenTipTip, OpenTipTo225, TreasuryProposal } from '@polkadot/types/interfaces/treasury';
+import type { Multiplier } from '@polkadot/types/interfaces/txpayment';
+import type { TransactionSource, TransactionValidity, ValidTransaction } from '@polkadot/types/interfaces/txqueue';
+import type { ClassDetails, ClassId, ClassMetadata, DepositBalance, DepositBalanceOf, DestroyWitness, InstanceDetails, InstanceId, InstanceMetadata } from '@polkadot/types/interfaces/uniques';
+import type { Multisig, Timepoint } from '@polkadot/types/interfaces/utility';
+import type { VestingInfo } from '@polkadot/types/interfaces/vesting';
+import type { AssetInstance, AssetInstanceV0, AssetInstanceV1, AssetInstanceV2, BodyId, BodyPart, DoubleEncodedCall, Fungibility, FungibilityV0, FungibilityV1, FungibilityV2, InboundStatus, InstructionV2, InteriorMultiLocation, Junction, JunctionV0, JunctionV1, JunctionV2, Junctions, JunctionsV1, JunctionsV2, MultiAsset, MultiAssetFilter, MultiAssetFilterV1, MultiAssetFilterV2, MultiAssetV0, MultiAssetV1, MultiAssetV2, MultiAssets, MultiAssetsV1, MultiAssetsV2, MultiLocation, MultiLocationV0, MultiLocationV1, MultiLocationV2, NetworkId, OriginKindV0, OriginKindV1, OriginKindV2, OutboundStatus, Outcome, QueryId, QueryStatus, QueueConfigData, Response, ResponseV0, ResponseV1, ResponseV2, ResponseV2Error, ResponseV2Result, VersionMigrationStage, VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, VersionedResponse, VersionedXcm, WeightLimitV2, WildFungibility, WildFungibilityV0, WildFungibilityV1, WildFungibilityV2, WildMultiAsset, WildMultiAssetV1, WildMultiAssetV2, Xcm, XcmAssetId, XcmError, XcmErrorV0, XcmErrorV1, XcmErrorV2, XcmOrder, XcmOrderV0, XcmOrderV1, XcmOrderV2, XcmOrigin, XcmOriginKind, XcmV0, XcmV1, XcmV2, XcmVersion, XcmpMessageFormat } from '@polkadot/types/interfaces/xcm';
+
+declare module '@polkadot/types/types/registry' {
+ interface InterfaceTypes {
+ AbridgedCandidateReceipt: AbridgedCandidateReceipt;
+ AbridgedHostConfiguration: AbridgedHostConfiguration;
+ AbridgedHrmpChannel: AbridgedHrmpChannel;
+ AccountData: AccountData;
+ AccountId: AccountId;
+ AccountId20: AccountId20;
+ AccountId32: AccountId32;
+ AccountId33: AccountId33;
+ AccountIdOf: AccountIdOf;
+ AccountIndex: AccountIndex;
+ AccountInfo: AccountInfo;
+ AccountInfoWithDualRefCount: AccountInfoWithDualRefCount;
+ AccountInfoWithProviders: AccountInfoWithProviders;
+ AccountInfoWithRefCount: AccountInfoWithRefCount;
+ AccountInfoWithRefCountU8: AccountInfoWithRefCountU8;
+ AccountInfoWithTripleRefCount: AccountInfoWithTripleRefCount;
+ AccountStatus: AccountStatus;
+ AccountValidity: AccountValidity;
+ AccountVote: AccountVote;
+ AccountVoteSplit: AccountVoteSplit;
+ AccountVoteStandard: AccountVoteStandard;
+ ActiveEraInfo: ActiveEraInfo;
+ ActiveGilt: ActiveGilt;
+ ActiveGiltsTotal: ActiveGiltsTotal;
+ ActiveIndex: ActiveIndex;
+ ActiveRecovery: ActiveRecovery;
+ Address: Address;
+ AliveContractInfo: AliveContractInfo;
+ AllowedSlots: AllowedSlots;
+ AnySignature: AnySignature;
+ ApiId: ApiId;
+ ApplyExtrinsicResult: ApplyExtrinsicResult;
+ ApplyExtrinsicResultPre6: ApplyExtrinsicResultPre6;
+ ApprovalFlag: ApprovalFlag;
+ Approvals: Approvals;
+ ArithmeticError: ArithmeticError;
+ AssetApproval: AssetApproval;
+ AssetApprovalKey: AssetApprovalKey;
+ AssetBalance: AssetBalance;
+ AssetDestroyWitness: AssetDestroyWitness;
+ AssetDetails: AssetDetails;
+ AssetId: AssetId;
+ AssetInstance: AssetInstance;
+ AssetInstanceV0: AssetInstanceV0;
+ AssetInstanceV1: AssetInstanceV1;
+ AssetInstanceV2: AssetInstanceV2;
+ AssetMetadata: AssetMetadata;
+ AssetOptions: AssetOptions;
+ AssignmentId: AssignmentId;
+ AssignmentKind: AssignmentKind;
+ AttestedCandidate: AttestedCandidate;
+ AuctionIndex: AuctionIndex;
+ AuthIndex: AuthIndex;
+ AuthorityDiscoveryId: AuthorityDiscoveryId;
+ AuthorityId: AuthorityId;
+ AuthorityIndex: AuthorityIndex;
+ AuthorityList: AuthorityList;
+ AuthoritySet: AuthoritySet;
+ AuthoritySetChange: AuthoritySetChange;
+ AuthoritySetChanges: AuthoritySetChanges;
+ AuthoritySignature: AuthoritySignature;
+ AuthorityWeight: AuthorityWeight;
+ AvailabilityBitfield: AvailabilityBitfield;
+ AvailabilityBitfieldRecord: AvailabilityBitfieldRecord;
+ BabeAuthorityWeight: BabeAuthorityWeight;
+ BabeBlockWeight: BabeBlockWeight;
+ BabeEpochConfiguration: BabeEpochConfiguration;
+ BabeEquivocationProof: BabeEquivocationProof;
+ BabeGenesisConfiguration: BabeGenesisConfiguration;
+ BabeGenesisConfigurationV1: BabeGenesisConfigurationV1;
+ BabeWeight: BabeWeight;
+ BackedCandidate: BackedCandidate;
+ Balance: Balance;
+ BalanceLock: BalanceLock;
+ BalanceLockTo212: BalanceLockTo212;
+ BalanceOf: BalanceOf;
+ BalanceStatus: BalanceStatus;
+ BeefyAuthoritySet: BeefyAuthoritySet;
+ BeefyCommitment: BeefyCommitment;
+ BeefyEquivocationProof: BeefyEquivocationProof;
+ BeefyId: BeefyId;
+ BeefyKey: BeefyKey;
+ BeefyNextAuthoritySet: BeefyNextAuthoritySet;
+ BeefyPayload: BeefyPayload;
+ BeefyPayloadId: BeefyPayloadId;
+ BeefySignedCommitment: BeefySignedCommitment;
+ BeefyVoteMessage: BeefyVoteMessage;
+ BenchmarkBatch: BenchmarkBatch;
+ BenchmarkConfig: BenchmarkConfig;
+ BenchmarkList: BenchmarkList;
+ BenchmarkMetadata: BenchmarkMetadata;
+ BenchmarkParameter: BenchmarkParameter;
+ BenchmarkResult: BenchmarkResult;
+ Bid: Bid;
+ Bidder: Bidder;
+ BidKind: BidKind;
+ BitVec: BitVec;
+ Block: Block;
+ BlockAttestations: BlockAttestations;
+ BlockHash: BlockHash;
+ BlockLength: BlockLength;
+ BlockNumber: BlockNumber;
+ BlockNumberFor: BlockNumberFor;
+ BlockNumberOf: BlockNumberOf;
+ BlockStats: BlockStats;
+ BlockTrace: BlockTrace;
+ BlockTraceEvent: BlockTraceEvent;
+ BlockTraceEventData: BlockTraceEventData;
+ BlockTraceSpan: BlockTraceSpan;
+ BlockV0: BlockV0;
+ BlockV1: BlockV1;
+ BlockV2: BlockV2;
+ BlockWeights: BlockWeights;
+ BodyId: BodyId;
+ BodyPart: BodyPart;
+ bool: bool;
+ Bool: Bool;
+ Bounty: Bounty;
+ BountyIndex: BountyIndex;
+ BountyStatus: BountyStatus;
+ BountyStatusActive: BountyStatusActive;
+ BountyStatusCuratorProposed: BountyStatusCuratorProposed;
+ BountyStatusPendingPayout: BountyStatusPendingPayout;
+ BridgedBlockHash: BridgedBlockHash;
+ BridgedBlockNumber: BridgedBlockNumber;
+ BridgedHeader: BridgedHeader;
+ BridgeMessageId: BridgeMessageId;
+ BufferedSessionChange: BufferedSessionChange;
+ Bytes: Bytes;
+ Call: Call;
+ CallHash: CallHash;
+ CallHashOf: CallHashOf;
+ CallIndex: CallIndex;
+ CallOrigin: CallOrigin;
+ CandidateCommitments: CandidateCommitments;
+ CandidateDescriptor: CandidateDescriptor;
+ CandidateEvent: CandidateEvent;
+ CandidateHash: CandidateHash;
+ CandidateInfo: CandidateInfo;
+ CandidatePendingAvailability: CandidatePendingAvailability;
+ CandidateReceipt: CandidateReceipt;
+ ChainId: ChainId;
+ ChainProperties: ChainProperties;
+ ChainType: ChainType;
+ ChangesTrieConfiguration: ChangesTrieConfiguration;
+ ChangesTrieSignal: ChangesTrieSignal;
+ CheckInherentsResult: CheckInherentsResult;
+ ClassDetails: ClassDetails;
+ ClassId: ClassId;
+ ClassMetadata: ClassMetadata;
+ CodecHash: CodecHash;
+ CodeHash: CodeHash;
+ CodeSource: CodeSource;
+ CodeUploadRequest: CodeUploadRequest;
+ CodeUploadResult: CodeUploadResult;
+ CodeUploadResultValue: CodeUploadResultValue;
+ CollationInfo: CollationInfo;
+ CollationInfoV1: CollationInfoV1;
+ CollatorId: CollatorId;
+ CollatorSignature: CollatorSignature;
+ CollectiveOrigin: CollectiveOrigin;
+ CommittedCandidateReceipt: CommittedCandidateReceipt;
+ CompactAssignments: CompactAssignments;
+ CompactAssignmentsTo257: CompactAssignmentsTo257;
+ CompactAssignmentsTo265: CompactAssignmentsTo265;
+ CompactAssignmentsWith16: CompactAssignmentsWith16;
+ CompactAssignmentsWith24: CompactAssignmentsWith24;
+ CompactScore: CompactScore;
+ CompactScoreCompact: CompactScoreCompact;
+ ConfigData: ConfigData;
+ Consensus: Consensus;
+ ConsensusEngineId: ConsensusEngineId;
+ ConsumedWeight: ConsumedWeight;
+ ContractCallFlags: ContractCallFlags;
+ ContractCallRequest: ContractCallRequest;
+ ContractConstructorSpecLatest: ContractConstructorSpecLatest;
+ ContractConstructorSpecV0: ContractConstructorSpecV0;
+ ContractConstructorSpecV1: ContractConstructorSpecV1;
+ ContractConstructorSpecV2: ContractConstructorSpecV2;
+ ContractConstructorSpecV3: ContractConstructorSpecV3;
+ ContractConstructorSpecV4: ContractConstructorSpecV4;
+ ContractContractSpecV0: ContractContractSpecV0;
+ ContractContractSpecV1: ContractContractSpecV1;
+ ContractContractSpecV2: ContractContractSpecV2;
+ ContractContractSpecV3: ContractContractSpecV3;
+ ContractContractSpecV4: ContractContractSpecV4;
+ ContractCryptoHasher: ContractCryptoHasher;
+ ContractDiscriminant: ContractDiscriminant;
+ ContractDisplayName: ContractDisplayName;
+ ContractEnvironmentV4: ContractEnvironmentV4;
+ ContractEventParamSpecLatest: ContractEventParamSpecLatest;
+ ContractEventParamSpecV0: ContractEventParamSpecV0;
+ ContractEventParamSpecV2: ContractEventParamSpecV2;
+ ContractEventSpecLatest: ContractEventSpecLatest;
+ ContractEventSpecV0: ContractEventSpecV0;
+ ContractEventSpecV1: ContractEventSpecV1;
+ ContractEventSpecV2: ContractEventSpecV2;
+ ContractExecResult: ContractExecResult;
+ ContractExecResultOk: ContractExecResultOk;
+ ContractExecResultResult: ContractExecResultResult;
+ ContractExecResultSuccessTo255: ContractExecResultSuccessTo255;
+ ContractExecResultSuccessTo260: ContractExecResultSuccessTo260;
+ ContractExecResultTo255: ContractExecResultTo255;
+ ContractExecResultTo260: ContractExecResultTo260;
+ ContractExecResultTo267: ContractExecResultTo267;
+ ContractExecResultU64: ContractExecResultU64;
+ ContractInfo: ContractInfo;
+ ContractInstantiateResult: ContractInstantiateResult;
+ ContractInstantiateResultTo267: ContractInstantiateResultTo267;
+ ContractInstantiateResultTo299: ContractInstantiateResultTo299;
+ ContractInstantiateResultU64: ContractInstantiateResultU64;
+ ContractLayoutArray: ContractLayoutArray;
+ ContractLayoutCell: ContractLayoutCell;
+ ContractLayoutEnum: ContractLayoutEnum;
+ ContractLayoutHash: ContractLayoutHash;
+ ContractLayoutHashingStrategy: ContractLayoutHashingStrategy;
+ ContractLayoutKey: ContractLayoutKey;
+ ContractLayoutStruct: ContractLayoutStruct;
+ ContractLayoutStructField: ContractLayoutStructField;
+ ContractMessageParamSpecLatest: ContractMessageParamSpecLatest;
+ ContractMessageParamSpecV0: ContractMessageParamSpecV0;
+ ContractMessageParamSpecV2: ContractMessageParamSpecV2;
+ ContractMessageSpecLatest: ContractMessageSpecLatest;
+ ContractMessageSpecV0: ContractMessageSpecV0;
+ ContractMessageSpecV1: ContractMessageSpecV1;
+ ContractMessageSpecV2: ContractMessageSpecV2;
+ ContractMessageSpecV3: ContractMessageSpecV3;
+ ContractMetadata: ContractMetadata;
+ ContractMetadataLatest: ContractMetadataLatest;
+ ContractMetadataV0: ContractMetadataV0;
+ ContractMetadataV1: ContractMetadataV1;
+ ContractMetadataV2: ContractMetadataV2;
+ ContractMetadataV3: ContractMetadataV3;
+ ContractMetadataV4: ContractMetadataV4;
+ ContractProject: ContractProject;
+ ContractProjectContract: ContractProjectContract;
+ ContractProjectInfo: ContractProjectInfo;
+ ContractProjectSource: ContractProjectSource;
+ ContractProjectV0: ContractProjectV0;
+ ContractReturnFlags: ContractReturnFlags;
+ ContractSelector: ContractSelector;
+ ContractStorageKey: ContractStorageKey;
+ ContractStorageLayout: ContractStorageLayout;
+ ContractTypeSpec: ContractTypeSpec;
+ Conviction: Conviction;
+ CoreAssignment: CoreAssignment;
+ CoreIndex: CoreIndex;
+ CoreOccupied: CoreOccupied;
+ CoreState: CoreState;
+ CrateVersion: CrateVersion;
+ CreatedBlock: CreatedBlock;
+ CumulusPalletDmpQueueCall: CumulusPalletDmpQueueCall;
+ CumulusPalletDmpQueueConfigData: CumulusPalletDmpQueueConfigData;
+ CumulusPalletDmpQueueError: CumulusPalletDmpQueueError;
+ CumulusPalletDmpQueueEvent: CumulusPalletDmpQueueEvent;
+ CumulusPalletDmpQueuePageIndexData: CumulusPalletDmpQueuePageIndexData;
+ CumulusPalletParachainSystemCall: CumulusPalletParachainSystemCall;
+ CumulusPalletParachainSystemCodeUpgradeAuthorization: CumulusPalletParachainSystemCodeUpgradeAuthorization;
+ CumulusPalletParachainSystemError: CumulusPalletParachainSystemError;
+ CumulusPalletParachainSystemEvent: CumulusPalletParachainSystemEvent;
+ CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot;
+ CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity: CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity;
+ CumulusPalletParachainSystemUnincludedSegmentAncestor: CumulusPalletParachainSystemUnincludedSegmentAncestor;
+ CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate: CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate;
+ CumulusPalletParachainSystemUnincludedSegmentSegmentTracker: CumulusPalletParachainSystemUnincludedSegmentSegmentTracker;
+ CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
+ CumulusPalletXcmCall: CumulusPalletXcmCall;
+ CumulusPalletXcmError: CumulusPalletXcmError;
+ CumulusPalletXcmEvent: CumulusPalletXcmEvent;
+ CumulusPalletXcmOrigin: CumulusPalletXcmOrigin;
+ CumulusPalletXcmpQueueCall: CumulusPalletXcmpQueueCall;
+ CumulusPalletXcmpQueueError: CumulusPalletXcmpQueueError;
+ CumulusPalletXcmpQueueEvent: CumulusPalletXcmpQueueEvent;
+ CumulusPalletXcmpQueueInboundChannelDetails: CumulusPalletXcmpQueueInboundChannelDetails;
+ CumulusPalletXcmpQueueInboundState: CumulusPalletXcmpQueueInboundState;
+ CumulusPalletXcmpQueueOutboundChannelDetails: CumulusPalletXcmpQueueOutboundChannelDetails;
+ CumulusPalletXcmpQueueOutboundState: CumulusPalletXcmpQueueOutboundState;
+ CumulusPalletXcmpQueueQueueConfigData: CumulusPalletXcmpQueueQueueConfigData;
+ CumulusPrimitivesParachainInherentParachainInherentData: CumulusPrimitivesParachainInherentParachainInherentData;
+ CustomMetadata15: CustomMetadata15;
+ CustomValueMetadata15: CustomValueMetadata15;
+ Data: Data;
+ DeferredOffenceOf: DeferredOffenceOf;
+ DefunctVoter: DefunctVoter;
+ DelayKind: DelayKind;
+ DelayKindBest: DelayKindBest;
+ Delegations: Delegations;
+ DeletedContract: DeletedContract;
+ DeliveredMessages: DeliveredMessages;
+ DepositBalance: DepositBalance;
+ DepositBalanceOf: DepositBalanceOf;
+ DestroyWitness: DestroyWitness;
+ Digest: Digest;
+ DigestItem: DigestItem;
+ DigestOf: DigestOf;
+ DispatchClass: DispatchClass;
+ DispatchError: DispatchError;
+ DispatchErrorModule: DispatchErrorModule;
+ DispatchErrorModulePre6: DispatchErrorModulePre6;
+ DispatchErrorModuleU8: DispatchErrorModuleU8;
+ DispatchErrorModuleU8a: DispatchErrorModuleU8a;
+ DispatchErrorPre6: DispatchErrorPre6;
+ DispatchErrorPre6First: DispatchErrorPre6First;
+ DispatchErrorTo198: DispatchErrorTo198;
+ DispatchFeePayment: DispatchFeePayment;
+ DispatchInfo: DispatchInfo;
+ DispatchInfoTo190: DispatchInfoTo190;
+ DispatchInfoTo244: DispatchInfoTo244;
+ DispatchOutcome: DispatchOutcome;
+ DispatchOutcomePre6: DispatchOutcomePre6;
+ DispatchResult: DispatchResult;
+ DispatchResultOf: DispatchResultOf;
+ DispatchResultTo198: DispatchResultTo198;
+ DisputeLocation: DisputeLocation;
+ DisputeProof: DisputeProof;
+ DisputeResult: DisputeResult;
+ DisputeState: DisputeState;
+ DisputeStatement: DisputeStatement;
+ DisputeStatementSet: DisputeStatementSet;
+ DisputesTimeSlot: DisputesTimeSlot;
+ DoubleEncodedCall: DoubleEncodedCall;
+ DoubleVoteReport: DoubleVoteReport;
+ DownwardMessage: DownwardMessage;
+ EcdsaSignature: EcdsaSignature;
+ Ed25519Signature: Ed25519Signature;
+ EIP1559Transaction: EIP1559Transaction;
+ EIP2930Transaction: EIP2930Transaction;
+ ElectionCompute: ElectionCompute;
+ ElectionPhase: ElectionPhase;
+ ElectionResult: ElectionResult;
+ ElectionScore: ElectionScore;
+ ElectionSize: ElectionSize;
+ ElectionStatus: ElectionStatus;
+ EncodedFinalityProofs: EncodedFinalityProofs;
+ EncodedJustification: EncodedJustification;
+ Epoch: Epoch;
+ EpochAuthorship: EpochAuthorship;
+ Era: Era;
+ EraIndex: EraIndex;
+ EraPoints: EraPoints;
+ EraRewardPoints: EraRewardPoints;
+ EraRewards: EraRewards;
+ ErrorMetadataLatest: ErrorMetadataLatest;
+ ErrorMetadataV10: ErrorMetadataV10;
+ ErrorMetadataV11: ErrorMetadataV11;
+ ErrorMetadataV12: ErrorMetadataV12;
+ ErrorMetadataV13: ErrorMetadataV13;
+ ErrorMetadataV14: ErrorMetadataV14;
+ ErrorMetadataV9: ErrorMetadataV9;
+ EthAccessList: EthAccessList;
+ EthAccessListItem: EthAccessListItem;
+ EthAccount: EthAccount;
+ EthAddress: EthAddress;
+ EthBlock: EthBlock;
+ EthBloom: EthBloom;
+ EthbloomBloom: EthbloomBloom;
+ EthCallRequest: EthCallRequest;
+ EthereumAccountId: EthereumAccountId;
+ EthereumAddress: EthereumAddress;
+ EthereumBlock: EthereumBlock;
+ EthereumHeader: EthereumHeader;
+ EthereumLog: EthereumLog;
+ EthereumLookupSource: EthereumLookupSource;
+ EthereumReceiptEip658ReceiptData: EthereumReceiptEip658ReceiptData;
+ EthereumReceiptReceiptV3: EthereumReceiptReceiptV3;
+ EthereumSignature: EthereumSignature;
+ EthereumTransactionAccessListItem: EthereumTransactionAccessListItem;
+ EthereumTransactionEip1559Transaction: EthereumTransactionEip1559Transaction;
+ EthereumTransactionEip2930Transaction: EthereumTransactionEip2930Transaction;
+ EthereumTransactionLegacyTransaction: EthereumTransactionLegacyTransaction;
+ EthereumTransactionTransactionAction: EthereumTransactionTransactionAction;
+ EthereumTransactionTransactionSignature: EthereumTransactionTransactionSignature;
+ EthereumTransactionTransactionV2: EthereumTransactionTransactionV2;
+ EthereumTypesHashH64: EthereumTypesHashH64;
+ EthFeeHistory: EthFeeHistory;
+ EthFilter: EthFilter;
+ EthFilterAddress: EthFilterAddress;
+ EthFilterChanges: EthFilterChanges;
+ EthFilterTopic: EthFilterTopic;
+ EthFilterTopicEntry: EthFilterTopicEntry;
+ EthFilterTopicInner: EthFilterTopicInner;
+ EthHeader: EthHeader;
+ EthLog: EthLog;
+ EthReceipt: EthReceipt;
+ EthReceiptV0: EthReceiptV0;
+ EthReceiptV3: EthReceiptV3;
+ EthRichBlock: EthRichBlock;
+ EthRichHeader: EthRichHeader;
+ EthStorageProof: EthStorageProof;
+ EthSubKind: EthSubKind;
+ EthSubParams: EthSubParams;
+ EthSubResult: EthSubResult;
+ EthSyncInfo: EthSyncInfo;
+ EthSyncStatus: EthSyncStatus;
+ EthTransaction: EthTransaction;
+ EthTransactionAction: EthTransactionAction;
+ EthTransactionCondition: EthTransactionCondition;
+ EthTransactionRequest: EthTransactionRequest;
+ EthTransactionSignature: EthTransactionSignature;
+ EthTransactionStatus: EthTransactionStatus;
+ EthWork: EthWork;
+ Event: Event;
+ EventId: EventId;
+ EventIndex: EventIndex;
+ EventMetadataLatest: EventMetadataLatest;
+ EventMetadataV10: EventMetadataV10;
+ EventMetadataV11: EventMetadataV11;
+ EventMetadataV12: EventMetadataV12;
+ EventMetadataV13: EventMetadataV13;
+ EventMetadataV14: EventMetadataV14;
+ EventMetadataV9: EventMetadataV9;
+ EventRecord: EventRecord;
+ EvmAccount: EvmAccount;
+ EvmCallInfo: EvmCallInfo;
+ EvmCallInfoV2: EvmCallInfoV2;
+ EvmCoreErrorExitError: EvmCoreErrorExitError;
+ EvmCoreErrorExitFatal: EvmCoreErrorExitFatal;
+ EvmCoreErrorExitReason: EvmCoreErrorExitReason;
+ EvmCoreErrorExitRevert: EvmCoreErrorExitRevert;
+ EvmCoreErrorExitSucceed: EvmCoreErrorExitSucceed;
+ EvmCreateInfo: EvmCreateInfo;
+ EvmCreateInfoV2: EvmCreateInfoV2;
+ EvmLog: EvmLog;
+ EvmVicinity: EvmVicinity;
+ EvmWeightInfo: EvmWeightInfo;
+ ExecReturnValue: ExecReturnValue;
+ ExecutorParam: ExecutorParam;
+ ExecutorParams: ExecutorParams;
+ ExecutorParamsHash: ExecutorParamsHash;
+ ExitError: ExitError;
+ ExitFatal: ExitFatal;
+ ExitReason: ExitReason;
+ ExitRevert: ExitRevert;
+ ExitSucceed: ExitSucceed;
+ ExplicitDisputeStatement: ExplicitDisputeStatement;
+ Exposure: Exposure;
+ ExtendedBalance: ExtendedBalance;
+ Extrinsic: Extrinsic;
+ ExtrinsicEra: ExtrinsicEra;
+ ExtrinsicMetadataLatest: ExtrinsicMetadataLatest;
+ ExtrinsicMetadataV11: ExtrinsicMetadataV11;
+ ExtrinsicMetadataV12: ExtrinsicMetadataV12;
+ ExtrinsicMetadataV13: ExtrinsicMetadataV13;
+ ExtrinsicMetadataV14: ExtrinsicMetadataV14;
+ ExtrinsicMetadataV15: ExtrinsicMetadataV15;
+ ExtrinsicOrHash: ExtrinsicOrHash;
+ ExtrinsicPayload: ExtrinsicPayload;
+ ExtrinsicPayloadUnknown: ExtrinsicPayloadUnknown;
+ ExtrinsicPayloadV4: ExtrinsicPayloadV4;
+ ExtrinsicSignature: ExtrinsicSignature;
+ ExtrinsicSignatureV4: ExtrinsicSignatureV4;
+ ExtrinsicStatus: ExtrinsicStatus;
+ ExtrinsicsWeight: ExtrinsicsWeight;
+ ExtrinsicUnknown: ExtrinsicUnknown;
+ ExtrinsicV4: ExtrinsicV4;
+ f32: f32;
+ F32: F32;
+ f64: f64;
+ F64: F64;
+ FeeDetails: FeeDetails;
+ Fixed128: Fixed128;
+ Fixed64: Fixed64;
+ FixedI128: FixedI128;
+ FixedI64: FixedI64;
+ FixedU128: FixedU128;
+ FixedU64: FixedU64;
+ Forcing: Forcing;
+ ForkTreePendingChange: ForkTreePendingChange;
+ ForkTreePendingChangeNode: ForkTreePendingChangeNode;
+ FpRpcTransactionStatus: FpRpcTransactionStatus;
+ FrameSupportDispatchDispatchClass: FrameSupportDispatchDispatchClass;
+ FrameSupportDispatchDispatchInfo: FrameSupportDispatchDispatchInfo;
+ FrameSupportDispatchPays: FrameSupportDispatchPays;
+ FrameSupportDispatchPerDispatchClassU32: FrameSupportDispatchPerDispatchClassU32;
+ FrameSupportDispatchPerDispatchClassWeight: FrameSupportDispatchPerDispatchClassWeight;
+ FrameSupportDispatchPerDispatchClassWeightsPerClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
+ FrameSupportDispatchRawOrigin: FrameSupportDispatchRawOrigin;
+ FrameSupportPalletId: FrameSupportPalletId;
+ FrameSupportPreimagesBounded: FrameSupportPreimagesBounded;
+ FrameSupportScheduleDispatchTime: FrameSupportScheduleDispatchTime;
+ FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus;
+ FrameSystemAccountInfo: FrameSystemAccountInfo;
+ FrameSystemCall: FrameSystemCall;
+ FrameSystemError: FrameSystemError;
+ FrameSystemEvent: FrameSystemEvent;
+ FrameSystemEventRecord: FrameSystemEventRecord;
+ FrameSystemExtensionsCheckGenesis: FrameSystemExtensionsCheckGenesis;
+ FrameSystemExtensionsCheckNonce: FrameSystemExtensionsCheckNonce;
+ FrameSystemExtensionsCheckSpecVersion: FrameSystemExtensionsCheckSpecVersion;
+ FrameSystemExtensionsCheckTxVersion: FrameSystemExtensionsCheckTxVersion;
+ FrameSystemExtensionsCheckWeight: FrameSystemExtensionsCheckWeight;
+ FrameSystemLastRuntimeUpgradeInfo: FrameSystemLastRuntimeUpgradeInfo;
+ FrameSystemLimitsBlockLength: FrameSystemLimitsBlockLength;
+ FrameSystemLimitsBlockWeights: FrameSystemLimitsBlockWeights;
+ FrameSystemLimitsWeightsPerClass: FrameSystemLimitsWeightsPerClass;
+ FrameSystemPhase: FrameSystemPhase;
+ FullIdentification: FullIdentification;
+ FunctionArgumentMetadataLatest: FunctionArgumentMetadataLatest;
+ FunctionArgumentMetadataV10: FunctionArgumentMetadataV10;
+ FunctionArgumentMetadataV11: FunctionArgumentMetadataV11;
+ FunctionArgumentMetadataV12: FunctionArgumentMetadataV12;
+ FunctionArgumentMetadataV13: FunctionArgumentMetadataV13;
+ FunctionArgumentMetadataV14: FunctionArgumentMetadataV14;
+ FunctionArgumentMetadataV9: FunctionArgumentMetadataV9;
+ FunctionMetadataLatest: FunctionMetadataLatest;
+ FunctionMetadataV10: FunctionMetadataV10;
+ FunctionMetadataV11: FunctionMetadataV11;
+ FunctionMetadataV12: FunctionMetadataV12;
+ FunctionMetadataV13: FunctionMetadataV13;
+ FunctionMetadataV14: FunctionMetadataV14;
+ FunctionMetadataV9: FunctionMetadataV9;
+ FundIndex: FundIndex;
+ FundInfo: FundInfo;
+ Fungibility: Fungibility;
+ FungibilityV0: FungibilityV0;
+ FungibilityV1: FungibilityV1;
+ FungibilityV2: FungibilityV2;
+ FungiblesAccessError: FungiblesAccessError;
+ Gas: Gas;
+ GiltBid: GiltBid;
+ GlobalValidationData: GlobalValidationData;
+ GlobalValidationSchedule: GlobalValidationSchedule;
+ GrandpaCommit: GrandpaCommit;
+ GrandpaEquivocation: GrandpaEquivocation;
+ GrandpaEquivocationProof: GrandpaEquivocationProof;
+ GrandpaEquivocationValue: GrandpaEquivocationValue;
+ GrandpaJustification: GrandpaJustification;
+ GrandpaPrecommit: GrandpaPrecommit;
+ GrandpaPrevote: GrandpaPrevote;
+ GrandpaSignedPrecommit: GrandpaSignedPrecommit;
+ GroupIndex: GroupIndex;
+ GroupRotationInfo: GroupRotationInfo;
+ H1024: H1024;
+ H128: H128;
+ H160: H160;
+ H2048: H2048;
+ H256: H256;
+ H32: H32;
+ H512: H512;
+ H64: H64;
+ Hash: Hash;
+ HeadData: HeadData;
+ Header: Header;
+ HeaderPartial: HeaderPartial;
+ Health: Health;
+ Heartbeat: Heartbeat;
+ HeartbeatTo244: HeartbeatTo244;
+ HostConfiguration: HostConfiguration;
+ HostFnWeights: HostFnWeights;
+ HostFnWeightsTo264: HostFnWeightsTo264;
+ HrmpChannel: HrmpChannel;
+ HrmpChannelId: HrmpChannelId;
+ HrmpOpenChannelRequest: HrmpOpenChannelRequest;
+ i128: i128;
+ I128: I128;
+ i16: i16;
+ I16: I16;
+ i256: i256;
+ I256: I256;
+ i32: i32;
+ I32: I32;
+ I32F32: I32F32;
+ i64: i64;
+ I64: I64;
+ i8: i8;
+ I8: I8;
+ IdentificationTuple: IdentificationTuple;
+ IdentityFields: IdentityFields;
+ IdentityInfo: IdentityInfo;
+ IdentityInfoAdditional: IdentityInfoAdditional;
+ IdentityInfoTo198: IdentityInfoTo198;
+ IdentityJudgement: IdentityJudgement;
+ ImmortalEra: ImmortalEra;
+ ImportedAux: ImportedAux;
+ InboundDownwardMessage: InboundDownwardMessage;
+ InboundHrmpMessage: InboundHrmpMessage;
+ InboundHrmpMessages: InboundHrmpMessages;
+ InboundLaneData: InboundLaneData;
+ InboundRelayer: InboundRelayer;
+ InboundStatus: InboundStatus;
+ IncludedBlocks: IncludedBlocks;
+ InclusionFee: InclusionFee;
+ IncomingParachain: IncomingParachain;
+ IncomingParachainDeploy: IncomingParachainDeploy;
+ IncomingParachainFixed: IncomingParachainFixed;
+ Index: Index;
+ IndicesLookupSource: IndicesLookupSource;
+ IndividualExposure: IndividualExposure;
+ InherentData: InherentData;
+ InherentIdentifier: InherentIdentifier;
+ InitializationData: InitializationData;
+ InstanceDetails: InstanceDetails;
+ InstanceId: InstanceId;
+ InstanceMetadata: InstanceMetadata;
+ InstantiateRequest: InstantiateRequest;
+ InstantiateRequestV1: InstantiateRequestV1;
+ InstantiateRequestV2: InstantiateRequestV2;
+ InstantiateReturnValue: InstantiateReturnValue;
+ InstantiateReturnValueOk: InstantiateReturnValueOk;
+ InstantiateReturnValueTo267: InstantiateReturnValueTo267;
+ InstructionV2: InstructionV2;
+ InstructionWeights: InstructionWeights;
+ InteriorMultiLocation: InteriorMultiLocation;
+ InvalidDisputeStatementKind: InvalidDisputeStatementKind;
+ InvalidTransaction: InvalidTransaction;
+ isize: isize;
+ ISize: ISize;
+ Json: Json;
+ Junction: Junction;
+ Junctions: Junctions;
+ JunctionsV1: JunctionsV1;
+ JunctionsV2: JunctionsV2;
+ JunctionV0: JunctionV0;
+ JunctionV1: JunctionV1;
+ JunctionV2: JunctionV2;
+ Justification: Justification;
+ JustificationNotification: JustificationNotification;
+ Justifications: Justifications;
+ Key: Key;
+ KeyOwnerProof: KeyOwnerProof;
+ Keys: Keys;
+ KeyType: KeyType;
+ KeyTypeId: KeyTypeId;
+ KeyValue: KeyValue;
+ KeyValueOption: KeyValueOption;
+ Kind: Kind;
+ LaneId: LaneId;
+ LastContribution: LastContribution;
+ LastRuntimeUpgradeInfo: LastRuntimeUpgradeInfo;
+ LeasePeriod: LeasePeriod;
+ LeasePeriodOf: LeasePeriodOf;
+ LegacyTransaction: LegacyTransaction;
+ Limits: Limits;
+ LimitsTo264: LimitsTo264;
+ LocalValidationData: LocalValidationData;
+ LockIdentifier: LockIdentifier;
+ LookupSource: LookupSource;
+ LookupTarget: LookupTarget;
+ LotteryConfig: LotteryConfig;
+ MaybeRandomness: MaybeRandomness;
+ MaybeVrf: MaybeVrf;
+ MemberCount: MemberCount;
+ MembershipProof: MembershipProof;
+ MessageData: MessageData;
+ MessageId: MessageId;
+ MessageIngestionType: MessageIngestionType;
+ MessageKey: MessageKey;
+ MessageNonce: MessageNonce;
+ MessageQueueChain: MessageQueueChain;
+ MessagesDeliveryProofOf: MessagesDeliveryProofOf;
+ MessagesProofOf: MessagesProofOf;
+ MessagingStateSnapshot: MessagingStateSnapshot;
+ MessagingStateSnapshotEgressEntry: MessagingStateSnapshotEgressEntry;
+ MetadataAll: MetadataAll;
+ MetadataLatest: MetadataLatest;
+ MetadataV10: MetadataV10;
+ MetadataV11: MetadataV11;
+ MetadataV12: MetadataV12;
+ MetadataV13: MetadataV13;
+ MetadataV14: MetadataV14;
+ MetadataV15: MetadataV15;
+ MetadataV9: MetadataV9;
+ MigrationStatusResult: MigrationStatusResult;
+ MmrBatchProof: MmrBatchProof;
+ MmrEncodableOpaqueLeaf: MmrEncodableOpaqueLeaf;
+ MmrError: MmrError;
+ MmrHash: MmrHash;
+ MmrLeafBatchProof: MmrLeafBatchProof;
+ MmrLeafIndex: MmrLeafIndex;
+ MmrLeafProof: MmrLeafProof;
+ MmrNodeIndex: MmrNodeIndex;
+ MmrProof: MmrProof;
+ MmrRootHash: MmrRootHash;
+ ModuleConstantMetadataV10: ModuleConstantMetadataV10;
+ ModuleConstantMetadataV11: ModuleConstantMetadataV11;
+ ModuleConstantMetadataV12: ModuleConstantMetadataV12;
+ ModuleConstantMetadataV13: ModuleConstantMetadataV13;
+ ModuleConstantMetadataV9: ModuleConstantMetadataV9;
+ ModuleId: ModuleId;
+ ModuleMetadataV10: ModuleMetadataV10;
+ ModuleMetadataV11: ModuleMetadataV11;
+ ModuleMetadataV12: ModuleMetadataV12;
+ ModuleMetadataV13: ModuleMetadataV13;
+ ModuleMetadataV9: ModuleMetadataV9;
+ Moment: Moment;
+ MomentOf: MomentOf;
+ MoreAttestations: MoreAttestations;
+ MortalEra: MortalEra;
+ MultiAddress: MultiAddress;
+ MultiAsset: MultiAsset;
+ MultiAssetFilter: MultiAssetFilter;
+ MultiAssetFilterV1: MultiAssetFilterV1;
+ MultiAssetFilterV2: MultiAssetFilterV2;
+ MultiAssets: MultiAssets;
+ MultiAssetsV1: MultiAssetsV1;
+ MultiAssetsV2: MultiAssetsV2;
+ MultiAssetV0: MultiAssetV0;
+ MultiAssetV1: MultiAssetV1;
+ MultiAssetV2: MultiAssetV2;
+ MultiDisputeStatementSet: MultiDisputeStatementSet;
+ MultiLocation: MultiLocation;
+ MultiLocationV0: MultiLocationV0;
+ MultiLocationV1: MultiLocationV1;
+ MultiLocationV2: MultiLocationV2;
+ Multiplier: Multiplier;
+ Multisig: Multisig;
+ MultiSignature: MultiSignature;
+ MultiSigner: MultiSigner;
+ NetworkId: NetworkId;
+ NetworkState: NetworkState;
+ NetworkStatePeerset: NetworkStatePeerset;
+ NetworkStatePeersetInfo: NetworkStatePeersetInfo;
+ NewBidder: NewBidder;
+ NextAuthority: NextAuthority;
+ NextConfigDescriptor: NextConfigDescriptor;
+ NextConfigDescriptorV1: NextConfigDescriptorV1;
+ NftCollectionId: NftCollectionId;
+ NftItemId: NftItemId;
+ NodeRole: NodeRole;
+ Nominations: Nominations;
+ NominatorIndex: NominatorIndex;
+ NominatorIndexCompact: NominatorIndexCompact;
+ NotConnectedPeer: NotConnectedPeer;
+ NpApiError: NpApiError;
+ NpPoolId: NpPoolId;
+ Null: Null;
+ OccupiedCore: OccupiedCore;
+ OccupiedCoreAssumption: OccupiedCoreAssumption;
+ OffchainAccuracy: OffchainAccuracy;
+ OffchainAccuracyCompact: OffchainAccuracyCompact;
+ OffenceDetails: OffenceDetails;
+ Offender: Offender;
+ OldV1SessionInfo: OldV1SessionInfo;
+ OpalRuntimeOriginCaller: OpalRuntimeOriginCaller;
+ OpalRuntimeRuntime: OpalRuntimeRuntime;
+ OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls: OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls;
+ OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance;
+ OpalRuntimeRuntimeCommonSessionKeys: OpalRuntimeRuntimeCommonSessionKeys;
+ OpalRuntimeRuntimeHoldReason: OpalRuntimeRuntimeHoldReason;
+ OpaqueCall: OpaqueCall;
+ OpaqueKeyOwnershipProof: OpaqueKeyOwnershipProof;
+ OpaqueMetadata: OpaqueMetadata;
+ OpaqueMultiaddr: OpaqueMultiaddr;
+ OpaqueNetworkState: OpaqueNetworkState;
+ OpaquePeerId: OpaquePeerId;
+ OpaqueTimeSlot: OpaqueTimeSlot;
+ OpenTip: OpenTip;
+ OpenTipFinderTo225: OpenTipFinderTo225;
+ OpenTipTip: OpenTipTip;
+ OpenTipTo225: OpenTipTo225;
+ OperatingMode: OperatingMode;
+ OptionBool: OptionBool;
+ Origin: Origin;
+ OriginCaller: OriginCaller;
+ OriginKindV0: OriginKindV0;
+ OriginKindV1: OriginKindV1;
+ OriginKindV2: OriginKindV2;
+ OrmlTokensAccountData: OrmlTokensAccountData;
+ OrmlTokensBalanceLock: OrmlTokensBalanceLock;
+ OrmlTokensModuleCall: OrmlTokensModuleCall;
+ OrmlTokensModuleError: OrmlTokensModuleError;
+ OrmlTokensModuleEvent: OrmlTokensModuleEvent;
+ OrmlTokensReserveData: OrmlTokensReserveData;
+ OrmlVestingModuleCall: OrmlVestingModuleCall;
+ OrmlVestingModuleError: OrmlVestingModuleError;
+ OrmlVestingModuleEvent: OrmlVestingModuleEvent;
+ OrmlVestingVestingSchedule: OrmlVestingVestingSchedule;
+ OrmlXtokensModuleCall: OrmlXtokensModuleCall;
+ OrmlXtokensModuleError: OrmlXtokensModuleError;
+ OrmlXtokensModuleEvent: OrmlXtokensModuleEvent;
+ OutboundHrmpMessage: OutboundHrmpMessage;
+ OutboundLaneData: OutboundLaneData;
+ OutboundMessageFee: OutboundMessageFee;
+ OutboundPayload: OutboundPayload;
+ OutboundStatus: OutboundStatus;
+ Outcome: Outcome;
+ OuterEnums15: OuterEnums15;
+ OverweightIndex: OverweightIndex;
+ Owner: Owner;
+ PageCounter: PageCounter;
+ PageIndexData: PageIndexData;
+ PalletAppPromotionCall: PalletAppPromotionCall;
+ PalletAppPromotionError: PalletAppPromotionError;
+ PalletAppPromotionEvent: PalletAppPromotionEvent;
+ PalletBalancesAccountData: PalletBalancesAccountData;
+ PalletBalancesBalanceLock: PalletBalancesBalanceLock;
+ PalletBalancesCall: PalletBalancesCall;
+ PalletBalancesError: PalletBalancesError;
+ PalletBalancesEvent: PalletBalancesEvent;
+ PalletBalancesIdAmount: PalletBalancesIdAmount;
+ PalletBalancesReasons: PalletBalancesReasons;
+ PalletBalancesReserveData: PalletBalancesReserveData;
+ PalletCallMetadataLatest: PalletCallMetadataLatest;
+ PalletCallMetadataV14: PalletCallMetadataV14;
+ PalletCollatorSelectionCall: PalletCollatorSelectionCall;
+ PalletCollatorSelectionError: PalletCollatorSelectionError;
+ PalletCollatorSelectionEvent: PalletCollatorSelectionEvent;
+ PalletCollatorSelectionHoldReason: PalletCollatorSelectionHoldReason;
+ PalletCollectiveCall: PalletCollectiveCall;
+ PalletCollectiveError: PalletCollectiveError;
+ PalletCollectiveEvent: PalletCollectiveEvent;
+ PalletCollectiveRawOrigin: PalletCollectiveRawOrigin;
+ PalletCollectiveVotes: PalletCollectiveVotes;
+ PalletCommonError: PalletCommonError;
+ PalletCommonEvent: PalletCommonEvent;
+ PalletConfigurationAppPromotionConfiguration: PalletConfigurationAppPromotionConfiguration;
+ PalletConfigurationCall: PalletConfigurationCall;
+ PalletConfigurationError: PalletConfigurationError;
+ PalletConfigurationEvent: PalletConfigurationEvent;
+ PalletConstantMetadataLatest: PalletConstantMetadataLatest;
+ PalletConstantMetadataV14: PalletConstantMetadataV14;
+ PalletDemocracyCall: PalletDemocracyCall;
+ PalletDemocracyConviction: PalletDemocracyConviction;
+ PalletDemocracyDelegations: PalletDemocracyDelegations;
+ PalletDemocracyError: PalletDemocracyError;
+ PalletDemocracyEvent: PalletDemocracyEvent;
+ PalletDemocracyMetadataOwner: PalletDemocracyMetadataOwner;
+ PalletDemocracyReferendumInfo: PalletDemocracyReferendumInfo;
+ PalletDemocracyReferendumStatus: PalletDemocracyReferendumStatus;
+ PalletDemocracyTally: PalletDemocracyTally;
+ PalletDemocracyVoteAccountVote: PalletDemocracyVoteAccountVote;
+ PalletDemocracyVotePriorLock: PalletDemocracyVotePriorLock;
+ PalletDemocracyVoteThreshold: PalletDemocracyVoteThreshold;
+ PalletDemocracyVoteVoting: PalletDemocracyVoteVoting;
+ PalletErrorMetadataLatest: PalletErrorMetadataLatest;
+ PalletErrorMetadataV14: PalletErrorMetadataV14;
+ PalletEthereumCall: PalletEthereumCall;
+ PalletEthereumError: PalletEthereumError;
+ PalletEthereumEvent: PalletEthereumEvent;
+ PalletEthereumFakeTransactionFinalizer: PalletEthereumFakeTransactionFinalizer;
+ PalletEthereumRawOrigin: PalletEthereumRawOrigin;
+ PalletEventMetadataLatest: PalletEventMetadataLatest;
+ PalletEventMetadataV14: PalletEventMetadataV14;
+ PalletEvmAccountBasicCrossAccountIdRepr: PalletEvmAccountBasicCrossAccountIdRepr;
+ PalletEvmCall: PalletEvmCall;
+ PalletEvmCodeMetadata: PalletEvmCodeMetadata;
+ PalletEvmCoderSubstrateError: PalletEvmCoderSubstrateError;
+ PalletEvmContractHelpersCall: PalletEvmContractHelpersCall;
+ PalletEvmContractHelpersError: PalletEvmContractHelpersError;
+ PalletEvmContractHelpersEvent: PalletEvmContractHelpersEvent;
+ PalletEvmContractHelpersSponsoringModeT: PalletEvmContractHelpersSponsoringModeT;
+ PalletEvmError: PalletEvmError;
+ PalletEvmEvent: PalletEvmEvent;
+ PalletEvmMigrationCall: PalletEvmMigrationCall;
+ PalletEvmMigrationError: PalletEvmMigrationError;
+ PalletEvmMigrationEvent: PalletEvmMigrationEvent;
+ PalletForeignAssetsAssetId: PalletForeignAssetsAssetId;
+ PalletForeignAssetsModuleAssetMetadata: PalletForeignAssetsModuleAssetMetadata;
+ PalletForeignAssetsModuleCall: PalletForeignAssetsModuleCall;
+ PalletForeignAssetsModuleError: PalletForeignAssetsModuleError;
+ PalletForeignAssetsModuleEvent: PalletForeignAssetsModuleEvent;
+ PalletForeignAssetsNativeCurrency: PalletForeignAssetsNativeCurrency;
+ PalletFungibleError: PalletFungibleError;
+ PalletGovOriginsOrigin: PalletGovOriginsOrigin;
+ PalletId: PalletId;
+ PalletIdentityBitFlags: PalletIdentityBitFlags;
+ PalletIdentityCall: PalletIdentityCall;
+ PalletIdentityError: PalletIdentityError;
+ PalletIdentityEvent: PalletIdentityEvent;
+ PalletIdentityIdentityField: PalletIdentityIdentityField;
+ PalletIdentityIdentityInfo: PalletIdentityIdentityInfo;
+ PalletIdentityJudgement: PalletIdentityJudgement;
+ PalletIdentityRegistrarInfo: PalletIdentityRegistrarInfo;
+ PalletIdentityRegistration: PalletIdentityRegistration;
+ PalletInflationCall: PalletInflationCall;
+ PalletMaintenanceCall: PalletMaintenanceCall;
+ PalletMaintenanceError: PalletMaintenanceError;
+ PalletMaintenanceEvent: PalletMaintenanceEvent;
+ PalletMembershipCall: PalletMembershipCall;
+ PalletMembershipError: PalletMembershipError;
+ PalletMembershipEvent: PalletMembershipEvent;
+ PalletMetadataLatest: PalletMetadataLatest;
+ PalletMetadataV14: PalletMetadataV14;
+ PalletMetadataV15: PalletMetadataV15;
+ PalletNonfungibleError: PalletNonfungibleError;
+ PalletNonfungibleItemData: PalletNonfungibleItemData;
+ PalletPreimageCall: PalletPreimageCall;
+ PalletPreimageError: PalletPreimageError;
+ PalletPreimageEvent: PalletPreimageEvent;
+ PalletPreimageRequestStatus: PalletPreimageRequestStatus;
+ PalletRankedCollectiveCall: PalletRankedCollectiveCall;
+ PalletRankedCollectiveError: PalletRankedCollectiveError;
+ PalletRankedCollectiveEvent: PalletRankedCollectiveEvent;
+ PalletRankedCollectiveMemberRecord: PalletRankedCollectiveMemberRecord;
+ PalletRankedCollectiveTally: PalletRankedCollectiveTally;
+ PalletRankedCollectiveVoteRecord: PalletRankedCollectiveVoteRecord;
+ PalletReferendaCall: PalletReferendaCall;
+ PalletReferendaCurve: PalletReferendaCurve;
+ PalletReferendaDecidingStatus: PalletReferendaDecidingStatus;
+ PalletReferendaDeposit: PalletReferendaDeposit;
+ PalletReferendaError: PalletReferendaError;
+ PalletReferendaEvent: PalletReferendaEvent;
+ PalletReferendaReferendumInfo: PalletReferendaReferendumInfo;
+ PalletReferendaReferendumStatus: PalletReferendaReferendumStatus;
+ PalletReferendaTrackInfo: PalletReferendaTrackInfo;
+ PalletRefungibleError: PalletRefungibleError;
+ PalletSchedulerCall: PalletSchedulerCall;
+ PalletSchedulerError: PalletSchedulerError;
+ PalletSchedulerEvent: PalletSchedulerEvent;
+ PalletSchedulerScheduled: PalletSchedulerScheduled;
+ PalletSessionCall: PalletSessionCall;
+ PalletSessionError: PalletSessionError;
+ PalletSessionEvent: PalletSessionEvent;
+ PalletsOrigin: PalletsOrigin;
+ PalletStateTrieMigrationCall: PalletStateTrieMigrationCall;
+ PalletStateTrieMigrationError: PalletStateTrieMigrationError;
+ PalletStateTrieMigrationEvent: PalletStateTrieMigrationEvent;
+ PalletStateTrieMigrationMigrationCompute: PalletStateTrieMigrationMigrationCompute;
+ PalletStateTrieMigrationMigrationLimits: PalletStateTrieMigrationMigrationLimits;
+ PalletStateTrieMigrationMigrationTask: PalletStateTrieMigrationMigrationTask;
+ PalletStateTrieMigrationProgress: PalletStateTrieMigrationProgress;
+ PalletStorageMetadataLatest: PalletStorageMetadataLatest;
+ PalletStorageMetadataV14: PalletStorageMetadataV14;
+ PalletStructureCall: PalletStructureCall;
+ PalletStructureError: PalletStructureError;
+ PalletStructureEvent: PalletStructureEvent;
+ PalletSudoCall: PalletSudoCall;
+ PalletSudoError: PalletSudoError;
+ PalletSudoEvent: PalletSudoEvent;
+ PalletTemplateTransactionPaymentChargeTransactionPayment: PalletTemplateTransactionPaymentChargeTransactionPayment;
+ PalletTestUtilsCall: PalletTestUtilsCall;
+ PalletTestUtilsError: PalletTestUtilsError;
+ PalletTestUtilsEvent: PalletTestUtilsEvent;
+ PalletTimestampCall: PalletTimestampCall;
+ PalletTransactionPaymentEvent: PalletTransactionPaymentEvent;
+ PalletTransactionPaymentReleases: PalletTransactionPaymentReleases;
+ PalletTreasuryCall: PalletTreasuryCall;
+ PalletTreasuryError: PalletTreasuryError;
+ PalletTreasuryEvent: PalletTreasuryEvent;
+ PalletTreasuryProposal: PalletTreasuryProposal;
+ PalletUniqueCall: PalletUniqueCall;
+ PalletUniqueError: PalletUniqueError;
+ PalletUtilityCall: PalletUtilityCall;
+ PalletUtilityError: PalletUtilityError;
+ PalletUtilityEvent: PalletUtilityEvent;
+ PalletVersion: PalletVersion;
+ PalletXcmCall: PalletXcmCall;
+ PalletXcmError: PalletXcmError;
+ PalletXcmEvent: PalletXcmEvent;
+ PalletXcmOrigin: PalletXcmOrigin;
+ PalletXcmQueryStatus: PalletXcmQueryStatus;
+ PalletXcmRemoteLockedFungibleRecord: PalletXcmRemoteLockedFungibleRecord;
+ PalletXcmVersionMigrationStage: PalletXcmVersionMigrationStage;
+ ParachainDispatchOrigin: ParachainDispatchOrigin;
+ ParachainInfoCall: ParachainInfoCall;
+ ParachainInherentData: ParachainInherentData;
+ ParachainProposal: ParachainProposal;
+ ParachainsInherentData: ParachainsInherentData;
+ ParaGenesisArgs: ParaGenesisArgs;
+ ParaId: ParaId;
+ ParaInfo: ParaInfo;
+ ParaLifecycle: ParaLifecycle;
+ Parameter: Parameter;
+ ParaPastCodeMeta: ParaPastCodeMeta;
+ ParaScheduling: ParaScheduling;
+ ParathreadClaim: ParathreadClaim;
+ ParathreadClaimQueue: ParathreadClaimQueue;
+ ParathreadEntry: ParathreadEntry;
+ ParaValidatorIndex: ParaValidatorIndex;
+ Pays: Pays;
+ Peer: Peer;
+ PeerEndpoint: PeerEndpoint;
+ PeerEndpointAddr: PeerEndpointAddr;
+ PeerInfo: PeerInfo;
+ PeerPing: PeerPing;
+ PendingChange: PendingChange;
+ PendingPause: PendingPause;
+ PendingResume: PendingResume;
+ PendingSlashes: PendingSlashes;
+ Perbill: Perbill;
+ Percent: Percent;
+ PerDispatchClassU32: PerDispatchClassU32;
+ PerDispatchClassWeight: PerDispatchClassWeight;
+ PerDispatchClassWeightsPerClass: PerDispatchClassWeightsPerClass;
+ Period: Period;
+ Permill: Permill;
+ PermissionLatest: PermissionLatest;
+ PermissionsV1: PermissionsV1;
+ PermissionVersions: PermissionVersions;
+ Perquintill: Perquintill;
+ PersistedValidationData: PersistedValidationData;
+ PerU16: PerU16;
+ Phantom: Phantom;
+ PhantomData: PhantomData;
+ PhantomTypeUpDataStructs: PhantomTypeUpDataStructs;
+ Phase: Phase;
+ PhragmenScore: PhragmenScore;
+ Points: Points;
+ PolkadotCorePrimitivesInboundDownwardMessage: PolkadotCorePrimitivesInboundDownwardMessage;
+ PolkadotCorePrimitivesInboundHrmpMessage: PolkadotCorePrimitivesInboundHrmpMessage;
+ PolkadotCorePrimitivesOutboundHrmpMessage: PolkadotCorePrimitivesOutboundHrmpMessage;
+ PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat: PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat;
+ PolkadotPrimitivesV5AbridgedHostConfiguration: PolkadotPrimitivesV5AbridgedHostConfiguration;
+ PolkadotPrimitivesV5AbridgedHrmpChannel: PolkadotPrimitivesV5AbridgedHrmpChannel;
+ PolkadotPrimitivesV5PersistedValidationData: PolkadotPrimitivesV5PersistedValidationData;
+ PolkadotPrimitivesV5UpgradeGoAhead: PolkadotPrimitivesV5UpgradeGoAhead;
+ PolkadotPrimitivesV5UpgradeRestriction: PolkadotPrimitivesV5UpgradeRestriction;
+ PolkadotPrimitivesVstagingAsyncBackingParams: PolkadotPrimitivesVstagingAsyncBackingParams;
+ PortableType: PortableType;
+ PortableTypeV14: PortableTypeV14;
+ Precommits: Precommits;
+ PrefabWasmModule: PrefabWasmModule;
+ PrefixedStorageKey: PrefixedStorageKey;
+ PreimageStatus: PreimageStatus;
+ PreimageStatusAvailable: PreimageStatusAvailable;
+ PreRuntime: PreRuntime;
+ Prevotes: Prevotes;
+ Priority: Priority;
+ PriorLock: PriorLock;
+ PropIndex: PropIndex;
+ Proposal: Proposal;
+ ProposalIndex: ProposalIndex;
+ ProxyAnnouncement: ProxyAnnouncement;
+ ProxyDefinition: ProxyDefinition;
+ ProxyState: ProxyState;
+ ProxyType: ProxyType;
+ PvfCheckStatement: PvfCheckStatement;
+ PvfExecTimeoutKind: PvfExecTimeoutKind;
+ PvfPrepTimeoutKind: PvfPrepTimeoutKind;
+ QueryId: QueryId;
+ QueryStatus: QueryStatus;
+ QueueConfigData: QueueConfigData;
+ QueuedParathread: QueuedParathread;
+ Randomness: Randomness;
+ Raw: Raw;
+ RawAuraPreDigest: RawAuraPreDigest;
+ RawBabePreDigest: RawBabePreDigest;
+ RawBabePreDigestCompat: RawBabePreDigestCompat;
+ RawBabePreDigestPrimary: RawBabePreDigestPrimary;
+ RawBabePreDigestPrimaryTo159: RawBabePreDigestPrimaryTo159;
+ RawBabePreDigestSecondaryPlain: RawBabePreDigestSecondaryPlain;
+ RawBabePreDigestSecondaryTo159: RawBabePreDigestSecondaryTo159;
+ RawBabePreDigestSecondaryVRF: RawBabePreDigestSecondaryVRF;
+ RawBabePreDigestTo159: RawBabePreDigestTo159;
+ RawOrigin: RawOrigin;
+ RawSolution: RawSolution;
+ RawSolutionTo265: RawSolutionTo265;
+ RawSolutionWith16: RawSolutionWith16;
+ RawSolutionWith24: RawSolutionWith24;
+ RawVRFOutput: RawVRFOutput;
+ ReadProof: ReadProof;
+ ReadySolution: ReadySolution;
+ Reasons: Reasons;
+ RecoveryConfig: RecoveryConfig;
+ RefCount: RefCount;
+ RefCountTo259: RefCountTo259;
+ ReferendumIndex: ReferendumIndex;
+ ReferendumInfo: ReferendumInfo;
+ ReferendumInfoFinished: ReferendumInfoFinished;
+ ReferendumInfoTo239: ReferendumInfoTo239;
+ ReferendumStatus: ReferendumStatus;
+ RegisteredParachainInfo: RegisteredParachainInfo;
+ RegistrarIndex: RegistrarIndex;
+ RegistrarInfo: RegistrarInfo;
+ Registration: Registration;
+ RegistrationJudgement: RegistrationJudgement;
+ RegistrationTo198: RegistrationTo198;
+ RelayBlockNumber: RelayBlockNumber;
+ RelayChainBlockNumber: RelayChainBlockNumber;
+ RelayChainHash: RelayChainHash;
+ RelayerId: RelayerId;
+ RelayHash: RelayHash;
+ Releases: Releases;
+ Remark: Remark;
+ Renouncing: Renouncing;
+ RentProjection: RentProjection;
+ ReplacementTimes: ReplacementTimes;
+ ReportedRoundStates: ReportedRoundStates;
+ Reporter: Reporter;
+ ReportIdOf: ReportIdOf;
+ ReserveData: ReserveData;
+ ReserveIdentifier: ReserveIdentifier;
+ Response: Response;
+ ResponseV0: ResponseV0;
+ ResponseV1: ResponseV1;
+ ResponseV2: ResponseV2;
+ ResponseV2Error: ResponseV2Error;
+ ResponseV2Result: ResponseV2Result;
+ Retriable: Retriable;
+ RewardDestination: RewardDestination;
+ RewardPoint: RewardPoint;
+ RoundSnapshot: RoundSnapshot;
+ RoundState: RoundState;
+ RpcMethods: RpcMethods;
+ RuntimeApiMetadataLatest: RuntimeApiMetadataLatest;
+ RuntimeApiMetadataV15: RuntimeApiMetadataV15;
+ RuntimeApiMethodMetadataV15: RuntimeApiMethodMetadataV15;
+ RuntimeApiMethodParamMetadataV15: RuntimeApiMethodParamMetadataV15;
+ RuntimeCall: RuntimeCall;
+ RuntimeDbWeight: RuntimeDbWeight;
+ RuntimeDispatchInfo: RuntimeDispatchInfo;
+ RuntimeDispatchInfoV1: RuntimeDispatchInfoV1;
+ RuntimeDispatchInfoV2: RuntimeDispatchInfoV2;
+ RuntimeEvent: RuntimeEvent;
+ RuntimeVersion: RuntimeVersion;
+ RuntimeVersionApi: RuntimeVersionApi;
+ RuntimeVersionPartial: RuntimeVersionPartial;
+ RuntimeVersionPre3: RuntimeVersionPre3;
+ RuntimeVersionPre4: RuntimeVersionPre4;
+ Schedule: Schedule;
+ Scheduled: Scheduled;
+ ScheduledCore: ScheduledCore;
+ ScheduledTo254: ScheduledTo254;
+ SchedulePeriod: SchedulePeriod;
+ SchedulePriority: SchedulePriority;
+ ScheduleTo212: ScheduleTo212;
+ ScheduleTo258: ScheduleTo258;
+ ScheduleTo264: ScheduleTo264;
+ Scheduling: Scheduling;
+ ScrapedOnChainVotes: ScrapedOnChainVotes;
+ Seal: Seal;
+ SealV0: SealV0;
+ SeatHolder: SeatHolder;
+ SeedOf: SeedOf;
+ ServiceQuality: ServiceQuality;
+ SessionIndex: SessionIndex;
+ SessionInfo: SessionInfo;
+ SessionInfoValidatorGroup: SessionInfoValidatorGroup;
+ SessionKeys1: SessionKeys1;
+ SessionKeys10: SessionKeys10;
+ SessionKeys10B: SessionKeys10B;
+ SessionKeys2: SessionKeys2;
+ SessionKeys3: SessionKeys3;
+ SessionKeys4: SessionKeys4;
+ SessionKeys5: SessionKeys5;
+ SessionKeys6: SessionKeys6;
+ SessionKeys6B: SessionKeys6B;
+ SessionKeys7: SessionKeys7;
+ SessionKeys7B: SessionKeys7B;
+ SessionKeys8: SessionKeys8;
+ SessionKeys8B: SessionKeys8B;
+ SessionKeys9: SessionKeys9;
+ SessionKeys9B: SessionKeys9B;
+ SetId: SetId;
+ SetIndex: SetIndex;
+ Si0Field: Si0Field;
+ Si0LookupTypeId: Si0LookupTypeId;
+ Si0Path: Si0Path;
+ Si0Type: Si0Type;
+ Si0TypeDef: Si0TypeDef;
+ Si0TypeDefArray: Si0TypeDefArray;
+ Si0TypeDefBitSequence: Si0TypeDefBitSequence;
+ Si0TypeDefCompact: Si0TypeDefCompact;
+ Si0TypeDefComposite: Si0TypeDefComposite;
+ Si0TypeDefPhantom: Si0TypeDefPhantom;
+ Si0TypeDefPrimitive: Si0TypeDefPrimitive;
+ Si0TypeDefSequence: Si0TypeDefSequence;
+ Si0TypeDefTuple: Si0TypeDefTuple;
+ Si0TypeDefVariant: Si0TypeDefVariant;
+ Si0TypeParameter: Si0TypeParameter;
+ Si0Variant: Si0Variant;
+ Si1Field: Si1Field;
+ Si1LookupTypeId: Si1LookupTypeId;
+ Si1Path: Si1Path;
+ Si1Type: Si1Type;
+ Si1TypeDef: Si1TypeDef;
+ Si1TypeDefArray: Si1TypeDefArray;
+ Si1TypeDefBitSequence: Si1TypeDefBitSequence;
+ Si1TypeDefCompact: Si1TypeDefCompact;
+ Si1TypeDefComposite: Si1TypeDefComposite;
+ Si1TypeDefPrimitive: Si1TypeDefPrimitive;
+ Si1TypeDefSequence: Si1TypeDefSequence;
+ Si1TypeDefTuple: Si1TypeDefTuple;
+ Si1TypeDefVariant: Si1TypeDefVariant;
+ Si1TypeParameter: Si1TypeParameter;
+ Si1Variant: Si1Variant;
+ SiField: SiField;
+ Signature: Signature;
+ SignedAvailabilityBitfield: SignedAvailabilityBitfield;
+ SignedAvailabilityBitfields: SignedAvailabilityBitfields;
+ SignedBlock: SignedBlock;
+ SignedBlockWithJustification: SignedBlockWithJustification;
+ SignedBlockWithJustifications: SignedBlockWithJustifications;
+ SignedExtensionMetadataLatest: SignedExtensionMetadataLatest;
+ SignedExtensionMetadataV14: SignedExtensionMetadataV14;
+ SignedSubmission: SignedSubmission;
+ SignedSubmissionOf: SignedSubmissionOf;
+ SignedSubmissionTo276: SignedSubmissionTo276;
+ SignerPayload: SignerPayload;
+ SigningContext: SigningContext;
+ SiLookupTypeId: SiLookupTypeId;
+ SiPath: SiPath;
+ SiType: SiType;
+ SiTypeDef: SiTypeDef;
+ SiTypeDefArray: SiTypeDefArray;
+ SiTypeDefBitSequence: SiTypeDefBitSequence;
+ SiTypeDefCompact: SiTypeDefCompact;
+ SiTypeDefComposite: SiTypeDefComposite;
+ SiTypeDefPrimitive: SiTypeDefPrimitive;
+ SiTypeDefSequence: SiTypeDefSequence;
+ SiTypeDefTuple: SiTypeDefTuple;
+ SiTypeDefVariant: SiTypeDefVariant;
+ SiTypeParameter: SiTypeParameter;
+ SiVariant: SiVariant;
+ SlashingOffenceKind: SlashingOffenceKind;
+ SlashingSpans: SlashingSpans;
+ SlashingSpansTo204: SlashingSpansTo204;
+ SlashJournalEntry: SlashJournalEntry;
+ Slot: Slot;
+ SlotDuration: SlotDuration;
+ SlotNumber: SlotNumber;
+ SlotRange: SlotRange;
+ SlotRange10: SlotRange10;
+ SocietyJudgement: SocietyJudgement;
+ SocietyVote: SocietyVote;
+ SolutionOrSnapshotSize: SolutionOrSnapshotSize;
+ SolutionSupport: SolutionSupport;
+ SolutionSupports: SolutionSupports;
+ SpanIndex: SpanIndex;
+ SpanRecord: SpanRecord;
+ SpArithmeticArithmeticError: SpArithmeticArithmeticError;
+ SpConsensusAuraSr25519AppSr25519Public: SpConsensusAuraSr25519AppSr25519Public;
+ SpCoreCryptoKeyTypeId: SpCoreCryptoKeyTypeId;
+ SpCoreEcdsaSignature: SpCoreEcdsaSignature;
+ SpCoreEd25519Signature: SpCoreEd25519Signature;
+ SpCoreSr25519Public: SpCoreSr25519Public;
+ SpCoreSr25519Signature: SpCoreSr25519Signature;
+ SpCoreVoid: SpCoreVoid;
+ SpecVersion: SpecVersion;
+ SpRuntimeDigest: SpRuntimeDigest;
+ SpRuntimeDigestDigestItem: SpRuntimeDigestDigestItem;
+ SpRuntimeDispatchError: SpRuntimeDispatchError;
+ SpRuntimeModuleError: SpRuntimeModuleError;
+ SpRuntimeMultiSignature: SpRuntimeMultiSignature;
+ SpRuntimeTokenError: SpRuntimeTokenError;
+ SpRuntimeTransactionalError: SpRuntimeTransactionalError;
+ SpRuntimeTransactionValidityInvalidTransaction: SpRuntimeTransactionValidityInvalidTransaction;
+ SpRuntimeTransactionValidityTransactionValidityError: SpRuntimeTransactionValidityTransactionValidityError;
+ SpRuntimeTransactionValidityUnknownTransaction: SpRuntimeTransactionValidityUnknownTransaction;
+ SpTrieStorageProof: SpTrieStorageProof;
+ SpVersionRuntimeVersion: SpVersionRuntimeVersion;
+ SpWeightsRuntimeDbWeight: SpWeightsRuntimeDbWeight;
+ SpWeightsWeightV2Weight: SpWeightsWeightV2Weight;
+ Sr25519Signature: Sr25519Signature;
+ StagingXcmDoubleEncoded: StagingXcmDoubleEncoded;
+ StagingXcmV2BodyId: StagingXcmV2BodyId;
+ StagingXcmV2BodyPart: StagingXcmV2BodyPart;
+ StagingXcmV2Instruction: StagingXcmV2Instruction;
+ StagingXcmV2Junction: StagingXcmV2Junction;
+ StagingXcmV2MultiAsset: StagingXcmV2MultiAsset;
+ StagingXcmV2MultiassetAssetId: StagingXcmV2MultiassetAssetId;
+ StagingXcmV2MultiassetAssetInstance: StagingXcmV2MultiassetAssetInstance;
+ StagingXcmV2MultiassetFungibility: StagingXcmV2MultiassetFungibility;
+ StagingXcmV2MultiassetMultiAssetFilter: StagingXcmV2MultiassetMultiAssetFilter;
+ StagingXcmV2MultiassetMultiAssets: StagingXcmV2MultiassetMultiAssets;
+ StagingXcmV2MultiassetWildFungibility: StagingXcmV2MultiassetWildFungibility;
+ StagingXcmV2MultiassetWildMultiAsset: StagingXcmV2MultiassetWildMultiAsset;
+ StagingXcmV2MultiLocation: StagingXcmV2MultiLocation;
+ StagingXcmV2MultilocationJunctions: StagingXcmV2MultilocationJunctions;
+ StagingXcmV2NetworkId: StagingXcmV2NetworkId;
+ StagingXcmV2OriginKind: StagingXcmV2OriginKind;
+ StagingXcmV2Response: StagingXcmV2Response;
+ StagingXcmV2TraitsError: StagingXcmV2TraitsError;
+ StagingXcmV2WeightLimit: StagingXcmV2WeightLimit;
+ StagingXcmV2Xcm: StagingXcmV2Xcm;
+ StagingXcmV3Instruction: StagingXcmV3Instruction;
+ StagingXcmV3Junction: StagingXcmV3Junction;
+ StagingXcmV3JunctionBodyId: StagingXcmV3JunctionBodyId;
+ StagingXcmV3JunctionBodyPart: StagingXcmV3JunctionBodyPart;
+ StagingXcmV3JunctionNetworkId: StagingXcmV3JunctionNetworkId;
+ StagingXcmV3Junctions: StagingXcmV3Junctions;
+ StagingXcmV3MaybeErrorCode: StagingXcmV3MaybeErrorCode;
+ StagingXcmV3MultiAsset: StagingXcmV3MultiAsset;
+ StagingXcmV3MultiassetAssetId: StagingXcmV3MultiassetAssetId;
+ StagingXcmV3MultiassetAssetInstance: StagingXcmV3MultiassetAssetInstance;
+ StagingXcmV3MultiassetFungibility: StagingXcmV3MultiassetFungibility;
+ StagingXcmV3MultiassetMultiAssetFilter: StagingXcmV3MultiassetMultiAssetFilter;
+ StagingXcmV3MultiassetMultiAssets: StagingXcmV3MultiassetMultiAssets;
+ StagingXcmV3MultiassetWildFungibility: StagingXcmV3MultiassetWildFungibility;
+ StagingXcmV3MultiassetWildMultiAsset: StagingXcmV3MultiassetWildMultiAsset;
+ StagingXcmV3MultiLocation: StagingXcmV3MultiLocation;
+ StagingXcmV3PalletInfo: StagingXcmV3PalletInfo;
+ StagingXcmV3QueryResponseInfo: StagingXcmV3QueryResponseInfo;
+ StagingXcmV3Response: StagingXcmV3Response;
+ StagingXcmV3TraitsError: StagingXcmV3TraitsError;
+ StagingXcmV3TraitsOutcome: StagingXcmV3TraitsOutcome;
+ StagingXcmV3WeightLimit: StagingXcmV3WeightLimit;
+ StagingXcmV3Xcm: StagingXcmV3Xcm;
+ StagingXcmVersionedAssetId: StagingXcmVersionedAssetId;
+ StagingXcmVersionedMultiAsset: StagingXcmVersionedMultiAsset;
+ StagingXcmVersionedMultiAssets: StagingXcmVersionedMultiAssets;
+ StagingXcmVersionedMultiLocation: StagingXcmVersionedMultiLocation;
+ StagingXcmVersionedResponse: StagingXcmVersionedResponse;
+ StagingXcmVersionedXcm: StagingXcmVersionedXcm;
+ StakingLedger: StakingLedger;
+ StakingLedgerTo223: StakingLedgerTo223;
+ StakingLedgerTo240: StakingLedgerTo240;
+ Statement: Statement;
+ StatementKind: StatementKind;
+ StorageChangeSet: StorageChangeSet;
+ StorageData: StorageData;
+ StorageDeposit: StorageDeposit;
+ StorageEntryMetadataLatest: StorageEntryMetadataLatest;
+ StorageEntryMetadataV10: StorageEntryMetadataV10;
+ StorageEntryMetadataV11: StorageEntryMetadataV11;
+ StorageEntryMetadataV12: StorageEntryMetadataV12;
+ StorageEntryMetadataV13: StorageEntryMetadataV13;
+ StorageEntryMetadataV14: StorageEntryMetadataV14;
+ StorageEntryMetadataV9: StorageEntryMetadataV9;
+ StorageEntryModifierLatest: StorageEntryModifierLatest;
+ StorageEntryModifierV10: StorageEntryModifierV10;
+ StorageEntryModifierV11: StorageEntryModifierV11;
+ StorageEntryModifierV12: StorageEntryModifierV12;
+ StorageEntryModifierV13: StorageEntryModifierV13;
+ StorageEntryModifierV14: StorageEntryModifierV14;
+ StorageEntryModifierV9: StorageEntryModifierV9;
+ StorageEntryTypeLatest: StorageEntryTypeLatest;
+ StorageEntryTypeV10: StorageEntryTypeV10;
+ StorageEntryTypeV11: StorageEntryTypeV11;
+ StorageEntryTypeV12: StorageEntryTypeV12;
+ StorageEntryTypeV13: StorageEntryTypeV13;
+ StorageEntryTypeV14: StorageEntryTypeV14;
+ StorageEntryTypeV9: StorageEntryTypeV9;
+ StorageHasher: StorageHasher;
+ StorageHasherV10: StorageHasherV10;
+ StorageHasherV11: StorageHasherV11;
+ StorageHasherV12: StorageHasherV12;
+ StorageHasherV13: StorageHasherV13;
+ StorageHasherV14: StorageHasherV14;
+ StorageHasherV9: StorageHasherV9;
+ StorageInfo: StorageInfo;
+ StorageKey: StorageKey;
+ StorageKind: StorageKind;
+ StorageMetadataV10: StorageMetadataV10;
+ StorageMetadataV11: StorageMetadataV11;
+ StorageMetadataV12: StorageMetadataV12;
+ StorageMetadataV13: StorageMetadataV13;
+ StorageMetadataV9: StorageMetadataV9;
+ StorageProof: StorageProof;
+ StoredPendingChange: StoredPendingChange;
+ StoredState: StoredState;
+ StrikeCount: StrikeCount;
+ SubId: SubId;
+ SubmissionIndicesOf: SubmissionIndicesOf;
+ Supports: Supports;
+ SyncState: SyncState;
+ SystemInherentData: SystemInherentData;
+ SystemOrigin: SystemOrigin;
+ Tally: Tally;
+ TaskAddress: TaskAddress;
+ TAssetBalance: TAssetBalance;
+ TAssetDepositBalance: TAssetDepositBalance;
+ Text: Text;
+ Timepoint: Timepoint;
+ TokenError: TokenError;
+ TombstoneContractInfo: TombstoneContractInfo;
+ TraceBlockResponse: TraceBlockResponse;
+ TraceError: TraceError;
+ TransactionalError: TransactionalError;
+ TransactionInfo: TransactionInfo;
+ TransactionLongevity: TransactionLongevity;
+ TransactionPriority: TransactionPriority;
+ TransactionSource: TransactionSource;
+ TransactionStorageProof: TransactionStorageProof;
+ TransactionTag: TransactionTag;
+ TransactionV0: TransactionV0;
+ TransactionV1: TransactionV1;
+ TransactionV2: TransactionV2;
+ TransactionValidity: TransactionValidity;
+ TransactionValidityError: TransactionValidityError;
+ TransientValidationData: TransientValidationData;
+ TreasuryProposal: TreasuryProposal;
+ TrieId: TrieId;
+ TrieIndex: TrieIndex;
+ Type: Type;
+ u128: u128;
+ U128: U128;
+ u16: u16;
+ U16: U16;
+ u256: u256;
+ U256: U256;
+ u32: u32;
+ U32: U32;
+ U32F32: U32F32;
+ u64: u64;
+ U64: U64;
+ u8: u8;
+ U8: U8;
+ UnappliedSlash: UnappliedSlash;
+ UnappliedSlashOther: UnappliedSlashOther;
+ UncleEntryItem: UncleEntryItem;
+ UnknownTransaction: UnknownTransaction;
+ UnlockChunk: UnlockChunk;
+ UnrewardedRelayer: UnrewardedRelayer;
+ UnrewardedRelayersState: UnrewardedRelayersState;
+ UpDataStructsAccessMode: UpDataStructsAccessMode;
+ UpDataStructsCollection: UpDataStructsCollection;
+ UpDataStructsCollectionLimits: UpDataStructsCollectionLimits;
+ UpDataStructsCollectionMode: UpDataStructsCollectionMode;
+ UpDataStructsCollectionPermissions: UpDataStructsCollectionPermissions;
+ UpDataStructsCollectionStats: UpDataStructsCollectionStats;
+ UpDataStructsCreateCollectionData: UpDataStructsCreateCollectionData;
+ UpDataStructsCreateFungibleData: UpDataStructsCreateFungibleData;
+ UpDataStructsCreateItemData: UpDataStructsCreateItemData;
+ UpDataStructsCreateItemExData: UpDataStructsCreateItemExData;
+ UpDataStructsCreateNftData: UpDataStructsCreateNftData;
+ UpDataStructsCreateNftExData: UpDataStructsCreateNftExData;
+ UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData;
+ UpDataStructsCreateRefungibleExMultipleOwners: UpDataStructsCreateRefungibleExMultipleOwners;
+ UpDataStructsCreateRefungibleExSingleOwner: UpDataStructsCreateRefungibleExSingleOwner;
+ UpDataStructsNestingPermissions: UpDataStructsNestingPermissions;
+ UpDataStructsOwnerRestrictedSet: UpDataStructsOwnerRestrictedSet;
+ UpDataStructsProperties: UpDataStructsProperties;
+ UpDataStructsPropertiesMapBoundedVec: UpDataStructsPropertiesMapBoundedVec;
+ UpDataStructsPropertiesMapPropertyPermission: UpDataStructsPropertiesMapPropertyPermission;
+ UpDataStructsProperty: UpDataStructsProperty;
+ UpDataStructsPropertyKeyPermission: UpDataStructsPropertyKeyPermission;
+ UpDataStructsPropertyPermission: UpDataStructsPropertyPermission;
+ UpDataStructsPropertyScope: UpDataStructsPropertyScope;
+ UpDataStructsRpcCollection: UpDataStructsRpcCollection;
+ UpDataStructsRpcCollectionFlags: UpDataStructsRpcCollectionFlags;
+ UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
+ UpDataStructsSponsorshipStateAccountId32: UpDataStructsSponsorshipStateAccountId32;
+ UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: UpDataStructsSponsorshipStateBasicCrossAccountIdRepr;
+ UpDataStructsTokenChild: UpDataStructsTokenChild;
+ UpDataStructsTokenData: UpDataStructsTokenData;
+ UpgradeGoAhead: UpgradeGoAhead;
+ UpgradeRestriction: UpgradeRestriction;
+ UpPovEstimateRpcPovInfo: UpPovEstimateRpcPovInfo;
+ UpPovEstimateRpcTrieKeyValue: UpPovEstimateRpcTrieKeyValue;
+ UpwardMessage: UpwardMessage;
+ usize: usize;
+ USize: USize;
+ ValidationCode: ValidationCode;
+ ValidationCodeHash: ValidationCodeHash;
+ ValidationData: ValidationData;
+ ValidationDataType: ValidationDataType;
+ ValidationFunctionParams: ValidationFunctionParams;
+ ValidatorCount: ValidatorCount;
+ ValidatorId: ValidatorId;
+ ValidatorIdOf: ValidatorIdOf;
+ ValidatorIndex: ValidatorIndex;
+ ValidatorIndexCompact: ValidatorIndexCompact;
+ ValidatorPrefs: ValidatorPrefs;
+ ValidatorPrefsTo145: ValidatorPrefsTo145;
+ ValidatorPrefsTo196: ValidatorPrefsTo196;
+ ValidatorPrefsWithBlocked: ValidatorPrefsWithBlocked;
+ ValidatorPrefsWithCommission: ValidatorPrefsWithCommission;
+ ValidatorSet: ValidatorSet;
+ ValidatorSetId: ValidatorSetId;
+ ValidatorSignature: ValidatorSignature;
+ ValidDisputeStatementKind: ValidDisputeStatementKind;
+ ValidityAttestation: ValidityAttestation;
+ ValidTransaction: ValidTransaction;
+ VecInboundHrmpMessage: VecInboundHrmpMessage;
+ VersionedMultiAsset: VersionedMultiAsset;
+ VersionedMultiAssets: VersionedMultiAssets;
+ VersionedMultiLocation: VersionedMultiLocation;
+ VersionedResponse: VersionedResponse;
+ VersionedXcm: VersionedXcm;
+ VersionMigrationStage: VersionMigrationStage;
+ VestingInfo: VestingInfo;
+ VestingSchedule: VestingSchedule;
+ Vote: Vote;
+ VoteIndex: VoteIndex;
+ Voter: Voter;
+ VoterInfo: VoterInfo;
+ Votes: Votes;
+ VotesTo230: VotesTo230;
+ VoteThreshold: VoteThreshold;
+ VoteWeight: VoteWeight;
+ Voting: Voting;
+ VotingDelegating: VotingDelegating;
+ VotingDirect: VotingDirect;
+ VotingDirectVote: VotingDirectVote;
+ VouchingStatus: VouchingStatus;
+ VrfData: VrfData;
+ VrfOutput: VrfOutput;
+ VrfProof: VrfProof;
+ Weight: Weight;
+ WeightLimitV2: WeightLimitV2;
+ WeightMultiplier: WeightMultiplier;
+ WeightPerClass: WeightPerClass;
+ WeightToFeeCoefficient: WeightToFeeCoefficient;
+ WeightV0: WeightV0;
+ WeightV1: WeightV1;
+ WeightV2: WeightV2;
+ WildFungibility: WildFungibility;
+ WildFungibilityV0: WildFungibilityV0;
+ WildFungibilityV1: WildFungibilityV1;
+ WildFungibilityV2: WildFungibilityV2;
+ WildMultiAsset: WildMultiAsset;
+ WildMultiAssetV1: WildMultiAssetV1;
+ WildMultiAssetV2: WildMultiAssetV2;
+ WinnersData: WinnersData;
+ WinnersData10: WinnersData10;
+ WinnersDataTuple: WinnersDataTuple;
+ WinnersDataTuple10: WinnersDataTuple10;
+ WinningData: WinningData;
+ WinningData10: WinningData10;
+ WinningDataEntry: WinningDataEntry;
+ WithdrawReasons: WithdrawReasons;
+ Xcm: Xcm;
+ XcmAssetId: XcmAssetId;
+ XcmError: XcmError;
+ XcmErrorV0: XcmErrorV0;
+ XcmErrorV1: XcmErrorV1;
+ XcmErrorV2: XcmErrorV2;
+ XcmOrder: XcmOrder;
+ XcmOrderV0: XcmOrderV0;
+ XcmOrderV1: XcmOrderV1;
+ XcmOrderV2: XcmOrderV2;
+ XcmOrigin: XcmOrigin;
+ XcmOriginKind: XcmOriginKind;
+ XcmpMessageFormat: XcmpMessageFormat;
+ XcmV0: XcmV0;
+ XcmV1: XcmV1;
+ XcmV2: XcmV2;
+ XcmVersion: XcmVersion;
+ } // InterfaceTypes
+} // declare module
js-packages/types/default/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/default/definitions.ts
@@ -0,0 +1,6 @@
+import types from '../lookup.js';
+
+export default {
+ types,
+ rpc: {},
+};
js-packages/types/default/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/default/index.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './types.js';
js-packages/types/default/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/default/types.ts
@@ -0,0 +1,5537 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+import type { Data } from '@polkadot/types';
+import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, i64, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { ITuple } from '@polkadot/types-codec/types';
+import type { Vote } from '@polkadot/types/interfaces/elections';
+import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
+import type { Event } from '@polkadot/types/interfaces/system';
+
+/** @name CumulusPalletDmpQueueCall */
+export interface CumulusPalletDmpQueueCall extends Enum {
+ readonly isServiceOverweight: boolean;
+ readonly asServiceOverweight: {
+ readonly index: u64;
+ readonly weightLimit: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'ServiceOverweight';
+}
+
+/** @name CumulusPalletDmpQueueConfigData */
+export interface CumulusPalletDmpQueueConfigData extends Struct {
+ readonly maxIndividual: SpWeightsWeightV2Weight;
+}
+
+/** @name CumulusPalletDmpQueueError */
+export interface CumulusPalletDmpQueueError extends Enum {
+ readonly isUnknown: boolean;
+ readonly isOverLimit: boolean;
+ readonly type: 'Unknown' | 'OverLimit';
+}
+
+/** @name CumulusPalletDmpQueueEvent */
+export interface CumulusPalletDmpQueueEvent extends Enum {
+ readonly isInvalidFormat: boolean;
+ readonly asInvalidFormat: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isUnsupportedVersion: boolean;
+ readonly asUnsupportedVersion: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isExecutedDownward: boolean;
+ readonly asExecutedDownward: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly outcome: StagingXcmV3TraitsOutcome;
+ } & Struct;
+ readonly isWeightExhausted: boolean;
+ readonly asWeightExhausted: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly remainingWeight: SpWeightsWeightV2Weight;
+ readonly requiredWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isOverweightEnqueued: boolean;
+ readonly asOverweightEnqueued: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly overweightIndex: u64;
+ readonly requiredWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isOverweightServiced: boolean;
+ readonly asOverweightServiced: {
+ readonly overweightIndex: u64;
+ readonly weightUsed: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isMaxMessagesExhausted: boolean;
+ readonly asMaxMessagesExhausted: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced' | 'MaxMessagesExhausted';
+}
+
+/** @name CumulusPalletDmpQueuePageIndexData */
+export interface CumulusPalletDmpQueuePageIndexData extends Struct {
+ readonly beginUsed: u32;
+ readonly endUsed: u32;
+ readonly overweightCount: u64;
+}
+
+/** @name CumulusPalletParachainSystemCall */
+export interface CumulusPalletParachainSystemCall extends Enum {
+ readonly isSetValidationData: boolean;
+ readonly asSetValidationData: {
+ readonly data: CumulusPrimitivesParachainInherentParachainInherentData;
+ } & Struct;
+ readonly isSudoSendUpwardMessage: boolean;
+ readonly asSudoSendUpwardMessage: {
+ readonly message: Bytes;
+ } & Struct;
+ readonly isAuthorizeUpgrade: boolean;
+ readonly asAuthorizeUpgrade: {
+ readonly codeHash: H256;
+ readonly checkVersion: bool;
+ } & Struct;
+ readonly isEnactAuthorizedUpgrade: boolean;
+ readonly asEnactAuthorizedUpgrade: {
+ readonly code: Bytes;
+ } & Struct;
+ readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
+}
+
+/** @name CumulusPalletParachainSystemCodeUpgradeAuthorization */
+export interface CumulusPalletParachainSystemCodeUpgradeAuthorization extends Struct {
+ readonly codeHash: H256;
+ readonly checkVersion: bool;
+}
+
+/** @name CumulusPalletParachainSystemError */
+export interface CumulusPalletParachainSystemError extends Enum {
+ readonly isOverlappingUpgrades: boolean;
+ readonly isProhibitedByPolkadot: boolean;
+ readonly isTooBig: boolean;
+ readonly isValidationDataNotAvailable: boolean;
+ readonly isHostConfigurationNotAvailable: boolean;
+ readonly isNotScheduled: boolean;
+ readonly isNothingAuthorized: boolean;
+ readonly isUnauthorized: boolean;
+ readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
+}
+
+/** @name CumulusPalletParachainSystemEvent */
+export interface CumulusPalletParachainSystemEvent extends Enum {
+ readonly isValidationFunctionStored: boolean;
+ readonly isValidationFunctionApplied: boolean;
+ readonly asValidationFunctionApplied: {
+ readonly relayChainBlockNum: u32;
+ } & Struct;
+ readonly isValidationFunctionDiscarded: boolean;
+ readonly isUpgradeAuthorized: boolean;
+ readonly asUpgradeAuthorized: {
+ readonly codeHash: H256;
+ } & Struct;
+ readonly isDownwardMessagesReceived: boolean;
+ readonly asDownwardMessagesReceived: {
+ readonly count: u32;
+ } & Struct;
+ readonly isDownwardMessagesProcessed: boolean;
+ readonly asDownwardMessagesProcessed: {
+ readonly weightUsed: SpWeightsWeightV2Weight;
+ readonly dmqHead: H256;
+ } & Struct;
+ readonly isUpwardMessageSent: boolean;
+ readonly asUpwardMessageSent: {
+ readonly messageHash: Option<U8aFixed>;
+ } & Struct;
+ readonly type: 'ValidationFunctionStored' | 'ValidationFunctionApplied' | 'ValidationFunctionDiscarded' | 'UpgradeAuthorized' | 'DownwardMessagesReceived' | 'DownwardMessagesProcessed' | 'UpwardMessageSent';
+}
+
+/** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot */
+export interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
+ readonly dmqMqcHead: H256;
+ readonly relayDispatchQueueRemainingCapacity: CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity;
+ readonly ingressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
+ readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
+}
+
+/** @name CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity */
+export interface CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity extends Struct {
+ readonly remainingCount: u32;
+ readonly remainingSize: u32;
+}
+
+/** @name CumulusPalletParachainSystemUnincludedSegmentAncestor */
+export interface CumulusPalletParachainSystemUnincludedSegmentAncestor extends Struct {
+ readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
+ readonly paraHeadHash: Option<H256>;
+ readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
+}
+
+/** @name CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate */
+export interface CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate extends Struct {
+ readonly msgCount: u32;
+ readonly totalBytes: u32;
+}
+
+/** @name CumulusPalletParachainSystemUnincludedSegmentSegmentTracker */
+export interface CumulusPalletParachainSystemUnincludedSegmentSegmentTracker extends Struct {
+ readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
+ readonly hrmpWatermark: Option<u32>;
+ readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
+}
+
+/** @name CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth */
+export interface CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth extends Struct {
+ readonly umpMsgCount: u32;
+ readonly umpTotalBytes: u32;
+ readonly hrmpOutgoing: BTreeMap<u32, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate>;
+}
+
+/** @name CumulusPalletXcmCall */
+export interface CumulusPalletXcmCall extends Null {}
+
+/** @name CumulusPalletXcmError */
+export interface CumulusPalletXcmError extends Null {}
+
+/** @name CumulusPalletXcmEvent */
+export interface CumulusPalletXcmEvent extends Enum {
+ readonly isInvalidFormat: boolean;
+ readonly asInvalidFormat: U8aFixed;
+ readonly isUnsupportedVersion: boolean;
+ readonly asUnsupportedVersion: U8aFixed;
+ readonly isExecutedDownward: boolean;
+ readonly asExecutedDownward: ITuple<[U8aFixed, StagingXcmV3TraitsOutcome]>;
+ readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward';
+}
+
+/** @name CumulusPalletXcmOrigin */
+export interface CumulusPalletXcmOrigin extends Enum {
+ readonly isRelay: boolean;
+ readonly isSiblingParachain: boolean;
+ readonly asSiblingParachain: u32;
+ readonly type: 'Relay' | 'SiblingParachain';
+}
+
+/** @name CumulusPalletXcmpQueueCall */
+export interface CumulusPalletXcmpQueueCall extends Enum {
+ readonly isServiceOverweight: boolean;
+ readonly asServiceOverweight: {
+ readonly index: u64;
+ readonly weightLimit: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isSuspendXcmExecution: boolean;
+ readonly isResumeXcmExecution: boolean;
+ readonly isUpdateSuspendThreshold: boolean;
+ readonly asUpdateSuspendThreshold: {
+ readonly new_: u32;
+ } & Struct;
+ readonly isUpdateDropThreshold: boolean;
+ readonly asUpdateDropThreshold: {
+ readonly new_: u32;
+ } & Struct;
+ readonly isUpdateResumeThreshold: boolean;
+ readonly asUpdateResumeThreshold: {
+ readonly new_: u32;
+ } & Struct;
+ readonly isUpdateThresholdWeight: boolean;
+ readonly asUpdateThresholdWeight: {
+ readonly new_: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isUpdateWeightRestrictDecay: boolean;
+ readonly asUpdateWeightRestrictDecay: {
+ readonly new_: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isUpdateXcmpMaxIndividualWeight: boolean;
+ readonly asUpdateXcmpMaxIndividualWeight: {
+ readonly new_: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
+}
+
+/** @name CumulusPalletXcmpQueueError */
+export interface CumulusPalletXcmpQueueError extends Enum {
+ readonly isFailedToSend: boolean;
+ readonly isBadXcmOrigin: boolean;
+ readonly isBadXcm: boolean;
+ readonly isBadOverweightIndex: boolean;
+ readonly isWeightOverLimit: boolean;
+ readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
+}
+
+/** @name CumulusPalletXcmpQueueEvent */
+export interface CumulusPalletXcmpQueueEvent extends Enum {
+ readonly isSuccess: boolean;
+ readonly asSuccess: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isFail: boolean;
+ readonly asFail: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly error: StagingXcmV3TraitsError;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isBadVersion: boolean;
+ readonly asBadVersion: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isBadFormat: boolean;
+ readonly asBadFormat: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isXcmpMessageSent: boolean;
+ readonly asXcmpMessageSent: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isOverweightEnqueued: boolean;
+ readonly asOverweightEnqueued: {
+ readonly sender: u32;
+ readonly sentAt: u32;
+ readonly index: u64;
+ readonly required: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isOverweightServiced: boolean;
+ readonly asOverweightServiced: {
+ readonly index: u64;
+ readonly used: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced';
+}
+
+/** @name CumulusPalletXcmpQueueInboundChannelDetails */
+export interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
+ readonly sender: u32;
+ readonly state: CumulusPalletXcmpQueueInboundState;
+ readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat]>>;
+}
+
+/** @name CumulusPalletXcmpQueueInboundState */
+export interface CumulusPalletXcmpQueueInboundState extends Enum {
+ readonly isOk: boolean;
+ readonly isSuspended: boolean;
+ readonly type: 'Ok' | 'Suspended';
+}
+
+/** @name CumulusPalletXcmpQueueOutboundChannelDetails */
+export interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
+ readonly recipient: u32;
+ readonly state: CumulusPalletXcmpQueueOutboundState;
+ readonly signalsExist: bool;
+ readonly firstIndex: u16;
+ readonly lastIndex: u16;
+}
+
+/** @name CumulusPalletXcmpQueueOutboundState */
+export interface CumulusPalletXcmpQueueOutboundState extends Enum {
+ readonly isOk: boolean;
+ readonly isSuspended: boolean;
+ readonly type: 'Ok' | 'Suspended';
+}
+
+/** @name CumulusPalletXcmpQueueQueueConfigData */
+export interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
+ readonly suspendThreshold: u32;
+ readonly dropThreshold: u32;
+ readonly resumeThreshold: u32;
+ readonly thresholdWeight: SpWeightsWeightV2Weight;
+ readonly weightRestrictDecay: SpWeightsWeightV2Weight;
+ readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight;
+}
+
+/** @name CumulusPrimitivesParachainInherentParachainInherentData */
+export interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
+ readonly validationData: PolkadotPrimitivesV5PersistedValidationData;
+ readonly relayChainState: SpTrieStorageProof;
+ readonly downwardMessages: Vec<PolkadotCorePrimitivesInboundDownwardMessage>;
+ readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
+}
+
+/** @name EthbloomBloom */
+export interface EthbloomBloom extends U8aFixed {}
+
+/** @name EthereumBlock */
+export interface EthereumBlock extends Struct {
+ readonly header: EthereumHeader;
+ readonly transactions: Vec<EthereumTransactionTransactionV2>;
+ readonly ommers: Vec<EthereumHeader>;
+}
+
+/** @name EthereumHeader */
+export interface EthereumHeader extends Struct {
+ readonly parentHash: H256;
+ readonly ommersHash: H256;
+ readonly beneficiary: H160;
+ readonly stateRoot: H256;
+ readonly transactionsRoot: H256;
+ readonly receiptsRoot: H256;
+ readonly logsBloom: EthbloomBloom;
+ readonly difficulty: U256;
+ readonly number: U256;
+ readonly gasLimit: U256;
+ readonly gasUsed: U256;
+ readonly timestamp: u64;
+ readonly extraData: Bytes;
+ readonly mixHash: H256;
+ readonly nonce: EthereumTypesHashH64;
+}
+
+/** @name EthereumLog */
+export interface EthereumLog extends Struct {
+ readonly address: H160;
+ readonly topics: Vec<H256>;
+ readonly data: Bytes;
+}
+
+/** @name EthereumReceiptEip658ReceiptData */
+export interface EthereumReceiptEip658ReceiptData extends Struct {
+ readonly statusCode: u8;
+ readonly usedGas: U256;
+ readonly logsBloom: EthbloomBloom;
+ readonly logs: Vec<EthereumLog>;
+}
+
+/** @name EthereumReceiptReceiptV3 */
+export interface EthereumReceiptReceiptV3 extends Enum {
+ readonly isLegacy: boolean;
+ readonly asLegacy: EthereumReceiptEip658ReceiptData;
+ readonly isEip2930: boolean;
+ readonly asEip2930: EthereumReceiptEip658ReceiptData;
+ readonly isEip1559: boolean;
+ readonly asEip1559: EthereumReceiptEip658ReceiptData;
+ readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
+}
+
+/** @name EthereumTransactionAccessListItem */
+export interface EthereumTransactionAccessListItem extends Struct {
+ readonly address: H160;
+ readonly storageKeys: Vec<H256>;
+}
+
+/** @name EthereumTransactionEip1559Transaction */
+export interface EthereumTransactionEip1559Transaction extends Struct {
+ readonly chainId: u64;
+ readonly nonce: U256;
+ readonly maxPriorityFeePerGas: U256;
+ readonly maxFeePerGas: U256;
+ readonly gasLimit: U256;
+ readonly action: EthereumTransactionTransactionAction;
+ readonly value: U256;
+ readonly input: Bytes;
+ readonly accessList: Vec<EthereumTransactionAccessListItem>;
+ readonly oddYParity: bool;
+ readonly r: H256;
+ readonly s: H256;
+}
+
+/** @name EthereumTransactionEip2930Transaction */
+export interface EthereumTransactionEip2930Transaction extends Struct {
+ readonly chainId: u64;
+ readonly nonce: U256;
+ readonly gasPrice: U256;
+ readonly gasLimit: U256;
+ readonly action: EthereumTransactionTransactionAction;
+ readonly value: U256;
+ readonly input: Bytes;
+ readonly accessList: Vec<EthereumTransactionAccessListItem>;
+ readonly oddYParity: bool;
+ readonly r: H256;
+ readonly s: H256;
+}
+
+/** @name EthereumTransactionLegacyTransaction */
+export interface EthereumTransactionLegacyTransaction extends Struct {
+ readonly nonce: U256;
+ readonly gasPrice: U256;
+ readonly gasLimit: U256;
+ readonly action: EthereumTransactionTransactionAction;
+ readonly value: U256;
+ readonly input: Bytes;
+ readonly signature: EthereumTransactionTransactionSignature;
+}
+
+/** @name EthereumTransactionTransactionAction */
+export interface EthereumTransactionTransactionAction extends Enum {
+ readonly isCall: boolean;
+ readonly asCall: H160;
+ readonly isCreate: boolean;
+ readonly type: 'Call' | 'Create';
+}
+
+/** @name EthereumTransactionTransactionSignature */
+export interface EthereumTransactionTransactionSignature extends Struct {
+ readonly v: u64;
+ readonly r: H256;
+ readonly s: H256;
+}
+
+/** @name EthereumTransactionTransactionV2 */
+export interface EthereumTransactionTransactionV2 extends Enum {
+ readonly isLegacy: boolean;
+ readonly asLegacy: EthereumTransactionLegacyTransaction;
+ readonly isEip2930: boolean;
+ readonly asEip2930: EthereumTransactionEip2930Transaction;
+ readonly isEip1559: boolean;
+ readonly asEip1559: EthereumTransactionEip1559Transaction;
+ readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
+}
+
+/** @name EthereumTypesHashH64 */
+export interface EthereumTypesHashH64 extends U8aFixed {}
+
+/** @name EvmCoreErrorExitError */
+export interface EvmCoreErrorExitError extends Enum {
+ readonly isStackUnderflow: boolean;
+ readonly isStackOverflow: boolean;
+ readonly isInvalidJump: boolean;
+ readonly isInvalidRange: boolean;
+ readonly isDesignatedInvalid: boolean;
+ readonly isCallTooDeep: boolean;
+ readonly isCreateCollision: boolean;
+ readonly isCreateContractLimit: boolean;
+ readonly isOutOfOffset: boolean;
+ readonly isOutOfGas: boolean;
+ readonly isOutOfFund: boolean;
+ readonly isPcUnderflow: boolean;
+ readonly isCreateEmpty: boolean;
+ readonly isOther: boolean;
+ readonly asOther: Text;
+ readonly isMaxNonce: boolean;
+ readonly isInvalidCode: boolean;
+ readonly asInvalidCode: u8;
+ readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'MaxNonce' | 'InvalidCode';
+}
+
+/** @name EvmCoreErrorExitFatal */
+export interface EvmCoreErrorExitFatal extends Enum {
+ readonly isNotSupported: boolean;
+ readonly isUnhandledInterrupt: boolean;
+ readonly isCallErrorAsFatal: boolean;
+ readonly asCallErrorAsFatal: EvmCoreErrorExitError;
+ readonly isOther: boolean;
+ readonly asOther: Text;
+ readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
+}
+
+/** @name EvmCoreErrorExitReason */
+export interface EvmCoreErrorExitReason extends Enum {
+ readonly isSucceed: boolean;
+ readonly asSucceed: EvmCoreErrorExitSucceed;
+ readonly isError: boolean;
+ readonly asError: EvmCoreErrorExitError;
+ readonly isRevert: boolean;
+ readonly asRevert: EvmCoreErrorExitRevert;
+ readonly isFatal: boolean;
+ readonly asFatal: EvmCoreErrorExitFatal;
+ readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
+}
+
+/** @name EvmCoreErrorExitRevert */
+export interface EvmCoreErrorExitRevert extends Enum {
+ readonly isReverted: boolean;
+ readonly type: 'Reverted';
+}
+
+/** @name EvmCoreErrorExitSucceed */
+export interface EvmCoreErrorExitSucceed extends Enum {
+ readonly isStopped: boolean;
+ readonly isReturned: boolean;
+ readonly isSuicided: boolean;
+ readonly type: 'Stopped' | 'Returned' | 'Suicided';
+}
+
+/** @name FpRpcTransactionStatus */
+export interface FpRpcTransactionStatus extends Struct {
+ readonly transactionHash: H256;
+ readonly transactionIndex: u32;
+ readonly from: H160;
+ readonly to: Option<H160>;
+ readonly contractAddress: Option<H160>;
+ readonly logs: Vec<EthereumLog>;
+ readonly logsBloom: EthbloomBloom;
+}
+
+/** @name FrameSupportDispatchDispatchClass */
+export interface FrameSupportDispatchDispatchClass extends Enum {
+ readonly isNormal: boolean;
+ readonly isOperational: boolean;
+ readonly isMandatory: boolean;
+ readonly type: 'Normal' | 'Operational' | 'Mandatory';
+}
+
+/** @name FrameSupportDispatchDispatchInfo */
+export interface FrameSupportDispatchDispatchInfo extends Struct {
+ readonly weight: SpWeightsWeightV2Weight;
+ readonly class: FrameSupportDispatchDispatchClass;
+ readonly paysFee: FrameSupportDispatchPays;
+}
+
+/** @name FrameSupportDispatchPays */
+export interface FrameSupportDispatchPays extends Enum {
+ readonly isYes: boolean;
+ readonly isNo: boolean;
+ readonly type: 'Yes' | 'No';
+}
+
+/** @name FrameSupportDispatchPerDispatchClassU32 */
+export interface FrameSupportDispatchPerDispatchClassU32 extends Struct {
+ readonly normal: u32;
+ readonly operational: u32;
+ readonly mandatory: u32;
+}
+
+/** @name FrameSupportDispatchPerDispatchClassWeight */
+export interface FrameSupportDispatchPerDispatchClassWeight extends Struct {
+ readonly normal: SpWeightsWeightV2Weight;
+ readonly operational: SpWeightsWeightV2Weight;
+ readonly mandatory: SpWeightsWeightV2Weight;
+}
+
+/** @name FrameSupportDispatchPerDispatchClassWeightsPerClass */
+export interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct {
+ readonly normal: FrameSystemLimitsWeightsPerClass;
+ readonly operational: FrameSystemLimitsWeightsPerClass;
+ readonly mandatory: FrameSystemLimitsWeightsPerClass;
+}
+
+/** @name FrameSupportDispatchRawOrigin */
+export interface FrameSupportDispatchRawOrigin extends Enum {
+ readonly isRoot: boolean;
+ readonly isSigned: boolean;
+ readonly asSigned: AccountId32;
+ readonly isNone: boolean;
+ readonly type: 'Root' | 'Signed' | 'None';
+}
+
+/** @name FrameSupportPalletId */
+export interface FrameSupportPalletId extends U8aFixed {}
+
+/** @name FrameSupportPreimagesBounded */
+export interface FrameSupportPreimagesBounded extends Enum {
+ readonly isLegacy: boolean;
+ readonly asLegacy: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isInline: boolean;
+ readonly asInline: Bytes;
+ readonly isLookup: boolean;
+ readonly asLookup: {
+ readonly hash_: H256;
+ readonly len: u32;
+ } & Struct;
+ readonly type: 'Legacy' | 'Inline' | 'Lookup';
+}
+
+/** @name FrameSupportScheduleDispatchTime */
+export interface FrameSupportScheduleDispatchTime extends Enum {
+ readonly isAt: boolean;
+ readonly asAt: u32;
+ readonly isAfter: boolean;
+ readonly asAfter: u32;
+ readonly type: 'At' | 'After';
+}
+
+/** @name FrameSupportTokensMiscBalanceStatus */
+export interface FrameSupportTokensMiscBalanceStatus extends Enum {
+ readonly isFree: boolean;
+ readonly isReserved: boolean;
+ readonly type: 'Free' | 'Reserved';
+}
+
+/** @name FrameSystemAccountInfo */
+export interface FrameSystemAccountInfo extends Struct {
+ readonly nonce: u32;
+ readonly consumers: u32;
+ readonly providers: u32;
+ readonly sufficients: u32;
+ readonly data: PalletBalancesAccountData;
+}
+
+/** @name FrameSystemCall */
+export interface FrameSystemCall extends Enum {
+ readonly isRemark: boolean;
+ readonly asRemark: {
+ readonly remark: Bytes;
+ } & Struct;
+ readonly isSetHeapPages: boolean;
+ readonly asSetHeapPages: {
+ readonly pages: u64;
+ } & Struct;
+ readonly isSetCode: boolean;
+ readonly asSetCode: {
+ readonly code: Bytes;
+ } & Struct;
+ readonly isSetCodeWithoutChecks: boolean;
+ readonly asSetCodeWithoutChecks: {
+ readonly code: Bytes;
+ } & Struct;
+ readonly isSetStorage: boolean;
+ readonly asSetStorage: {
+ readonly items: Vec<ITuple<[Bytes, Bytes]>>;
+ } & Struct;
+ readonly isKillStorage: boolean;
+ readonly asKillStorage: {
+ readonly keys_: Vec<Bytes>;
+ } & Struct;
+ readonly isKillPrefix: boolean;
+ readonly asKillPrefix: {
+ readonly prefix: Bytes;
+ readonly subkeys: u32;
+ } & Struct;
+ readonly isRemarkWithEvent: boolean;
+ readonly asRemarkWithEvent: {
+ readonly remark: Bytes;
+ } & Struct;
+ readonly type: 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
+}
+
+/** @name FrameSystemError */
+export interface FrameSystemError extends Enum {
+ readonly isInvalidSpecName: boolean;
+ readonly isSpecVersionNeedsToIncrease: boolean;
+ readonly isFailedToExtractRuntimeVersion: boolean;
+ readonly isNonDefaultComposite: boolean;
+ readonly isNonZeroRefCount: boolean;
+ readonly isCallFiltered: boolean;
+ readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
+}
+
+/** @name FrameSystemEvent */
+export interface FrameSystemEvent extends Enum {
+ readonly isExtrinsicSuccess: boolean;
+ readonly asExtrinsicSuccess: {
+ readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
+ } & Struct;
+ readonly isExtrinsicFailed: boolean;
+ readonly asExtrinsicFailed: {
+ readonly dispatchError: SpRuntimeDispatchError;
+ readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
+ } & Struct;
+ readonly isCodeUpdated: boolean;
+ readonly isNewAccount: boolean;
+ readonly asNewAccount: {
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isKilledAccount: boolean;
+ readonly asKilledAccount: {
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isRemarked: boolean;
+ readonly asRemarked: {
+ readonly sender: AccountId32;
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked';
+}
+
+/** @name FrameSystemEventRecord */
+export interface FrameSystemEventRecord extends Struct {
+ readonly phase: FrameSystemPhase;
+ readonly event: Event;
+ readonly topics: Vec<H256>;
+}
+
+/** @name FrameSystemExtensionsCheckGenesis */
+export interface FrameSystemExtensionsCheckGenesis extends Null {}
+
+/** @name FrameSystemExtensionsCheckNonce */
+export interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
+
+/** @name FrameSystemExtensionsCheckSpecVersion */
+export interface FrameSystemExtensionsCheckSpecVersion extends Null {}
+
+/** @name FrameSystemExtensionsCheckTxVersion */
+export interface FrameSystemExtensionsCheckTxVersion extends Null {}
+
+/** @name FrameSystemExtensionsCheckWeight */
+export interface FrameSystemExtensionsCheckWeight extends Null {}
+
+/** @name FrameSystemLastRuntimeUpgradeInfo */
+export interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
+ readonly specVersion: Compact<u32>;
+ readonly specName: Text;
+}
+
+/** @name FrameSystemLimitsBlockLength */
+export interface FrameSystemLimitsBlockLength extends Struct {
+ readonly max: FrameSupportDispatchPerDispatchClassU32;
+}
+
+/** @name FrameSystemLimitsBlockWeights */
+export interface FrameSystemLimitsBlockWeights extends Struct {
+ readonly baseBlock: SpWeightsWeightV2Weight;
+ readonly maxBlock: SpWeightsWeightV2Weight;
+ readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
+}
+
+/** @name FrameSystemLimitsWeightsPerClass */
+export interface FrameSystemLimitsWeightsPerClass extends Struct {
+ readonly baseExtrinsic: SpWeightsWeightV2Weight;
+ readonly maxExtrinsic: Option<SpWeightsWeightV2Weight>;
+ readonly maxTotal: Option<SpWeightsWeightV2Weight>;
+ readonly reserved: Option<SpWeightsWeightV2Weight>;
+}
+
+/** @name FrameSystemPhase */
+export interface FrameSystemPhase extends Enum {
+ readonly isApplyExtrinsic: boolean;
+ readonly asApplyExtrinsic: u32;
+ readonly isFinalization: boolean;
+ readonly isInitialization: boolean;
+ readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
+}
+
+/** @name OpalRuntimeOriginCaller */
+export interface OpalRuntimeOriginCaller extends Enum {
+ readonly isSystem: boolean;
+ readonly asSystem: FrameSupportDispatchRawOrigin;
+ readonly isVoid: boolean;
+ readonly asVoid: SpCoreVoid;
+ readonly isCouncil: boolean;
+ readonly asCouncil: PalletCollectiveRawOrigin;
+ readonly isTechnicalCommittee: boolean;
+ readonly asTechnicalCommittee: PalletCollectiveRawOrigin;
+ readonly isPolkadotXcm: boolean;
+ readonly asPolkadotXcm: PalletXcmOrigin;
+ readonly isCumulusXcm: boolean;
+ readonly asCumulusXcm: CumulusPalletXcmOrigin;
+ readonly isOrigins: boolean;
+ readonly asOrigins: PalletGovOriginsOrigin;
+ readonly isEthereum: boolean;
+ readonly asEthereum: PalletEthereumRawOrigin;
+ readonly type: 'System' | 'Void' | 'Council' | 'TechnicalCommittee' | 'PolkadotXcm' | 'CumulusXcm' | 'Origins' | 'Ethereum';
+}
+
+/** @name OpalRuntimeRuntime */
+export interface OpalRuntimeRuntime extends Null {}
+
+/** @name OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls */
+export interface OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls extends Null {}
+
+/** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance */
+export interface OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance extends Null {}
+
+/** @name OpalRuntimeRuntimeCommonSessionKeys */
+export interface OpalRuntimeRuntimeCommonSessionKeys extends Struct {
+ readonly aura: SpConsensusAuraSr25519AppSr25519Public;
+}
+
+/** @name OpalRuntimeRuntimeHoldReason */
+export interface OpalRuntimeRuntimeHoldReason extends Enum {
+ readonly isCollatorSelection: boolean;
+ readonly asCollatorSelection: PalletCollatorSelectionHoldReason;
+ readonly type: 'CollatorSelection';
+}
+
+/** @name OrmlTokensAccountData */
+export interface OrmlTokensAccountData extends Struct {
+ readonly free: u128;
+ readonly reserved: u128;
+ readonly frozen: u128;
+}
+
+/** @name OrmlTokensBalanceLock */
+export interface OrmlTokensBalanceLock extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+}
+
+/** @name OrmlTokensModuleCall */
+export interface OrmlTokensModuleCall extends Enum {
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: Compact<u128>;
+ } & Struct;
+ readonly isTransferAll: boolean;
+ readonly asTransferAll: {
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly keepAlive: bool;
+ } & Struct;
+ readonly isTransferKeepAlive: boolean;
+ readonly asTransferKeepAlive: {
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: Compact<u128>;
+ } & Struct;
+ readonly isForceTransfer: boolean;
+ readonly asForceTransfer: {
+ readonly source: MultiAddress;
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: Compact<u128>;
+ } & Struct;
+ readonly isSetBalance: boolean;
+ readonly asSetBalance: {
+ readonly who: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly newFree: Compact<u128>;
+ readonly newReserved: Compact<u128>;
+ } & Struct;
+ readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance';
+}
+
+/** @name OrmlTokensModuleError */
+export interface OrmlTokensModuleError extends Enum {
+ readonly isBalanceTooLow: boolean;
+ readonly isAmountIntoBalanceFailed: boolean;
+ readonly isLiquidityRestrictions: boolean;
+ readonly isMaxLocksExceeded: boolean;
+ readonly isKeepAlive: boolean;
+ readonly isExistentialDeposit: boolean;
+ readonly isDeadAccount: boolean;
+ readonly isTooManyReserves: boolean;
+ readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves';
+}
+
+/** @name OrmlTokensModuleEvent */
+export interface OrmlTokensModuleEvent extends Enum {
+ readonly isEndowed: boolean;
+ readonly asEndowed: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDustLost: boolean;
+ readonly asDustLost: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isReserved: boolean;
+ readonly asReserved: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnreserved: boolean;
+ readonly asUnreserved: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isReserveRepatriated: boolean;
+ readonly asReserveRepatriated: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ readonly status: FrameSupportTokensMiscBalanceStatus;
+ } & Struct;
+ readonly isBalanceSet: boolean;
+ readonly asBalanceSet: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly free: u128;
+ readonly reserved: u128;
+ } & Struct;
+ readonly isTotalIssuanceSet: boolean;
+ readonly asTotalIssuanceSet: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ } & Struct;
+ readonly isWithdrawn: boolean;
+ readonly asWithdrawn: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSlashed: boolean;
+ readonly asSlashed: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly freeAmount: u128;
+ readonly reservedAmount: u128;
+ } & Struct;
+ readonly isDeposited: boolean;
+ readonly asDeposited: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isLockSet: boolean;
+ readonly asLockSet: {
+ readonly lockId: U8aFixed;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isLockRemoved: boolean;
+ readonly asLockRemoved: {
+ readonly lockId: U8aFixed;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isLocked: boolean;
+ readonly asLocked: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnlocked: boolean;
+ readonly asUnlocked: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isIssued: boolean;
+ readonly asIssued: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ } & Struct;
+ readonly isRescinded: boolean;
+ readonly asRescinded: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ } & Struct;
+ readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'BalanceSet' | 'TotalIssuanceSet' | 'Withdrawn' | 'Slashed' | 'Deposited' | 'LockSet' | 'LockRemoved' | 'Locked' | 'Unlocked' | 'Issued' | 'Rescinded';
+}
+
+/** @name OrmlTokensReserveData */
+export interface OrmlTokensReserveData extends Struct {
+ readonly id: Null;
+ readonly amount: u128;
+}
+
+/** @name OrmlVestingModuleCall */
+export interface OrmlVestingModuleCall extends Enum {
+ readonly isClaim: boolean;
+ readonly isVestedTransfer: boolean;
+ readonly asVestedTransfer: {
+ readonly dest: MultiAddress;
+ readonly schedule: OrmlVestingVestingSchedule;
+ } & Struct;
+ readonly isUpdateVestingSchedules: boolean;
+ readonly asUpdateVestingSchedules: {
+ readonly who: MultiAddress;
+ readonly vestingSchedules: Vec<OrmlVestingVestingSchedule>;
+ } & Struct;
+ readonly isClaimFor: boolean;
+ readonly asClaimFor: {
+ readonly dest: MultiAddress;
+ } & Struct;
+ readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
+}
+
+/** @name OrmlVestingModuleError */
+export interface OrmlVestingModuleError extends Enum {
+ readonly isZeroVestingPeriod: boolean;
+ readonly isZeroVestingPeriodCount: boolean;
+ readonly isInsufficientBalanceToLock: boolean;
+ readonly isTooManyVestingSchedules: boolean;
+ readonly isAmountLow: boolean;
+ readonly isMaxVestingSchedulesExceeded: boolean;
+ readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
+}
+
+/** @name OrmlVestingModuleEvent */
+export interface OrmlVestingModuleEvent extends Enum {
+ readonly isVestingScheduleAdded: boolean;
+ readonly asVestingScheduleAdded: {
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly vestingSchedule: OrmlVestingVestingSchedule;
+ } & Struct;
+ readonly isClaimed: boolean;
+ readonly asClaimed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isVestingSchedulesUpdated: boolean;
+ readonly asVestingSchedulesUpdated: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated';
+}
+
+/** @name OrmlVestingVestingSchedule */
+export interface OrmlVestingVestingSchedule extends Struct {
+ readonly start: u32;
+ readonly period: u32;
+ readonly periodCount: u32;
+ readonly perPeriod: Compact<u128>;
+}
+
+/** @name OrmlXtokensModuleCall */
+export interface OrmlXtokensModuleCall extends Enum {
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMultiasset: boolean;
+ readonly asTransferMultiasset: {
+ readonly asset: StagingXcmVersionedMultiAsset;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferWithFee: boolean;
+ readonly asTransferWithFee: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ readonly fee: u128;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMultiassetWithFee: boolean;
+ readonly asTransferMultiassetWithFee: {
+ readonly asset: StagingXcmVersionedMultiAsset;
+ readonly fee: StagingXcmVersionedMultiAsset;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMulticurrencies: boolean;
+ readonly asTransferMulticurrencies: {
+ readonly currencies: Vec<ITuple<[PalletForeignAssetsAssetId, u128]>>;
+ readonly feeItem: u32;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMultiassets: boolean;
+ readonly asTransferMultiassets: {
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeItem: u32;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets';
+}
+
+/** @name OrmlXtokensModuleError */
+export interface OrmlXtokensModuleError extends Enum {
+ readonly isAssetHasNoReserve: boolean;
+ readonly isNotCrossChainTransfer: boolean;
+ readonly isInvalidDest: boolean;
+ readonly isNotCrossChainTransferableCurrency: boolean;
+ readonly isUnweighableMessage: boolean;
+ readonly isXcmExecutionFailed: boolean;
+ readonly isCannotReanchor: boolean;
+ readonly isInvalidAncestry: boolean;
+ readonly isInvalidAsset: boolean;
+ readonly isDestinationNotInvertible: boolean;
+ readonly isBadVersion: boolean;
+ readonly isDistinctReserveForAssetAndFee: boolean;
+ readonly isZeroFee: boolean;
+ readonly isZeroAmount: boolean;
+ readonly isTooManyAssetsBeingSent: boolean;
+ readonly isAssetIndexNonExistent: boolean;
+ readonly isFeeNotEnough: boolean;
+ readonly isNotSupportedMultiLocation: boolean;
+ readonly isMinXcmFeeNotDefined: boolean;
+ readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined';
+}
+
+/** @name OrmlXtokensModuleEvent */
+export interface OrmlXtokensModuleEvent extends Enum {
+ readonly isTransferredMultiAssets: boolean;
+ readonly asTransferredMultiAssets: {
+ readonly sender: AccountId32;
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly fee: StagingXcmV3MultiAsset;
+ readonly dest: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly type: 'TransferredMultiAssets';
+}
+
+/** @name PalletAppPromotionCall */
+export interface PalletAppPromotionCall extends Enum {
+ readonly isSetAdminAddress: boolean;
+ readonly asSetAdminAddress: {
+ readonly admin: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isStake: boolean;
+ readonly asStake: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnstakeAll: boolean;
+ readonly isSponsorCollection: boolean;
+ readonly asSponsorCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isStopSponsoringCollection: boolean;
+ readonly asStopSponsoringCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isSponsorContract: boolean;
+ readonly asSponsorContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isStopSponsoringContract: boolean;
+ readonly asStopSponsoringContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isPayoutStakers: boolean;
+ readonly asPayoutStakers: {
+ readonly stakersNumber: Option<u8>;
+ } & Struct;
+ readonly isUnstakePartial: boolean;
+ readonly asUnstakePartial: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isForceUnstake: boolean;
+ readonly asForceUnstake: {
+ readonly pendingBlocks: Vec<u32>;
+ } & Struct;
+ readonly type: 'SetAdminAddress' | 'Stake' | 'UnstakeAll' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers' | 'UnstakePartial' | 'ForceUnstake';
+}
+
+/** @name PalletAppPromotionError */
+export interface PalletAppPromotionError extends Enum {
+ readonly isAdminNotSet: boolean;
+ readonly isNoPermission: boolean;
+ readonly isNotSufficientFunds: boolean;
+ readonly isPendingForBlockOverflow: boolean;
+ readonly isSponsorNotSet: boolean;
+ readonly isInsufficientStakedBalance: boolean;
+ readonly isInconsistencyState: boolean;
+ readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'InsufficientStakedBalance' | 'InconsistencyState';
+}
+
+/** @name PalletAppPromotionEvent */
+export interface PalletAppPromotionEvent extends Enum {
+ readonly isStakingRecalculation: boolean;
+ readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
+ readonly isStake: boolean;
+ readonly asStake: ITuple<[AccountId32, u128]>;
+ readonly isUnstake: boolean;
+ readonly asUnstake: ITuple<[AccountId32, u128]>;
+ readonly isSetAdmin: boolean;
+ readonly asSetAdmin: AccountId32;
+ readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
+}
+
+/** @name PalletBalancesAccountData */
+export interface PalletBalancesAccountData extends Struct {
+ readonly free: u128;
+ readonly reserved: u128;
+ readonly frozen: u128;
+ readonly flags: u128;
+}
+
+/** @name PalletBalancesBalanceLock */
+export interface PalletBalancesBalanceLock extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+ readonly reasons: PalletBalancesReasons;
+}
+
+/** @name PalletBalancesCall */
+export interface PalletBalancesCall extends Enum {
+ readonly isTransferAllowDeath: boolean;
+ readonly asTransferAllowDeath: {
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isSetBalanceDeprecated: boolean;
+ readonly asSetBalanceDeprecated: {
+ readonly who: MultiAddress;
+ readonly newFree: Compact<u128>;
+ readonly oldReserved: Compact<u128>;
+ } & Struct;
+ readonly isForceTransfer: boolean;
+ readonly asForceTransfer: {
+ readonly source: MultiAddress;
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isTransferKeepAlive: boolean;
+ readonly asTransferKeepAlive: {
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isTransferAll: boolean;
+ readonly asTransferAll: {
+ readonly dest: MultiAddress;
+ readonly keepAlive: bool;
+ } & Struct;
+ readonly isForceUnreserve: boolean;
+ readonly asForceUnreserve: {
+ readonly who: MultiAddress;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUpgradeAccounts: boolean;
+ readonly asUpgradeAccounts: {
+ readonly who: Vec<AccountId32>;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isForceSetBalance: boolean;
+ readonly asForceSetBalance: {
+ readonly who: MultiAddress;
+ readonly newFree: Compact<u128>;
+ } & Struct;
+ readonly type: 'TransferAllowDeath' | 'SetBalanceDeprecated' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve' | 'UpgradeAccounts' | 'Transfer' | 'ForceSetBalance';
+}
+
+/** @name PalletBalancesError */
+export interface PalletBalancesError extends Enum {
+ readonly isVestingBalance: boolean;
+ readonly isLiquidityRestrictions: boolean;
+ readonly isInsufficientBalance: boolean;
+ readonly isExistentialDeposit: boolean;
+ readonly isExpendability: boolean;
+ readonly isExistingVestingSchedule: boolean;
+ readonly isDeadAccount: boolean;
+ readonly isTooManyReserves: boolean;
+ readonly isTooManyHolds: boolean;
+ readonly isTooManyFreezes: boolean;
+ readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'Expendability' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves' | 'TooManyHolds' | 'TooManyFreezes';
+}
+
+/** @name PalletBalancesEvent */
+export interface PalletBalancesEvent extends Enum {
+ readonly isEndowed: boolean;
+ readonly asEndowed: {
+ readonly account: AccountId32;
+ readonly freeBalance: u128;
+ } & Struct;
+ readonly isDustLost: boolean;
+ readonly asDustLost: {
+ readonly account: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isBalanceSet: boolean;
+ readonly asBalanceSet: {
+ readonly who: AccountId32;
+ readonly free: u128;
+ } & Struct;
+ readonly isReserved: boolean;
+ readonly asReserved: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnreserved: boolean;
+ readonly asUnreserved: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isReserveRepatriated: boolean;
+ readonly asReserveRepatriated: {
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ readonly destinationStatus: FrameSupportTokensMiscBalanceStatus;
+ } & Struct;
+ readonly isDeposit: boolean;
+ readonly asDeposit: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isWithdraw: boolean;
+ readonly asWithdraw: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSlashed: boolean;
+ readonly asSlashed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isMinted: boolean;
+ readonly asMinted: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isBurned: boolean;
+ readonly asBurned: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSuspended: boolean;
+ readonly asSuspended: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isRestored: boolean;
+ readonly asRestored: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUpgraded: boolean;
+ readonly asUpgraded: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isIssued: boolean;
+ readonly asIssued: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isRescinded: boolean;
+ readonly asRescinded: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isLocked: boolean;
+ readonly asLocked: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnlocked: boolean;
+ readonly asUnlocked: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isFrozen: boolean;
+ readonly asFrozen: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isThawed: boolean;
+ readonly asThawed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'BalanceSet' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'Deposit' | 'Withdraw' | 'Slashed' | 'Minted' | 'Burned' | 'Suspended' | 'Restored' | 'Upgraded' | 'Issued' | 'Rescinded' | 'Locked' | 'Unlocked' | 'Frozen' | 'Thawed';
+}
+
+/** @name PalletBalancesIdAmount */
+export interface PalletBalancesIdAmount extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+}
+
+/** @name PalletBalancesReasons */
+export interface PalletBalancesReasons extends Enum {
+ readonly isFee: boolean;
+ readonly isMisc: boolean;
+ readonly isAll: boolean;
+ readonly type: 'Fee' | 'Misc' | 'All';
+}
+
+/** @name PalletBalancesReserveData */
+export interface PalletBalancesReserveData extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+}
+
+/** @name PalletCollatorSelectionCall */
+export interface PalletCollatorSelectionCall extends Enum {
+ readonly isAddInvulnerable: boolean;
+ readonly asAddInvulnerable: {
+ readonly new_: AccountId32;
+ } & Struct;
+ readonly isRemoveInvulnerable: boolean;
+ readonly asRemoveInvulnerable: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isGetLicense: boolean;
+ readonly isOnboard: boolean;
+ readonly isOffboard: boolean;
+ readonly isReleaseLicense: boolean;
+ readonly isForceReleaseLicense: boolean;
+ readonly asForceReleaseLicense: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceReleaseLicense';
+}
+
+/** @name PalletCollatorSelectionError */
+export interface PalletCollatorSelectionError extends Enum {
+ readonly isTooManyCandidates: boolean;
+ readonly isUnknown: boolean;
+ readonly isPermission: boolean;
+ readonly isAlreadyHoldingLicense: boolean;
+ readonly isNoLicense: boolean;
+ readonly isAlreadyCandidate: boolean;
+ readonly isNotCandidate: boolean;
+ readonly isTooManyInvulnerables: boolean;
+ readonly isTooFewInvulnerables: boolean;
+ readonly isAlreadyInvulnerable: boolean;
+ readonly isNotInvulnerable: boolean;
+ readonly isNoAssociatedValidatorId: boolean;
+ readonly isValidatorNotRegistered: boolean;
+ readonly type: 'TooManyCandidates' | 'Unknown' | 'Permission' | 'AlreadyHoldingLicense' | 'NoLicense' | 'AlreadyCandidate' | 'NotCandidate' | 'TooManyInvulnerables' | 'TooFewInvulnerables' | 'AlreadyInvulnerable' | 'NotInvulnerable' | 'NoAssociatedValidatorId' | 'ValidatorNotRegistered';
+}
+
+/** @name PalletCollatorSelectionEvent */
+export interface PalletCollatorSelectionEvent extends Enum {
+ readonly isInvulnerableAdded: boolean;
+ readonly asInvulnerableAdded: {
+ readonly invulnerable: AccountId32;
+ } & Struct;
+ readonly isInvulnerableRemoved: boolean;
+ readonly asInvulnerableRemoved: {
+ readonly invulnerable: AccountId32;
+ } & Struct;
+ readonly isLicenseObtained: boolean;
+ readonly asLicenseObtained: {
+ readonly accountId: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isLicenseReleased: boolean;
+ readonly asLicenseReleased: {
+ readonly accountId: AccountId32;
+ readonly depositReturned: u128;
+ } & Struct;
+ readonly isCandidateAdded: boolean;
+ readonly asCandidateAdded: {
+ readonly accountId: AccountId32;
+ } & Struct;
+ readonly isCandidateRemoved: boolean;
+ readonly asCandidateRemoved: {
+ readonly accountId: AccountId32;
+ } & Struct;
+ readonly type: 'InvulnerableAdded' | 'InvulnerableRemoved' | 'LicenseObtained' | 'LicenseReleased' | 'CandidateAdded' | 'CandidateRemoved';
+}
+
+/** @name PalletCollatorSelectionHoldReason */
+export interface PalletCollatorSelectionHoldReason extends Enum {
+ readonly isLicenseBond: boolean;
+ readonly type: 'LicenseBond';
+}
+
+/** @name PalletCollectiveCall */
+export interface PalletCollectiveCall extends Enum {
+ readonly isSetMembers: boolean;
+ readonly asSetMembers: {
+ readonly newMembers: Vec<AccountId32>;
+ readonly prime: Option<AccountId32>;
+ readonly oldCount: u32;
+ } & Struct;
+ readonly isExecute: boolean;
+ readonly asExecute: {
+ readonly proposal: Call;
+ readonly lengthBound: Compact<u32>;
+ } & Struct;
+ readonly isPropose: boolean;
+ readonly asPropose: {
+ readonly threshold: Compact<u32>;
+ readonly proposal: Call;
+ readonly lengthBound: Compact<u32>;
+ } & Struct;
+ readonly isVote: boolean;
+ readonly asVote: {
+ readonly proposal: H256;
+ readonly index: Compact<u32>;
+ readonly approve: bool;
+ } & Struct;
+ readonly isDisapproveProposal: boolean;
+ readonly asDisapproveProposal: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isClose: boolean;
+ readonly asClose: {
+ readonly proposalHash: H256;
+ readonly index: Compact<u32>;
+ readonly proposalWeightBound: SpWeightsWeightV2Weight;
+ readonly lengthBound: Compact<u32>;
+ } & Struct;
+ readonly type: 'SetMembers' | 'Execute' | 'Propose' | 'Vote' | 'DisapproveProposal' | 'Close';
+}
+
+/** @name PalletCollectiveError */
+export interface PalletCollectiveError extends Enum {
+ readonly isNotMember: boolean;
+ readonly isDuplicateProposal: boolean;
+ readonly isProposalMissing: boolean;
+ readonly isWrongIndex: boolean;
+ readonly isDuplicateVote: boolean;
+ readonly isAlreadyInitialized: boolean;
+ readonly isTooEarly: boolean;
+ readonly isTooManyProposals: boolean;
+ readonly isWrongProposalWeight: boolean;
+ readonly isWrongProposalLength: boolean;
+ readonly isPrimeAccountNotMember: boolean;
+ readonly type: 'NotMember' | 'DuplicateProposal' | 'ProposalMissing' | 'WrongIndex' | 'DuplicateVote' | 'AlreadyInitialized' | 'TooEarly' | 'TooManyProposals' | 'WrongProposalWeight' | 'WrongProposalLength' | 'PrimeAccountNotMember';
+}
+
+/** @name PalletCollectiveEvent */
+export interface PalletCollectiveEvent extends Enum {
+ readonly isProposed: boolean;
+ readonly asProposed: {
+ readonly account: AccountId32;
+ readonly proposalIndex: u32;
+ readonly proposalHash: H256;
+ readonly threshold: u32;
+ } & Struct;
+ readonly isVoted: boolean;
+ readonly asVoted: {
+ readonly account: AccountId32;
+ readonly proposalHash: H256;
+ readonly voted: bool;
+ readonly yes: u32;
+ readonly no: u32;
+ } & Struct;
+ readonly isApproved: boolean;
+ readonly asApproved: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isDisapproved: boolean;
+ readonly asDisapproved: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isExecuted: boolean;
+ readonly asExecuted: {
+ readonly proposalHash: H256;
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isMemberExecuted: boolean;
+ readonly asMemberExecuted: {
+ readonly proposalHash: H256;
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isClosed: boolean;
+ readonly asClosed: {
+ readonly proposalHash: H256;
+ readonly yes: u32;
+ readonly no: u32;
+ } & Struct;
+ readonly type: 'Proposed' | 'Voted' | 'Approved' | 'Disapproved' | 'Executed' | 'MemberExecuted' | 'Closed';
+}
+
+/** @name PalletCollectiveRawOrigin */
+export interface PalletCollectiveRawOrigin extends Enum {
+ readonly isMembers: boolean;
+ readonly asMembers: ITuple<[u32, u32]>;
+ readonly isMember: boolean;
+ readonly asMember: AccountId32;
+ readonly isPhantom: boolean;
+ readonly type: 'Members' | 'Member' | 'Phantom';
+}
+
+/** @name PalletCollectiveVotes */
+export interface PalletCollectiveVotes extends Struct {
+ readonly index: u32;
+ readonly threshold: u32;
+ readonly ayes: Vec<AccountId32>;
+ readonly nays: Vec<AccountId32>;
+ readonly end: u32;
+}
+
+/** @name PalletCommonError */
+export interface PalletCommonError extends Enum {
+ readonly isCollectionNotFound: boolean;
+ readonly isMustBeTokenOwner: boolean;
+ readonly isNoPermission: boolean;
+ readonly isCantDestroyNotEmptyCollection: boolean;
+ readonly isPublicMintingNotAllowed: boolean;
+ readonly isAddressNotInAllowlist: boolean;
+ readonly isCollectionNameLimitExceeded: boolean;
+ readonly isCollectionDescriptionLimitExceeded: boolean;
+ readonly isCollectionTokenPrefixLimitExceeded: boolean;
+ readonly isTotalCollectionsLimitExceeded: boolean;
+ readonly isCollectionAdminCountExceeded: boolean;
+ readonly isCollectionLimitBoundsExceeded: boolean;
+ readonly isOwnerPermissionsCantBeReverted: boolean;
+ readonly isTransferNotAllowed: boolean;
+ readonly isAccountTokenLimitExceeded: boolean;
+ readonly isCollectionTokenLimitExceeded: boolean;
+ readonly isMetadataFlagFrozen: boolean;
+ readonly isTokenNotFound: boolean;
+ readonly isTokenValueTooLow: boolean;
+ readonly isApprovedValueTooLow: boolean;
+ readonly isCantApproveMoreThanOwned: boolean;
+ readonly isAddressIsNotEthMirror: boolean;
+ readonly isAddressIsZero: boolean;
+ readonly isUnsupportedOperation: boolean;
+ readonly isNotSufficientFounds: boolean;
+ readonly isUserIsNotAllowedToNest: boolean;
+ readonly isSourceCollectionIsNotAllowedToNest: boolean;
+ readonly isCollectionFieldSizeExceeded: boolean;
+ readonly isNoSpaceForProperty: boolean;
+ readonly isPropertyLimitReached: boolean;
+ readonly isPropertyKeyIsTooLong: boolean;
+ readonly isInvalidCharacterInPropertyKey: boolean;
+ readonly isEmptyPropertyKey: boolean;
+ readonly isCollectionIsExternal: boolean;
+ readonly isCollectionIsInternal: boolean;
+ readonly isConfirmSponsorshipFail: boolean;
+ readonly isUserIsNotCollectionAdmin: boolean;
+ readonly isFungibleItemsHaveNoId: boolean;
+ readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsNotEthMirror' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin' | 'FungibleItemsHaveNoId';
+}
+
+/** @name PalletCommonEvent */
+export interface PalletCommonEvent extends Enum {
+ readonly isCollectionCreated: boolean;
+ readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
+ readonly isCollectionDestroyed: boolean;
+ readonly asCollectionDestroyed: u32;
+ readonly isItemCreated: boolean;
+ readonly asItemCreated: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isItemDestroyed: boolean;
+ readonly asItemDestroyed: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isTransfer: boolean;
+ readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isApproved: boolean;
+ readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isApprovedForAll: boolean;
+ readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
+ readonly isCollectionPropertySet: boolean;
+ readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
+ readonly isCollectionPropertyDeleted: boolean;
+ readonly asCollectionPropertyDeleted: ITuple<[u32, Bytes]>;
+ readonly isTokenPropertySet: boolean;
+ readonly asTokenPropertySet: ITuple<[u32, u32, Bytes]>;
+ readonly isTokenPropertyDeleted: boolean;
+ readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
+ readonly isPropertyPermissionSet: boolean;
+ readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
+ readonly isAllowListAddressAdded: boolean;
+ readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isAllowListAddressRemoved: boolean;
+ readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isCollectionAdminAdded: boolean;
+ readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isCollectionAdminRemoved: boolean;
+ readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isCollectionLimitSet: boolean;
+ readonly asCollectionLimitSet: u32;
+ readonly isCollectionOwnerChanged: boolean;
+ readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>;
+ readonly isCollectionPermissionSet: boolean;
+ readonly asCollectionPermissionSet: u32;
+ readonly isCollectionSponsorSet: boolean;
+ readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
+ readonly isSponsorshipConfirmed: boolean;
+ readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
+ readonly isCollectionSponsorRemoved: boolean;
+ readonly asCollectionSponsorRemoved: u32;
+ readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved';
+}
+
+/** @name PalletConfigurationAppPromotionConfiguration */
+export interface PalletConfigurationAppPromotionConfiguration extends Struct {
+ readonly recalculationInterval: Option<u32>;
+ readonly pendingInterval: Option<u32>;
+ readonly intervalIncome: Option<Perbill>;
+ readonly maxStakersPerCalculation: Option<u8>;
+}
+
+/** @name PalletConfigurationCall */
+export interface PalletConfigurationCall extends Enum {
+ readonly isSetWeightToFeeCoefficientOverride: boolean;
+ readonly asSetWeightToFeeCoefficientOverride: {
+ readonly coeff: Option<u64>;
+ } & Struct;
+ readonly isSetMinGasPriceOverride: boolean;
+ readonly asSetMinGasPriceOverride: {
+ readonly coeff: Option<u64>;
+ } & Struct;
+ readonly isSetAppPromotionConfigurationOverride: boolean;
+ readonly asSetAppPromotionConfigurationOverride: {
+ readonly configuration: PalletConfigurationAppPromotionConfiguration;
+ } & Struct;
+ readonly isSetCollatorSelectionDesiredCollators: boolean;
+ readonly asSetCollatorSelectionDesiredCollators: {
+ readonly max: Option<u32>;
+ } & Struct;
+ readonly isSetCollatorSelectionLicenseBond: boolean;
+ readonly asSetCollatorSelectionLicenseBond: {
+ readonly amount: Option<u128>;
+ } & Struct;
+ readonly isSetCollatorSelectionKickThreshold: boolean;
+ readonly asSetCollatorSelectionKickThreshold: {
+ readonly threshold: Option<u32>;
+ } & Struct;
+ readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride' | 'SetAppPromotionConfigurationOverride' | 'SetCollatorSelectionDesiredCollators' | 'SetCollatorSelectionLicenseBond' | 'SetCollatorSelectionKickThreshold';
+}
+
+/** @name PalletConfigurationError */
+export interface PalletConfigurationError extends Enum {
+ readonly isInconsistentConfiguration: boolean;
+ readonly type: 'InconsistentConfiguration';
+}
+
+/** @name PalletConfigurationEvent */
+export interface PalletConfigurationEvent extends Enum {
+ readonly isNewDesiredCollators: boolean;
+ readonly asNewDesiredCollators: {
+ readonly desiredCollators: Option<u32>;
+ } & Struct;
+ readonly isNewCollatorLicenseBond: boolean;
+ readonly asNewCollatorLicenseBond: {
+ readonly bondCost: Option<u128>;
+ } & Struct;
+ readonly isNewCollatorKickThreshold: boolean;
+ readonly asNewCollatorKickThreshold: {
+ readonly lengthInBlocks: Option<u32>;
+ } & Struct;
+ readonly type: 'NewDesiredCollators' | 'NewCollatorLicenseBond' | 'NewCollatorKickThreshold';
+}
+
+/** @name PalletDemocracyCall */
+export interface PalletDemocracyCall extends Enum {
+ readonly isPropose: boolean;
+ readonly asPropose: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isSecond: boolean;
+ readonly asSecond: {
+ readonly proposal: Compact<u32>;
+ } & Struct;
+ readonly isVote: boolean;
+ readonly asVote: {
+ readonly refIndex: Compact<u32>;
+ readonly vote: PalletDemocracyVoteAccountVote;
+ } & Struct;
+ readonly isEmergencyCancel: boolean;
+ readonly asEmergencyCancel: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isExternalPropose: boolean;
+ readonly asExternalPropose: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isExternalProposeMajority: boolean;
+ readonly asExternalProposeMajority: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isExternalProposeDefault: boolean;
+ readonly asExternalProposeDefault: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isFastTrack: boolean;
+ readonly asFastTrack: {
+ readonly proposalHash: H256;
+ readonly votingPeriod: u32;
+ readonly delay: u32;
+ } & Struct;
+ readonly isVetoExternal: boolean;
+ readonly asVetoExternal: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isCancelReferendum: boolean;
+ readonly asCancelReferendum: {
+ readonly refIndex: Compact<u32>;
+ } & Struct;
+ readonly isDelegate: boolean;
+ readonly asDelegate: {
+ readonly to: MultiAddress;
+ readonly conviction: PalletDemocracyConviction;
+ readonly balance: u128;
+ } & Struct;
+ readonly isUndelegate: boolean;
+ readonly isClearPublicProposals: boolean;
+ readonly isUnlock: boolean;
+ readonly asUnlock: {
+ readonly target: MultiAddress;
+ } & Struct;
+ readonly isRemoveVote: boolean;
+ readonly asRemoveVote: {
+ readonly index: u32;
+ } & Struct;
+ readonly isRemoveOtherVote: boolean;
+ readonly asRemoveOtherVote: {
+ readonly target: MultiAddress;
+ readonly index: u32;
+ } & Struct;
+ readonly isBlacklist: boolean;
+ readonly asBlacklist: {
+ readonly proposalHash: H256;
+ readonly maybeRefIndex: Option<u32>;
+ } & Struct;
+ readonly isCancelProposal: boolean;
+ readonly asCancelProposal: {
+ readonly propIndex: Compact<u32>;
+ } & Struct;
+ readonly isSetMetadata: boolean;
+ readonly asSetMetadata: {
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly maybeHash: Option<H256>;
+ } & Struct;
+ readonly type: 'Propose' | 'Second' | 'Vote' | 'EmergencyCancel' | 'ExternalPropose' | 'ExternalProposeMajority' | 'ExternalProposeDefault' | 'FastTrack' | 'VetoExternal' | 'CancelReferendum' | 'Delegate' | 'Undelegate' | 'ClearPublicProposals' | 'Unlock' | 'RemoveVote' | 'RemoveOtherVote' | 'Blacklist' | 'CancelProposal' | 'SetMetadata';
+}
+
+/** @name PalletDemocracyConviction */
+export interface PalletDemocracyConviction extends Enum {
+ readonly isNone: boolean;
+ readonly isLocked1x: boolean;
+ readonly isLocked2x: boolean;
+ readonly isLocked3x: boolean;
+ readonly isLocked4x: boolean;
+ readonly isLocked5x: boolean;
+ readonly isLocked6x: boolean;
+ readonly type: 'None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x' | 'Locked6x';
+}
+
+/** @name PalletDemocracyDelegations */
+export interface PalletDemocracyDelegations extends Struct {
+ readonly votes: u128;
+ readonly capital: u128;
+}
+
+/** @name PalletDemocracyError */
+export interface PalletDemocracyError extends Enum {
+ readonly isValueLow: boolean;
+ readonly isProposalMissing: boolean;
+ readonly isAlreadyCanceled: boolean;
+ readonly isDuplicateProposal: boolean;
+ readonly isProposalBlacklisted: boolean;
+ readonly isNotSimpleMajority: boolean;
+ readonly isInvalidHash: boolean;
+ readonly isNoProposal: boolean;
+ readonly isAlreadyVetoed: boolean;
+ readonly isReferendumInvalid: boolean;
+ readonly isNoneWaiting: boolean;
+ readonly isNotVoter: boolean;
+ readonly isNoPermission: boolean;
+ readonly isAlreadyDelegating: boolean;
+ readonly isInsufficientFunds: boolean;
+ readonly isNotDelegating: boolean;
+ readonly isVotesExist: boolean;
+ readonly isInstantNotAllowed: boolean;
+ readonly isNonsense: boolean;
+ readonly isWrongUpperBound: boolean;
+ readonly isMaxVotesReached: boolean;
+ readonly isTooMany: boolean;
+ readonly isVotingPeriodLow: boolean;
+ readonly isPreimageNotExist: boolean;
+ readonly type: 'ValueLow' | 'ProposalMissing' | 'AlreadyCanceled' | 'DuplicateProposal' | 'ProposalBlacklisted' | 'NotSimpleMajority' | 'InvalidHash' | 'NoProposal' | 'AlreadyVetoed' | 'ReferendumInvalid' | 'NoneWaiting' | 'NotVoter' | 'NoPermission' | 'AlreadyDelegating' | 'InsufficientFunds' | 'NotDelegating' | 'VotesExist' | 'InstantNotAllowed' | 'Nonsense' | 'WrongUpperBound' | 'MaxVotesReached' | 'TooMany' | 'VotingPeriodLow' | 'PreimageNotExist';
+}
+
+/** @name PalletDemocracyEvent */
+export interface PalletDemocracyEvent extends Enum {
+ readonly isProposed: boolean;
+ readonly asProposed: {
+ readonly proposalIndex: u32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isTabled: boolean;
+ readonly asTabled: {
+ readonly proposalIndex: u32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isExternalTabled: boolean;
+ readonly isStarted: boolean;
+ readonly asStarted: {
+ readonly refIndex: u32;
+ readonly threshold: PalletDemocracyVoteThreshold;
+ } & Struct;
+ readonly isPassed: boolean;
+ readonly asPassed: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isNotPassed: boolean;
+ readonly asNotPassed: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isCancelled: boolean;
+ readonly asCancelled: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isDelegated: boolean;
+ readonly asDelegated: {
+ readonly who: AccountId32;
+ readonly target: AccountId32;
+ } & Struct;
+ readonly isUndelegated: boolean;
+ readonly asUndelegated: {
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isVetoed: boolean;
+ readonly asVetoed: {
+ readonly who: AccountId32;
+ readonly proposalHash: H256;
+ readonly until: u32;
+ } & Struct;
+ readonly isBlacklisted: boolean;
+ readonly asBlacklisted: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isVoted: boolean;
+ readonly asVoted: {
+ readonly voter: AccountId32;
+ readonly refIndex: u32;
+ readonly vote: PalletDemocracyVoteAccountVote;
+ } & Struct;
+ readonly isSeconded: boolean;
+ readonly asSeconded: {
+ readonly seconder: AccountId32;
+ readonly propIndex: u32;
+ } & Struct;
+ readonly isProposalCanceled: boolean;
+ readonly asProposalCanceled: {
+ readonly propIndex: u32;
+ } & Struct;
+ readonly isMetadataSet: boolean;
+ readonly asMetadataSet: {
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly hash_: H256;
+ } & Struct;
+ readonly isMetadataCleared: boolean;
+ readonly asMetadataCleared: {
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly hash_: H256;
+ } & Struct;
+ readonly isMetadataTransferred: boolean;
+ readonly asMetadataTransferred: {
+ readonly prevOwner: PalletDemocracyMetadataOwner;
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'Proposed' | 'Tabled' | 'ExternalTabled' | 'Started' | 'Passed' | 'NotPassed' | 'Cancelled' | 'Delegated' | 'Undelegated' | 'Vetoed' | 'Blacklisted' | 'Voted' | 'Seconded' | 'ProposalCanceled' | 'MetadataSet' | 'MetadataCleared' | 'MetadataTransferred';
+}
+
+/** @name PalletDemocracyMetadataOwner */
+export interface PalletDemocracyMetadataOwner extends Enum {
+ readonly isExternal: boolean;
+ readonly isProposal: boolean;
+ readonly asProposal: u32;
+ readonly isReferendum: boolean;
+ readonly asReferendum: u32;
+ readonly type: 'External' | 'Proposal' | 'Referendum';
+}
+
+/** @name PalletDemocracyReferendumInfo */
+export interface PalletDemocracyReferendumInfo extends Enum {
+ readonly isOngoing: boolean;
+ readonly asOngoing: PalletDemocracyReferendumStatus;
+ readonly isFinished: boolean;
+ readonly asFinished: {
+ readonly approved: bool;
+ readonly end: u32;
+ } & Struct;
+ readonly type: 'Ongoing' | 'Finished';
+}
+
+/** @name PalletDemocracyReferendumStatus */
+export interface PalletDemocracyReferendumStatus extends Struct {
+ readonly end: u32;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly threshold: PalletDemocracyVoteThreshold;
+ readonly delay: u32;
+ readonly tally: PalletDemocracyTally;
+}
+
+/** @name PalletDemocracyTally */
+export interface PalletDemocracyTally extends Struct {
+ readonly ayes: u128;
+ readonly nays: u128;
+ readonly turnout: u128;
+}
+
+/** @name PalletDemocracyVoteAccountVote */
+export interface PalletDemocracyVoteAccountVote extends Enum {
+ readonly isStandard: boolean;
+ readonly asStandard: {
+ readonly vote: Vote;
+ readonly balance: u128;
+ } & Struct;
+ readonly isSplit: boolean;
+ readonly asSplit: {
+ readonly aye: u128;
+ readonly nay: u128;
+ } & Struct;
+ readonly type: 'Standard' | 'Split';
+}
+
+/** @name PalletDemocracyVotePriorLock */
+export interface PalletDemocracyVotePriorLock extends ITuple<[u32, u128]> {}
+
+/** @name PalletDemocracyVoteThreshold */
+export interface PalletDemocracyVoteThreshold extends Enum {
+ readonly isSuperMajorityApprove: boolean;
+ readonly isSuperMajorityAgainst: boolean;
+ readonly isSimpleMajority: boolean;
+ readonly type: 'SuperMajorityApprove' | 'SuperMajorityAgainst' | 'SimpleMajority';
+}
+
+/** @name PalletDemocracyVoteVoting */
+export interface PalletDemocracyVoteVoting extends Enum {
+ readonly isDirect: boolean;
+ readonly asDirect: {
+ readonly votes: Vec<ITuple<[u32, PalletDemocracyVoteAccountVote]>>;
+ readonly delegations: PalletDemocracyDelegations;
+ readonly prior: PalletDemocracyVotePriorLock;
+ } & Struct;
+ readonly isDelegating: boolean;
+ readonly asDelegating: {
+ readonly balance: u128;
+ readonly target: AccountId32;
+ readonly conviction: PalletDemocracyConviction;
+ readonly delegations: PalletDemocracyDelegations;
+ readonly prior: PalletDemocracyVotePriorLock;
+ } & Struct;
+ readonly type: 'Direct' | 'Delegating';
+}
+
+/** @name PalletEthereumCall */
+export interface PalletEthereumCall extends Enum {
+ readonly isTransact: boolean;
+ readonly asTransact: {
+ readonly transaction: EthereumTransactionTransactionV2;
+ } & Struct;
+ readonly type: 'Transact';
+}
+
+/** @name PalletEthereumError */
+export interface PalletEthereumError extends Enum {
+ readonly isInvalidSignature: boolean;
+ readonly isPreLogExists: boolean;
+ readonly type: 'InvalidSignature' | 'PreLogExists';
+}
+
+/** @name PalletEthereumEvent */
+export interface PalletEthereumEvent extends Enum {
+ readonly isExecuted: boolean;
+ readonly asExecuted: {
+ readonly from: H160;
+ readonly to: H160;
+ readonly transactionHash: H256;
+ readonly exitReason: EvmCoreErrorExitReason;
+ readonly extraData: Bytes;
+ } & Struct;
+ readonly type: 'Executed';
+}
+
+/** @name PalletEthereumFakeTransactionFinalizer */
+export interface PalletEthereumFakeTransactionFinalizer extends Null {}
+
+/** @name PalletEthereumRawOrigin */
+export interface PalletEthereumRawOrigin extends Enum {
+ readonly isEthereumTransaction: boolean;
+ readonly asEthereumTransaction: H160;
+ readonly type: 'EthereumTransaction';
+}
+
+/** @name PalletEvmAccountBasicCrossAccountIdRepr */
+export interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
+ readonly isSubstrate: boolean;
+ readonly asSubstrate: AccountId32;
+ readonly isEthereum: boolean;
+ readonly asEthereum: H160;
+ readonly type: 'Substrate' | 'Ethereum';
+}
+
+/** @name PalletEvmCall */
+export interface PalletEvmCall extends Enum {
+ readonly isWithdraw: boolean;
+ readonly asWithdraw: {
+ readonly address: H160;
+ readonly value: u128;
+ } & Struct;
+ readonly isCall: boolean;
+ readonly asCall: {
+ readonly source: H160;
+ readonly target: H160;
+ readonly input: Bytes;
+ readonly value: U256;
+ readonly gasLimit: u64;
+ readonly maxFeePerGas: U256;
+ readonly maxPriorityFeePerGas: Option<U256>;
+ readonly nonce: Option<U256>;
+ readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
+ } & Struct;
+ readonly isCreate: boolean;
+ readonly asCreate: {
+ readonly source: H160;
+ readonly init: Bytes;
+ readonly value: U256;
+ readonly gasLimit: u64;
+ readonly maxFeePerGas: U256;
+ readonly maxPriorityFeePerGas: Option<U256>;
+ readonly nonce: Option<U256>;
+ readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
+ } & Struct;
+ readonly isCreate2: boolean;
+ readonly asCreate2: {
+ readonly source: H160;
+ readonly init: Bytes;
+ readonly salt: H256;
+ readonly value: U256;
+ readonly gasLimit: u64;
+ readonly maxFeePerGas: U256;
+ readonly maxPriorityFeePerGas: Option<U256>;
+ readonly nonce: Option<U256>;
+ readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
+ } & Struct;
+ readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
+}
+
+/** @name PalletEvmCodeMetadata */
+export interface PalletEvmCodeMetadata extends Struct {
+ readonly size_: u64;
+ readonly hash_: H256;
+}
+
+/** @name PalletEvmCoderSubstrateError */
+export interface PalletEvmCoderSubstrateError extends Enum {
+ readonly isOutOfGas: boolean;
+ readonly isOutOfFund: boolean;
+ readonly type: 'OutOfGas' | 'OutOfFund';
+}
+
+/** @name PalletEvmContractHelpersCall */
+export interface PalletEvmContractHelpersCall extends Enum {
+ readonly isMigrateFromSelfSponsoring: boolean;
+ readonly asMigrateFromSelfSponsoring: {
+ readonly addresses: Vec<H160>;
+ } & Struct;
+ readonly type: 'MigrateFromSelfSponsoring';
+}
+
+/** @name PalletEvmContractHelpersError */
+export interface PalletEvmContractHelpersError extends Enum {
+ readonly isNoPermission: boolean;
+ readonly isNoPendingSponsor: boolean;
+ readonly isTooManyMethodsHaveSponsoredLimit: boolean;
+ readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
+}
+
+/** @name PalletEvmContractHelpersEvent */
+export interface PalletEvmContractHelpersEvent extends Enum {
+ readonly isContractSponsorSet: boolean;
+ readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorshipConfirmed: boolean;
+ readonly asContractSponsorshipConfirmed: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorRemoved: boolean;
+ readonly asContractSponsorRemoved: H160;
+ readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
+}
+
+/** @name PalletEvmContractHelpersSponsoringModeT */
+export interface PalletEvmContractHelpersSponsoringModeT extends Enum {
+ readonly isDisabled: boolean;
+ readonly isAllowlisted: boolean;
+ readonly isGenerous: boolean;
+ readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
+}
+
+/** @name PalletEvmError */
+export interface PalletEvmError extends Enum {
+ readonly isBalanceLow: boolean;
+ readonly isFeeOverflow: boolean;
+ readonly isPaymentOverflow: boolean;
+ readonly isWithdrawFailed: boolean;
+ readonly isGasPriceTooLow: boolean;
+ readonly isInvalidNonce: boolean;
+ readonly isGasLimitTooLow: boolean;
+ readonly isGasLimitTooHigh: boolean;
+ readonly isUndefined: boolean;
+ readonly isReentrancy: boolean;
+ readonly isTransactionMustComeFromEOA: boolean;
+ readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA';
+}
+
+/** @name PalletEvmEvent */
+export interface PalletEvmEvent extends Enum {
+ readonly isLog: boolean;
+ readonly asLog: {
+ readonly log: EthereumLog;
+ } & Struct;
+ readonly isCreated: boolean;
+ readonly asCreated: {
+ readonly address: H160;
+ } & Struct;
+ readonly isCreatedFailed: boolean;
+ readonly asCreatedFailed: {
+ readonly address: H160;
+ } & Struct;
+ readonly isExecuted: boolean;
+ readonly asExecuted: {
+ readonly address: H160;
+ } & Struct;
+ readonly isExecutedFailed: boolean;
+ readonly asExecutedFailed: {
+ readonly address: H160;
+ } & Struct;
+ readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
+}
+
+/** @name PalletEvmMigrationCall */
+export interface PalletEvmMigrationCall extends Enum {
+ readonly isBegin: boolean;
+ readonly asBegin: {
+ readonly address: H160;
+ } & Struct;
+ readonly isSetData: boolean;
+ readonly asSetData: {
+ readonly address: H160;
+ readonly data: Vec<ITuple<[H256, H256]>>;
+ } & Struct;
+ readonly isFinish: boolean;
+ readonly asFinish: {
+ readonly address: H160;
+ readonly code: Bytes;
+ } & Struct;
+ readonly isInsertEthLogs: boolean;
+ readonly asInsertEthLogs: {
+ readonly logs: Vec<EthereumLog>;
+ } & Struct;
+ readonly isInsertEvents: boolean;
+ readonly asInsertEvents: {
+ readonly events: Vec<Bytes>;
+ } & Struct;
+ readonly isRemoveRmrkData: boolean;
+ readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents' | 'RemoveRmrkData';
+}
+
+/** @name PalletEvmMigrationError */
+export interface PalletEvmMigrationError extends Enum {
+ readonly isAccountNotEmpty: boolean;
+ readonly isAccountIsNotMigrating: boolean;
+ readonly isBadEvent: boolean;
+ readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
+}
+
+/** @name PalletEvmMigrationEvent */
+export interface PalletEvmMigrationEvent extends Enum {
+ readonly isTestEvent: boolean;
+ readonly type: 'TestEvent';
+}
+
+/** @name PalletForeignAssetsAssetId */
+export interface PalletForeignAssetsAssetId extends Enum {
+ readonly isForeignAssetId: boolean;
+ readonly asForeignAssetId: u32;
+ readonly isNativeAssetId: boolean;
+ readonly asNativeAssetId: PalletForeignAssetsNativeCurrency;
+ readonly type: 'ForeignAssetId' | 'NativeAssetId';
+}
+
+/** @name PalletForeignAssetsModuleAssetMetadata */
+export interface PalletForeignAssetsModuleAssetMetadata extends Struct {
+ readonly name: Bytes;
+ readonly symbol: Bytes;
+ readonly decimals: u8;
+ readonly minimalBalance: u128;
+}
+
+/** @name PalletForeignAssetsModuleCall */
+export interface PalletForeignAssetsModuleCall extends Enum {
+ readonly isRegisterForeignAsset: boolean;
+ readonly asRegisterForeignAsset: {
+ readonly owner: AccountId32;
+ readonly location: StagingXcmVersionedMultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isUpdateForeignAsset: boolean;
+ readonly asUpdateForeignAsset: {
+ readonly foreignAssetId: u32;
+ readonly location: StagingXcmVersionedMultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset';
+}
+
+/** @name PalletForeignAssetsModuleError */
+export interface PalletForeignAssetsModuleError extends Enum {
+ readonly isBadLocation: boolean;
+ readonly isMultiLocationExisted: boolean;
+ readonly isAssetIdNotExists: boolean;
+ readonly isAssetIdExisted: boolean;
+ readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
+}
+
+/** @name PalletForeignAssetsModuleEvent */
+export interface PalletForeignAssetsModuleEvent extends Enum {
+ readonly isForeignAssetRegistered: boolean;
+ readonly asForeignAssetRegistered: {
+ readonly assetId: u32;
+ readonly assetAddress: StagingXcmV3MultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isForeignAssetUpdated: boolean;
+ readonly asForeignAssetUpdated: {
+ readonly assetId: u32;
+ readonly assetAddress: StagingXcmV3MultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isAssetRegistered: boolean;
+ readonly asAssetRegistered: {
+ readonly assetId: PalletForeignAssetsAssetId;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isAssetUpdated: boolean;
+ readonly asAssetUpdated: {
+ readonly assetId: PalletForeignAssetsAssetId;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated';
+}
+
+/** @name PalletForeignAssetsNativeCurrency */
+export interface PalletForeignAssetsNativeCurrency extends Enum {
+ readonly isHere: boolean;
+ readonly isParent: boolean;
+ readonly type: 'Here' | 'Parent';
+}
+
+/** @name PalletFungibleError */
+export interface PalletFungibleError extends Enum {
+ readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
+ readonly isFungibleItemsDontHaveData: boolean;
+ readonly isFungibleDisallowsNesting: boolean;
+ readonly isSettingPropertiesNotAllowed: boolean;
+ readonly isSettingAllowanceForAllNotAllowed: boolean;
+ readonly isFungibleTokensAreAlwaysValid: boolean;
+ readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid';
+}
+
+/** @name PalletGovOriginsOrigin */
+export interface PalletGovOriginsOrigin extends Enum {
+ readonly isFellowshipProposition: boolean;
+ readonly type: 'FellowshipProposition';
+}
+
+/** @name PalletIdentityBitFlags */
+export interface PalletIdentityBitFlags extends Struct {
+ readonly _bitLength: 64;
+ readonly Display: 1;
+ readonly Legal: 2;
+ readonly Web: 4;
+ readonly Riot: 8;
+ readonly Email: 16;
+ readonly PgpFingerprint: 32;
+ readonly Image: 64;
+ readonly Twitter: 128;
+}
+
+/** @name PalletIdentityCall */
+export interface PalletIdentityCall extends Enum {
+ readonly isAddRegistrar: boolean;
+ readonly asAddRegistrar: {
+ readonly account: MultiAddress;
+ } & Struct;
+ readonly isSetIdentity: boolean;
+ readonly asSetIdentity: {
+ readonly info: PalletIdentityIdentityInfo;
+ } & Struct;
+ readonly isSetSubs: boolean;
+ readonly asSetSubs: {
+ readonly subs: Vec<ITuple<[AccountId32, Data]>>;
+ } & Struct;
+ readonly isClearIdentity: boolean;
+ readonly isRequestJudgement: boolean;
+ readonly asRequestJudgement: {
+ readonly regIndex: Compact<u32>;
+ readonly maxFee: Compact<u128>;
+ } & Struct;
+ readonly isCancelRequest: boolean;
+ readonly asCancelRequest: {
+ readonly regIndex: u32;
+ } & Struct;
+ readonly isSetFee: boolean;
+ readonly asSetFee: {
+ readonly index: Compact<u32>;
+ readonly fee: Compact<u128>;
+ } & Struct;
+ readonly isSetAccountId: boolean;
+ readonly asSetAccountId: {
+ readonly index: Compact<u32>;
+ readonly new_: MultiAddress;
+ } & Struct;
+ readonly isSetFields: boolean;
+ readonly asSetFields: {
+ readonly index: Compact<u32>;
+ readonly fields: PalletIdentityBitFlags;
+ } & Struct;
+ readonly isProvideJudgement: boolean;
+ readonly asProvideJudgement: {
+ readonly regIndex: Compact<u32>;
+ readonly target: MultiAddress;
+ readonly judgement: PalletIdentityJudgement;
+ readonly identity: H256;
+ } & Struct;
+ readonly isKillIdentity: boolean;
+ readonly asKillIdentity: {
+ readonly target: MultiAddress;
+ } & Struct;
+ readonly isAddSub: boolean;
+ readonly asAddSub: {
+ readonly sub: MultiAddress;
+ readonly data: Data;
+ } & Struct;
+ readonly isRenameSub: boolean;
+ readonly asRenameSub: {
+ readonly sub: MultiAddress;
+ readonly data: Data;
+ } & Struct;
+ readonly isRemoveSub: boolean;
+ readonly asRemoveSub: {
+ readonly sub: MultiAddress;
+ } & Struct;
+ readonly isQuitSub: boolean;
+ readonly isForceInsertIdentities: boolean;
+ readonly asForceInsertIdentities: {
+ readonly identities: Vec<ITuple<[AccountId32, PalletIdentityRegistration]>>;
+ } & Struct;
+ readonly isForceRemoveIdentities: boolean;
+ readonly asForceRemoveIdentities: {
+ readonly identities: Vec<AccountId32>;
+ } & Struct;
+ readonly isForceSetSubs: boolean;
+ readonly asForceSetSubs: {
+ readonly subs: Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>>;
+ } & Struct;
+ readonly type: 'AddRegistrar' | 'SetIdentity' | 'SetSubs' | 'ClearIdentity' | 'RequestJudgement' | 'CancelRequest' | 'SetFee' | 'SetAccountId' | 'SetFields' | 'ProvideJudgement' | 'KillIdentity' | 'AddSub' | 'RenameSub' | 'RemoveSub' | 'QuitSub' | 'ForceInsertIdentities' | 'ForceRemoveIdentities' | 'ForceSetSubs';
+}
+
+/** @name PalletIdentityError */
+export interface PalletIdentityError extends Enum {
+ readonly isTooManySubAccounts: boolean;
+ readonly isNotFound: boolean;
+ readonly isNotNamed: boolean;
+ readonly isEmptyIndex: boolean;
+ readonly isFeeChanged: boolean;
+ readonly isNoIdentity: boolean;
+ readonly isStickyJudgement: boolean;
+ readonly isJudgementGiven: boolean;
+ readonly isInvalidJudgement: boolean;
+ readonly isInvalidIndex: boolean;
+ readonly isInvalidTarget: boolean;
+ readonly isTooManyFields: boolean;
+ readonly isTooManyRegistrars: boolean;
+ readonly isAlreadyClaimed: boolean;
+ readonly isNotSub: boolean;
+ readonly isNotOwned: boolean;
+ readonly isJudgementForDifferentIdentity: boolean;
+ readonly isJudgementPaymentFailed: boolean;
+ readonly type: 'TooManySubAccounts' | 'NotFound' | 'NotNamed' | 'EmptyIndex' | 'FeeChanged' | 'NoIdentity' | 'StickyJudgement' | 'JudgementGiven' | 'InvalidJudgement' | 'InvalidIndex' | 'InvalidTarget' | 'TooManyFields' | 'TooManyRegistrars' | 'AlreadyClaimed' | 'NotSub' | 'NotOwned' | 'JudgementForDifferentIdentity' | 'JudgementPaymentFailed';
+}
+
+/** @name PalletIdentityEvent */
+export interface PalletIdentityEvent extends Enum {
+ readonly isIdentitySet: boolean;
+ readonly asIdentitySet: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isIdentityCleared: boolean;
+ readonly asIdentityCleared: {
+ readonly who: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isIdentityKilled: boolean;
+ readonly asIdentityKilled: {
+ readonly who: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isIdentitiesInserted: boolean;
+ readonly asIdentitiesInserted: {
+ readonly amount: u32;
+ } & Struct;
+ readonly isIdentitiesRemoved: boolean;
+ readonly asIdentitiesRemoved: {
+ readonly amount: u32;
+ } & Struct;
+ readonly isJudgementRequested: boolean;
+ readonly asJudgementRequested: {
+ readonly who: AccountId32;
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isJudgementUnrequested: boolean;
+ readonly asJudgementUnrequested: {
+ readonly who: AccountId32;
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isJudgementGiven: boolean;
+ readonly asJudgementGiven: {
+ readonly target: AccountId32;
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isRegistrarAdded: boolean;
+ readonly asRegistrarAdded: {
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isSubIdentityAdded: boolean;
+ readonly asSubIdentityAdded: {
+ readonly sub: AccountId32;
+ readonly main: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isSubIdentityRemoved: boolean;
+ readonly asSubIdentityRemoved: {
+ readonly sub: AccountId32;
+ readonly main: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isSubIdentityRevoked: boolean;
+ readonly asSubIdentityRevoked: {
+ readonly sub: AccountId32;
+ readonly main: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isSubIdentitiesInserted: boolean;
+ readonly asSubIdentitiesInserted: {
+ readonly amount: u32;
+ } & Struct;
+ readonly type: 'IdentitySet' | 'IdentityCleared' | 'IdentityKilled' | 'IdentitiesInserted' | 'IdentitiesRemoved' | 'JudgementRequested' | 'JudgementUnrequested' | 'JudgementGiven' | 'RegistrarAdded' | 'SubIdentityAdded' | 'SubIdentityRemoved' | 'SubIdentityRevoked' | 'SubIdentitiesInserted';
+}
+
+/** @name PalletIdentityIdentityField */
+export interface PalletIdentityIdentityField extends Enum {
+ readonly isDisplay: boolean;
+ readonly isLegal: boolean;
+ readonly isWeb: boolean;
+ readonly isRiot: boolean;
+ readonly isEmail: boolean;
+ readonly isPgpFingerprint: boolean;
+ readonly isImage: boolean;
+ readonly isTwitter: boolean;
+ readonly type: 'Display' | 'Legal' | 'Web' | 'Riot' | 'Email' | 'PgpFingerprint' | 'Image' | 'Twitter';
+}
+
+/** @name PalletIdentityIdentityInfo */
+export interface PalletIdentityIdentityInfo extends Struct {
+ readonly additional: Vec<ITuple<[Data, Data]>>;
+ readonly display: Data;
+ readonly legal: Data;
+ readonly web: Data;
+ readonly riot: Data;
+ readonly email: Data;
+ readonly pgpFingerprint: Option<U8aFixed>;
+ readonly image: Data;
+ readonly twitter: Data;
+}
+
+/** @name PalletIdentityJudgement */
+export interface PalletIdentityJudgement extends Enum {
+ readonly isUnknown: boolean;
+ readonly isFeePaid: boolean;
+ readonly asFeePaid: u128;
+ readonly isReasonable: boolean;
+ readonly isKnownGood: boolean;
+ readonly isOutOfDate: boolean;
+ readonly isLowQuality: boolean;
+ readonly isErroneous: boolean;
+ readonly type: 'Unknown' | 'FeePaid' | 'Reasonable' | 'KnownGood' | 'OutOfDate' | 'LowQuality' | 'Erroneous';
+}
+
+/** @name PalletIdentityRegistrarInfo */
+export interface PalletIdentityRegistrarInfo extends Struct {
+ readonly account: AccountId32;
+ readonly fee: u128;
+ readonly fields: PalletIdentityBitFlags;
+}
+
+/** @name PalletIdentityRegistration */
+export interface PalletIdentityRegistration extends Struct {
+ readonly judgements: Vec<ITuple<[u32, PalletIdentityJudgement]>>;
+ readonly deposit: u128;
+ readonly info: PalletIdentityIdentityInfo;
+}
+
+/** @name PalletInflationCall */
+export interface PalletInflationCall extends Enum {
+ readonly isStartInflation: boolean;
+ readonly asStartInflation: {
+ readonly inflationStartRelayBlock: u32;
+ } & Struct;
+ readonly type: 'StartInflation';
+}
+
+/** @name PalletMaintenanceCall */
+export interface PalletMaintenanceCall extends Enum {
+ readonly isEnable: boolean;
+ readonly isDisable: boolean;
+ readonly type: 'Enable' | 'Disable';
+}
+
+/** @name PalletMaintenanceError */
+export interface PalletMaintenanceError extends Null {}
+
+/** @name PalletMaintenanceEvent */
+export interface PalletMaintenanceEvent extends Enum {
+ readonly isMaintenanceEnabled: boolean;
+ readonly isMaintenanceDisabled: boolean;
+ readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled';
+}
+
+/** @name PalletMembershipCall */
+export interface PalletMembershipCall extends Enum {
+ readonly isAddMember: boolean;
+ readonly asAddMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isRemoveMember: boolean;
+ readonly asRemoveMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isSwapMember: boolean;
+ readonly asSwapMember: {
+ readonly remove: MultiAddress;
+ readonly add: MultiAddress;
+ } & Struct;
+ readonly isResetMembers: boolean;
+ readonly asResetMembers: {
+ readonly members: Vec<AccountId32>;
+ } & Struct;
+ readonly isChangeKey: boolean;
+ readonly asChangeKey: {
+ readonly new_: MultiAddress;
+ } & Struct;
+ readonly isSetPrime: boolean;
+ readonly asSetPrime: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isClearPrime: boolean;
+ readonly type: 'AddMember' | 'RemoveMember' | 'SwapMember' | 'ResetMembers' | 'ChangeKey' | 'SetPrime' | 'ClearPrime';
+}
+
+/** @name PalletMembershipError */
+export interface PalletMembershipError extends Enum {
+ readonly isAlreadyMember: boolean;
+ readonly isNotMember: boolean;
+ readonly isTooManyMembers: boolean;
+ readonly type: 'AlreadyMember' | 'NotMember' | 'TooManyMembers';
+}
+
+/** @name PalletMembershipEvent */
+export interface PalletMembershipEvent extends Enum {
+ readonly isMemberAdded: boolean;
+ readonly isMemberRemoved: boolean;
+ readonly isMembersSwapped: boolean;
+ readonly isMembersReset: boolean;
+ readonly isKeyChanged: boolean;
+ readonly isDummy: boolean;
+ readonly type: 'MemberAdded' | 'MemberRemoved' | 'MembersSwapped' | 'MembersReset' | 'KeyChanged' | 'Dummy';
+}
+
+/** @name PalletNonfungibleError */
+export interface PalletNonfungibleError extends Enum {
+ readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
+ readonly isNonfungibleItemsHaveNoAmount: boolean;
+ readonly isCantBurnNftWithChildren: boolean;
+ readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
+}
+
+/** @name PalletNonfungibleItemData */
+export interface PalletNonfungibleItemData extends Struct {
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+}
+
+/** @name PalletPreimageCall */
+export interface PalletPreimageCall extends Enum {
+ readonly isNotePreimage: boolean;
+ readonly asNotePreimage: {
+ readonly bytes: Bytes;
+ } & Struct;
+ readonly isUnnotePreimage: boolean;
+ readonly asUnnotePreimage: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isRequestPreimage: boolean;
+ readonly asRequestPreimage: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isUnrequestPreimage: boolean;
+ readonly asUnrequestPreimage: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'NotePreimage' | 'UnnotePreimage' | 'RequestPreimage' | 'UnrequestPreimage';
+}
+
+/** @name PalletPreimageError */
+export interface PalletPreimageError extends Enum {
+ readonly isTooBig: boolean;
+ readonly isAlreadyNoted: boolean;
+ readonly isNotAuthorized: boolean;
+ readonly isNotNoted: boolean;
+ readonly isRequested: boolean;
+ readonly isNotRequested: boolean;
+ readonly type: 'TooBig' | 'AlreadyNoted' | 'NotAuthorized' | 'NotNoted' | 'Requested' | 'NotRequested';
+}
+
+/** @name PalletPreimageEvent */
+export interface PalletPreimageEvent extends Enum {
+ readonly isNoted: boolean;
+ readonly asNoted: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isRequested: boolean;
+ readonly asRequested: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isCleared: boolean;
+ readonly asCleared: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'Noted' | 'Requested' | 'Cleared';
+}
+
+/** @name PalletPreimageRequestStatus */
+export interface PalletPreimageRequestStatus extends Enum {
+ readonly isUnrequested: boolean;
+ readonly asUnrequested: {
+ readonly deposit: ITuple<[AccountId32, u128]>;
+ readonly len: u32;
+ } & Struct;
+ readonly isRequested: boolean;
+ readonly asRequested: {
+ readonly deposit: Option<ITuple<[AccountId32, u128]>>;
+ readonly count: u32;
+ readonly len: Option<u32>;
+ } & Struct;
+ readonly type: 'Unrequested' | 'Requested';
+}
+
+/** @name PalletRankedCollectiveCall */
+export interface PalletRankedCollectiveCall extends Enum {
+ readonly isAddMember: boolean;
+ readonly asAddMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isPromoteMember: boolean;
+ readonly asPromoteMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isDemoteMember: boolean;
+ readonly asDemoteMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isRemoveMember: boolean;
+ readonly asRemoveMember: {
+ readonly who: MultiAddress;
+ readonly minRank: u16;
+ } & Struct;
+ readonly isVote: boolean;
+ readonly asVote: {
+ readonly poll: u32;
+ readonly aye: bool;
+ } & Struct;
+ readonly isCleanupPoll: boolean;
+ readonly asCleanupPoll: {
+ readonly pollIndex: u32;
+ readonly max: u32;
+ } & Struct;
+ readonly type: 'AddMember' | 'PromoteMember' | 'DemoteMember' | 'RemoveMember' | 'Vote' | 'CleanupPoll';
+}
+
+/** @name PalletRankedCollectiveError */
+export interface PalletRankedCollectiveError extends Enum {
+ readonly isAlreadyMember: boolean;
+ readonly isNotMember: boolean;
+ readonly isNotPolling: boolean;
+ readonly isOngoing: boolean;
+ readonly isNoneRemaining: boolean;
+ readonly isCorruption: boolean;
+ readonly isRankTooLow: boolean;
+ readonly isInvalidWitness: boolean;
+ readonly isNoPermission: boolean;
+ readonly type: 'AlreadyMember' | 'NotMember' | 'NotPolling' | 'Ongoing' | 'NoneRemaining' | 'Corruption' | 'RankTooLow' | 'InvalidWitness' | 'NoPermission';
+}
+
+/** @name PalletRankedCollectiveEvent */
+export interface PalletRankedCollectiveEvent extends Enum {
+ readonly isMemberAdded: boolean;
+ readonly asMemberAdded: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isRankChanged: boolean;
+ readonly asRankChanged: {
+ readonly who: AccountId32;
+ readonly rank: u16;
+ } & Struct;
+ readonly isMemberRemoved: boolean;
+ readonly asMemberRemoved: {
+ readonly who: AccountId32;
+ readonly rank: u16;
+ } & Struct;
+ readonly isVoted: boolean;
+ readonly asVoted: {
+ readonly who: AccountId32;
+ readonly poll: u32;
+ readonly vote: PalletRankedCollectiveVoteRecord;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly type: 'MemberAdded' | 'RankChanged' | 'MemberRemoved' | 'Voted';
+}
+
+/** @name PalletRankedCollectiveMemberRecord */
+export interface PalletRankedCollectiveMemberRecord extends Struct {
+ readonly rank: u16;
+}
+
+/** @name PalletRankedCollectiveTally */
+export interface PalletRankedCollectiveTally extends Struct {
+ readonly bareAyes: u32;
+ readonly ayes: u32;
+ readonly nays: u32;
+}
+
+/** @name PalletRankedCollectiveVoteRecord */
+export interface PalletRankedCollectiveVoteRecord extends Enum {
+ readonly isAye: boolean;
+ readonly asAye: u32;
+ readonly isNay: boolean;
+ readonly asNay: u32;
+ readonly type: 'Aye' | 'Nay';
+}
+
+/** @name PalletReferendaCall */
+export interface PalletReferendaCall extends Enum {
+ readonly isSubmit: boolean;
+ readonly asSubmit: {
+ readonly proposalOrigin: OpalRuntimeOriginCaller;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly enactmentMoment: FrameSupportScheduleDispatchTime;
+ } & Struct;
+ readonly isPlaceDecisionDeposit: boolean;
+ readonly asPlaceDecisionDeposit: {
+ readonly index: u32;
+ } & Struct;
+ readonly isRefundDecisionDeposit: boolean;
+ readonly asRefundDecisionDeposit: {
+ readonly index: u32;
+ } & Struct;
+ readonly isCancel: boolean;
+ readonly asCancel: {
+ readonly index: u32;
+ } & Struct;
+ readonly isKill: boolean;
+ readonly asKill: {
+ readonly index: u32;
+ } & Struct;
+ readonly isNudgeReferendum: boolean;
+ readonly asNudgeReferendum: {
+ readonly index: u32;
+ } & Struct;
+ readonly isOneFewerDeciding: boolean;
+ readonly asOneFewerDeciding: {
+ readonly track: u16;
+ } & Struct;
+ readonly isRefundSubmissionDeposit: boolean;
+ readonly asRefundSubmissionDeposit: {
+ readonly index: u32;
+ } & Struct;
+ readonly isSetMetadata: boolean;
+ readonly asSetMetadata: {
+ readonly index: u32;
+ readonly maybeHash: Option<H256>;
+ } & Struct;
+ readonly type: 'Submit' | 'PlaceDecisionDeposit' | 'RefundDecisionDeposit' | 'Cancel' | 'Kill' | 'NudgeReferendum' | 'OneFewerDeciding' | 'RefundSubmissionDeposit' | 'SetMetadata';
+}
+
+/** @name PalletReferendaCurve */
+export interface PalletReferendaCurve extends Enum {
+ readonly isLinearDecreasing: boolean;
+ readonly asLinearDecreasing: {
+ readonly length: Perbill;
+ readonly floor: Perbill;
+ readonly ceil: Perbill;
+ } & Struct;
+ readonly isSteppedDecreasing: boolean;
+ readonly asSteppedDecreasing: {
+ readonly begin: Perbill;
+ readonly end: Perbill;
+ readonly step: Perbill;
+ readonly period: Perbill;
+ } & Struct;
+ readonly isReciprocal: boolean;
+ readonly asReciprocal: {
+ readonly factor: i64;
+ readonly xOffset: i64;
+ readonly yOffset: i64;
+ } & Struct;
+ readonly type: 'LinearDecreasing' | 'SteppedDecreasing' | 'Reciprocal';
+}
+
+/** @name PalletReferendaDecidingStatus */
+export interface PalletReferendaDecidingStatus extends Struct {
+ readonly since: u32;
+ readonly confirming: Option<u32>;
+}
+
+/** @name PalletReferendaDeposit */
+export interface PalletReferendaDeposit extends Struct {
+ readonly who: AccountId32;
+ readonly amount: u128;
+}
+
+/** @name PalletReferendaError */
+export interface PalletReferendaError extends Enum {
+ readonly isNotOngoing: boolean;
+ readonly isHasDeposit: boolean;
+ readonly isBadTrack: boolean;
+ readonly isFull: boolean;
+ readonly isQueueEmpty: boolean;
+ readonly isBadReferendum: boolean;
+ readonly isNothingToDo: boolean;
+ readonly isNoTrack: boolean;
+ readonly isUnfinished: boolean;
+ readonly isNoPermission: boolean;
+ readonly isNoDeposit: boolean;
+ readonly isBadStatus: boolean;
+ readonly isPreimageNotExist: boolean;
+ readonly type: 'NotOngoing' | 'HasDeposit' | 'BadTrack' | 'Full' | 'QueueEmpty' | 'BadReferendum' | 'NothingToDo' | 'NoTrack' | 'Unfinished' | 'NoPermission' | 'NoDeposit' | 'BadStatus' | 'PreimageNotExist';
+}
+
+/** @name PalletReferendaEvent */
+export interface PalletReferendaEvent extends Enum {
+ readonly isSubmitted: boolean;
+ readonly asSubmitted: {
+ readonly index: u32;
+ readonly track: u16;
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isDecisionDepositPlaced: boolean;
+ readonly asDecisionDepositPlaced: {
+ readonly index: u32;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDecisionDepositRefunded: boolean;
+ readonly asDecisionDepositRefunded: {
+ readonly index: u32;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDepositSlashed: boolean;
+ readonly asDepositSlashed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDecisionStarted: boolean;
+ readonly asDecisionStarted: {
+ readonly index: u32;
+ readonly track: u16;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isConfirmStarted: boolean;
+ readonly asConfirmStarted: {
+ readonly index: u32;
+ } & Struct;
+ readonly isConfirmAborted: boolean;
+ readonly asConfirmAborted: {
+ readonly index: u32;
+ } & Struct;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isApproved: boolean;
+ readonly asApproved: {
+ readonly index: u32;
+ } & Struct;
+ readonly isRejected: boolean;
+ readonly asRejected: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isTimedOut: boolean;
+ readonly asTimedOut: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isCancelled: boolean;
+ readonly asCancelled: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isKilled: boolean;
+ readonly asKilled: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isSubmissionDepositRefunded: boolean;
+ readonly asSubmissionDepositRefunded: {
+ readonly index: u32;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isMetadataSet: boolean;
+ readonly asMetadataSet: {
+ readonly index: u32;
+ readonly hash_: H256;
+ } & Struct;
+ readonly isMetadataCleared: boolean;
+ readonly asMetadataCleared: {
+ readonly index: u32;
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'Submitted' | 'DecisionDepositPlaced' | 'DecisionDepositRefunded' | 'DepositSlashed' | 'DecisionStarted' | 'ConfirmStarted' | 'ConfirmAborted' | 'Confirmed' | 'Approved' | 'Rejected' | 'TimedOut' | 'Cancelled' | 'Killed' | 'SubmissionDepositRefunded' | 'MetadataSet' | 'MetadataCleared';
+}
+
+/** @name PalletReferendaReferendumInfo */
+export interface PalletReferendaReferendumInfo extends Enum {
+ readonly isOngoing: boolean;
+ readonly asOngoing: PalletReferendaReferendumStatus;
+ readonly isApproved: boolean;
+ readonly asApproved: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isRejected: boolean;
+ readonly asRejected: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isCancelled: boolean;
+ readonly asCancelled: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isTimedOut: boolean;
+ readonly asTimedOut: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isKilled: boolean;
+ readonly asKilled: u32;
+ readonly type: 'Ongoing' | 'Approved' | 'Rejected' | 'Cancelled' | 'TimedOut' | 'Killed';
+}
+
+/** @name PalletReferendaReferendumStatus */
+export interface PalletReferendaReferendumStatus extends Struct {
+ readonly track: u16;
+ readonly origin: OpalRuntimeOriginCaller;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly enactment: FrameSupportScheduleDispatchTime;
+ readonly submitted: u32;
+ readonly submissionDeposit: PalletReferendaDeposit;
+ readonly decisionDeposit: Option<PalletReferendaDeposit>;
+ readonly deciding: Option<PalletReferendaDecidingStatus>;
+ readonly tally: PalletRankedCollectiveTally;
+ readonly inQueue: bool;
+ readonly alarm: Option<ITuple<[u32, ITuple<[u32, u32]>]>>;
+}
+
+/** @name PalletReferendaTrackInfo */
+export interface PalletReferendaTrackInfo extends Struct {
+ readonly name: Text;
+ readonly maxDeciding: u32;
+ readonly decisionDeposit: u128;
+ readonly preparePeriod: u32;
+ readonly decisionPeriod: u32;
+ readonly confirmPeriod: u32;
+ readonly minEnactmentPeriod: u32;
+ readonly minApproval: PalletReferendaCurve;
+ readonly minSupport: PalletReferendaCurve;
+}
+
+/** @name PalletRefungibleError */
+export interface PalletRefungibleError extends Enum {
+ readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
+ readonly isWrongRefungiblePieces: boolean;
+ readonly isRepartitionWhileNotOwningAllPieces: boolean;
+ readonly isRefungibleDisallowsNesting: boolean;
+ readonly isSettingPropertiesNotAllowed: boolean;
+ readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
+}
+
+/** @name PalletSchedulerCall */
+export interface PalletSchedulerCall extends Enum {
+ readonly isSchedule: boolean;
+ readonly asSchedule: {
+ readonly when: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly isCancel: boolean;
+ readonly asCancel: {
+ readonly when: u32;
+ readonly index: u32;
+ } & Struct;
+ readonly isScheduleNamed: boolean;
+ readonly asScheduleNamed: {
+ readonly id: U8aFixed;
+ readonly when: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly isCancelNamed: boolean;
+ readonly asCancelNamed: {
+ readonly id: U8aFixed;
+ } & Struct;
+ readonly isScheduleAfter: boolean;
+ readonly asScheduleAfter: {
+ readonly after: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly isScheduleNamedAfter: boolean;
+ readonly asScheduleNamedAfter: {
+ readonly id: U8aFixed;
+ readonly after: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter';
+}
+
+/** @name PalletSchedulerError */
+export interface PalletSchedulerError extends Enum {
+ readonly isFailedToSchedule: boolean;
+ readonly isNotFound: boolean;
+ readonly isTargetBlockNumberInPast: boolean;
+ readonly isRescheduleNoChange: boolean;
+ readonly isNamed: boolean;
+ readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange' | 'Named';
+}
+
+/** @name PalletSchedulerEvent */
+export interface PalletSchedulerEvent extends Enum {
+ readonly isScheduled: boolean;
+ readonly asScheduled: {
+ readonly when: u32;
+ readonly index: u32;
+ } & Struct;
+ readonly isCanceled: boolean;
+ readonly asCanceled: {
+ readonly when: u32;
+ readonly index: u32;
+ } & Struct;
+ readonly isDispatched: boolean;
+ readonly asDispatched: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isCallUnavailable: boolean;
+ readonly asCallUnavailable: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ } & Struct;
+ readonly isPeriodicFailed: boolean;
+ readonly asPeriodicFailed: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ } & Struct;
+ readonly isPermanentlyOverweight: boolean;
+ readonly asPermanentlyOverweight: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ } & Struct;
+ readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'CallUnavailable' | 'PeriodicFailed' | 'PermanentlyOverweight';
+}
+
+/** @name PalletSchedulerScheduled */
+export interface PalletSchedulerScheduled extends Struct {
+ readonly maybeId: Option<U8aFixed>;
+ readonly priority: u8;
+ readonly call: FrameSupportPreimagesBounded;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly origin: OpalRuntimeOriginCaller;
+}
+
+/** @name PalletSessionCall */
+export interface PalletSessionCall extends Enum {
+ readonly isSetKeys: boolean;
+ readonly asSetKeys: {
+ readonly keys_: OpalRuntimeRuntimeCommonSessionKeys;
+ readonly proof: Bytes;
+ } & Struct;
+ readonly isPurgeKeys: boolean;
+ readonly type: 'SetKeys' | 'PurgeKeys';
+}
+
+/** @name PalletSessionError */
+export interface PalletSessionError extends Enum {
+ readonly isInvalidProof: boolean;
+ readonly isNoAssociatedValidatorId: boolean;
+ readonly isDuplicatedKey: boolean;
+ readonly isNoKeys: boolean;
+ readonly isNoAccount: boolean;
+ readonly type: 'InvalidProof' | 'NoAssociatedValidatorId' | 'DuplicatedKey' | 'NoKeys' | 'NoAccount';
+}
+
+/** @name PalletSessionEvent */
+export interface PalletSessionEvent extends Enum {
+ readonly isNewSession: boolean;
+ readonly asNewSession: {
+ readonly sessionIndex: u32;
+ } & Struct;
+ readonly type: 'NewSession';
+}
+
+/** @name PalletStateTrieMigrationCall */
+export interface PalletStateTrieMigrationCall extends Enum {
+ readonly isControlAutoMigration: boolean;
+ readonly asControlAutoMigration: {
+ readonly maybeConfig: Option<PalletStateTrieMigrationMigrationLimits>;
+ } & Struct;
+ readonly isContinueMigrate: boolean;
+ readonly asContinueMigrate: {
+ readonly limits: PalletStateTrieMigrationMigrationLimits;
+ readonly realSizeUpper: u32;
+ readonly witnessTask: PalletStateTrieMigrationMigrationTask;
+ } & Struct;
+ readonly isMigrateCustomTop: boolean;
+ readonly asMigrateCustomTop: {
+ readonly keys_: Vec<Bytes>;
+ readonly witnessSize: u32;
+ } & Struct;
+ readonly isMigrateCustomChild: boolean;
+ readonly asMigrateCustomChild: {
+ readonly root: Bytes;
+ readonly childKeys: Vec<Bytes>;
+ readonly totalSize: u32;
+ } & Struct;
+ readonly isSetSignedMaxLimits: boolean;
+ readonly asSetSignedMaxLimits: {
+ readonly limits: PalletStateTrieMigrationMigrationLimits;
+ } & Struct;
+ readonly isForceSetProgress: boolean;
+ readonly asForceSetProgress: {
+ readonly progressTop: PalletStateTrieMigrationProgress;
+ readonly progressChild: PalletStateTrieMigrationProgress;
+ } & Struct;
+ readonly type: 'ControlAutoMigration' | 'ContinueMigrate' | 'MigrateCustomTop' | 'MigrateCustomChild' | 'SetSignedMaxLimits' | 'ForceSetProgress';
+}
+
+/** @name PalletStateTrieMigrationError */
+export interface PalletStateTrieMigrationError extends Enum {
+ readonly isMaxSignedLimits: boolean;
+ readonly isKeyTooLong: boolean;
+ readonly isNotEnoughFunds: boolean;
+ readonly isBadWitness: boolean;
+ readonly isSignedMigrationNotAllowed: boolean;
+ readonly isBadChildRoot: boolean;
+ readonly type: 'MaxSignedLimits' | 'KeyTooLong' | 'NotEnoughFunds' | 'BadWitness' | 'SignedMigrationNotAllowed' | 'BadChildRoot';
+}
+
+/** @name PalletStateTrieMigrationEvent */
+export interface PalletStateTrieMigrationEvent extends Enum {
+ readonly isMigrated: boolean;
+ readonly asMigrated: {
+ readonly top: u32;
+ readonly child: u32;
+ readonly compute: PalletStateTrieMigrationMigrationCompute;
+ } & Struct;
+ readonly isSlashed: boolean;
+ readonly asSlashed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isAutoMigrationFinished: boolean;
+ readonly isHalted: boolean;
+ readonly asHalted: {
+ readonly error: PalletStateTrieMigrationError;
+ } & Struct;
+ readonly type: 'Migrated' | 'Slashed' | 'AutoMigrationFinished' | 'Halted';
+}
+
+/** @name PalletStateTrieMigrationMigrationCompute */
+export interface PalletStateTrieMigrationMigrationCompute extends Enum {
+ readonly isSigned: boolean;
+ readonly isAuto: boolean;
+ readonly type: 'Signed' | 'Auto';
+}
+
+/** @name PalletStateTrieMigrationMigrationLimits */
+export interface PalletStateTrieMigrationMigrationLimits extends Struct {
+ readonly size_: u32;
+ readonly item: u32;
+}
+
+/** @name PalletStateTrieMigrationMigrationTask */
+export interface PalletStateTrieMigrationMigrationTask extends Struct {
+ readonly progressTop: PalletStateTrieMigrationProgress;
+ readonly progressChild: PalletStateTrieMigrationProgress;
+ readonly size_: u32;
+ readonly topItems: u32;
+ readonly childItems: u32;
+}
+
+/** @name PalletStateTrieMigrationProgress */
+export interface PalletStateTrieMigrationProgress extends Enum {
+ readonly isToStart: boolean;
+ readonly isLastKey: boolean;
+ readonly asLastKey: Bytes;
+ readonly isComplete: boolean;
+ readonly type: 'ToStart' | 'LastKey' | 'Complete';
+}
+
+/** @name PalletStructureCall */
+export interface PalletStructureCall extends Null {}
+
+/** @name PalletStructureError */
+export interface PalletStructureError extends Enum {
+ readonly isOuroborosDetected: boolean;
+ readonly isDepthLimit: boolean;
+ readonly isBreadthLimit: boolean;
+ readonly isTokenNotFound: boolean;
+ readonly isCantNestTokenUnderCollection: boolean;
+ readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound' | 'CantNestTokenUnderCollection';
+}
+
+/** @name PalletStructureEvent */
+export interface PalletStructureEvent extends Enum {
+ readonly isExecuted: boolean;
+ readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
+ readonly type: 'Executed';
+}
+
+/** @name PalletSudoCall */
+export interface PalletSudoCall extends Enum {
+ readonly isSudo: boolean;
+ readonly asSudo: {
+ readonly call: Call;
+ } & Struct;
+ readonly isSudoUncheckedWeight: boolean;
+ readonly asSudoUncheckedWeight: {
+ readonly call: Call;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isSetKey: boolean;
+ readonly asSetKey: {
+ readonly new_: MultiAddress;
+ } & Struct;
+ readonly isSudoAs: boolean;
+ readonly asSudoAs: {
+ readonly who: MultiAddress;
+ readonly call: Call;
+ } & Struct;
+ readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
+}
+
+/** @name PalletSudoError */
+export interface PalletSudoError extends Enum {
+ readonly isRequireSudo: boolean;
+ readonly type: 'RequireSudo';
+}
+
+/** @name PalletSudoEvent */
+export interface PalletSudoEvent extends Enum {
+ readonly isSudid: boolean;
+ readonly asSudid: {
+ readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isKeyChanged: boolean;
+ readonly asKeyChanged: {
+ readonly oldSudoer: Option<AccountId32>;
+ } & Struct;
+ readonly isSudoAsDone: boolean;
+ readonly asSudoAsDone: {
+ readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone';
+}
+
+/** @name PalletTemplateTransactionPaymentChargeTransactionPayment */
+export interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
+
+/** @name PalletTestUtilsCall */
+export interface PalletTestUtilsCall extends Enum {
+ readonly isEnable: boolean;
+ readonly isSetTestValue: boolean;
+ readonly asSetTestValue: {
+ readonly value: u32;
+ } & Struct;
+ readonly isSetTestValueAndRollback: boolean;
+ readonly asSetTestValueAndRollback: {
+ readonly value: u32;
+ } & Struct;
+ readonly isIncTestValue: boolean;
+ readonly isJustTakeFee: boolean;
+ readonly isBatchAll: boolean;
+ readonly asBatchAll: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'JustTakeFee' | 'BatchAll';
+}
+
+/** @name PalletTestUtilsError */
+export interface PalletTestUtilsError extends Enum {
+ readonly isTestPalletDisabled: boolean;
+ readonly isTriggerRollback: boolean;
+ readonly type: 'TestPalletDisabled' | 'TriggerRollback';
+}
+
+/** @name PalletTestUtilsEvent */
+export interface PalletTestUtilsEvent extends Enum {
+ readonly isValueIsSet: boolean;
+ readonly isShouldRollback: boolean;
+ readonly isBatchCompleted: boolean;
+ readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
+}
+
+/** @name PalletTimestampCall */
+export interface PalletTimestampCall extends Enum {
+ readonly isSet: boolean;
+ readonly asSet: {
+ readonly now: Compact<u64>;
+ } & Struct;
+ readonly type: 'Set';
+}
+
+/** @name PalletTransactionPaymentEvent */
+export interface PalletTransactionPaymentEvent extends Enum {
+ readonly isTransactionFeePaid: boolean;
+ readonly asTransactionFeePaid: {
+ readonly who: AccountId32;
+ readonly actualFee: u128;
+ readonly tip: u128;
+ } & Struct;
+ readonly type: 'TransactionFeePaid';
+}
+
+/** @name PalletTransactionPaymentReleases */
+export interface PalletTransactionPaymentReleases extends Enum {
+ readonly isV1Ancient: boolean;
+ readonly isV2: boolean;
+ readonly type: 'V1Ancient' | 'V2';
+}
+
+/** @name PalletTreasuryCall */
+export interface PalletTreasuryCall extends Enum {
+ readonly isProposeSpend: boolean;
+ readonly asProposeSpend: {
+ readonly value: Compact<u128>;
+ readonly beneficiary: MultiAddress;
+ } & Struct;
+ readonly isRejectProposal: boolean;
+ readonly asRejectProposal: {
+ readonly proposalId: Compact<u32>;
+ } & Struct;
+ readonly isApproveProposal: boolean;
+ readonly asApproveProposal: {
+ readonly proposalId: Compact<u32>;
+ } & Struct;
+ readonly isSpend: boolean;
+ readonly asSpend: {
+ readonly amount: Compact<u128>;
+ readonly beneficiary: MultiAddress;
+ } & Struct;
+ readonly isRemoveApproval: boolean;
+ readonly asRemoveApproval: {
+ readonly proposalId: Compact<u32>;
+ } & Struct;
+ readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
+}
+
+/** @name PalletTreasuryError */
+export interface PalletTreasuryError extends Enum {
+ readonly isInsufficientProposersBalance: boolean;
+ readonly isInvalidIndex: boolean;
+ readonly isTooManyApprovals: boolean;
+ readonly isInsufficientPermission: boolean;
+ readonly isProposalNotApproved: boolean;
+ readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
+}
+
+/** @name PalletTreasuryEvent */
+export interface PalletTreasuryEvent extends Enum {
+ readonly isProposed: boolean;
+ readonly asProposed: {
+ readonly proposalIndex: u32;
+ } & Struct;
+ readonly isSpending: boolean;
+ readonly asSpending: {
+ readonly budgetRemaining: u128;
+ } & Struct;
+ readonly isAwarded: boolean;
+ readonly asAwarded: {
+ readonly proposalIndex: u32;
+ readonly award: u128;
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isRejected: boolean;
+ readonly asRejected: {
+ readonly proposalIndex: u32;
+ readonly slashed: u128;
+ } & Struct;
+ readonly isBurnt: boolean;
+ readonly asBurnt: {
+ readonly burntFunds: u128;
+ } & Struct;
+ readonly isRollover: boolean;
+ readonly asRollover: {
+ readonly rolloverBalance: u128;
+ } & Struct;
+ readonly isDeposit: boolean;
+ readonly asDeposit: {
+ readonly value: u128;
+ } & Struct;
+ readonly isSpendApproved: boolean;
+ readonly asSpendApproved: {
+ readonly proposalIndex: u32;
+ readonly amount: u128;
+ readonly beneficiary: AccountId32;
+ } & Struct;
+ readonly isUpdatedInactive: boolean;
+ readonly asUpdatedInactive: {
+ readonly reactivated: u128;
+ readonly deactivated: u128;
+ } & Struct;
+ readonly type: 'Proposed' | 'Spending' | 'Awarded' | 'Rejected' | 'Burnt' | 'Rollover' | 'Deposit' | 'SpendApproved' | 'UpdatedInactive';
+}
+
+/** @name PalletTreasuryProposal */
+export interface PalletTreasuryProposal extends Struct {
+ readonly proposer: AccountId32;
+ readonly value: u128;
+ readonly beneficiary: AccountId32;
+ readonly bond: u128;
+}
+
+/** @name PalletUniqueCall */
+export interface PalletUniqueCall extends Enum {
+ readonly isCreateCollection: boolean;
+ readonly asCreateCollection: {
+ readonly collectionName: Vec<u16>;
+ readonly collectionDescription: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly mode: UpDataStructsCollectionMode;
+ } & Struct;
+ readonly isCreateCollectionEx: boolean;
+ readonly asCreateCollectionEx: {
+ readonly data: UpDataStructsCreateCollectionData;
+ } & Struct;
+ readonly isDestroyCollection: boolean;
+ readonly asDestroyCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isAddToAllowList: boolean;
+ readonly asAddToAllowList: {
+ readonly collectionId: u32;
+ readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isRemoveFromAllowList: boolean;
+ readonly asRemoveFromAllowList: {
+ readonly collectionId: u32;
+ readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isChangeCollectionOwner: boolean;
+ readonly asChangeCollectionOwner: {
+ readonly collectionId: u32;
+ readonly newOwner: AccountId32;
+ } & Struct;
+ readonly isAddCollectionAdmin: boolean;
+ readonly asAddCollectionAdmin: {
+ readonly collectionId: u32;
+ readonly newAdminId: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isRemoveCollectionAdmin: boolean;
+ readonly asRemoveCollectionAdmin: {
+ readonly collectionId: u32;
+ readonly accountId: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isSetCollectionSponsor: boolean;
+ readonly asSetCollectionSponsor: {
+ readonly collectionId: u32;
+ readonly newSponsor: AccountId32;
+ } & Struct;
+ readonly isConfirmSponsorship: boolean;
+ readonly asConfirmSponsorship: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isRemoveCollectionSponsor: boolean;
+ readonly asRemoveCollectionSponsor: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isCreateItem: boolean;
+ readonly asCreateItem: {
+ readonly collectionId: u32;
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly data: UpDataStructsCreateItemData;
+ } & Struct;
+ readonly isCreateMultipleItems: boolean;
+ readonly asCreateMultipleItems: {
+ readonly collectionId: u32;
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly itemsData: Vec<UpDataStructsCreateItemData>;
+ } & Struct;
+ readonly isSetCollectionProperties: boolean;
+ readonly asSetCollectionProperties: {
+ readonly collectionId: u32;
+ readonly properties: Vec<UpDataStructsProperty>;
+ } & Struct;
+ readonly isDeleteCollectionProperties: boolean;
+ readonly asDeleteCollectionProperties: {
+ readonly collectionId: u32;
+ readonly propertyKeys: Vec<Bytes>;
+ } & Struct;
+ readonly isSetTokenProperties: boolean;
+ readonly asSetTokenProperties: {
+ readonly collectionId: u32;
+ readonly tokenId: u32;
+ readonly properties: Vec<UpDataStructsProperty>;
+ } & Struct;
+ readonly isDeleteTokenProperties: boolean;
+ readonly asDeleteTokenProperties: {
+ readonly collectionId: u32;
+ readonly tokenId: u32;
+ readonly propertyKeys: Vec<Bytes>;
+ } & Struct;
+ readonly isSetTokenPropertyPermissions: boolean;
+ readonly asSetTokenPropertyPermissions: {
+ readonly collectionId: u32;
+ readonly propertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
+ } & Struct;
+ readonly isCreateMultipleItemsEx: boolean;
+ readonly asCreateMultipleItemsEx: {
+ readonly collectionId: u32;
+ readonly data: UpDataStructsCreateItemExData;
+ } & Struct;
+ readonly isSetTransfersEnabledFlag: boolean;
+ readonly asSetTransfersEnabledFlag: {
+ readonly collectionId: u32;
+ readonly value: bool;
+ } & Struct;
+ readonly isBurnItem: boolean;
+ readonly asBurnItem: {
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isBurnFrom: boolean;
+ readonly asBurnFrom: {
+ readonly collectionId: u32;
+ readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isApprove: boolean;
+ readonly asApprove: {
+ readonly spender: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isApproveFrom: boolean;
+ readonly asApproveFrom: {
+ readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly to: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isTransferFrom: boolean;
+ readonly asTransferFrom: {
+ readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isSetCollectionLimits: boolean;
+ readonly asSetCollectionLimits: {
+ readonly collectionId: u32;
+ readonly newLimit: UpDataStructsCollectionLimits;
+ } & Struct;
+ readonly isSetCollectionPermissions: boolean;
+ readonly asSetCollectionPermissions: {
+ readonly collectionId: u32;
+ readonly newPermission: UpDataStructsCollectionPermissions;
+ } & Struct;
+ readonly isRepartition: boolean;
+ readonly asRepartition: {
+ readonly collectionId: u32;
+ readonly tokenId: u32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSetAllowanceForAll: boolean;
+ readonly asSetAllowanceForAll: {
+ readonly collectionId: u32;
+ readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly approve: bool;
+ } & Struct;
+ readonly isForceRepairCollection: boolean;
+ readonly asForceRepairCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isForceRepairItem: boolean;
+ readonly asForceRepairItem: {
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ } & Struct;
+ readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'ApproveFrom' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem';
+}
+
+/** @name PalletUniqueError */
+export interface PalletUniqueError extends Enum {
+ readonly isCollectionDecimalPointLimitExceeded: boolean;
+ readonly isEmptyArgument: boolean;
+ readonly isRepartitionCalledOnNonRefungibleCollection: boolean;
+ readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
+}
+
+/** @name PalletUtilityCall */
+export interface PalletUtilityCall extends Enum {
+ readonly isBatch: boolean;
+ readonly asBatch: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly isAsDerivative: boolean;
+ readonly asAsDerivative: {
+ readonly index: u16;
+ readonly call: Call;
+ } & Struct;
+ readonly isBatchAll: boolean;
+ readonly asBatchAll: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly isDispatchAs: boolean;
+ readonly asDispatchAs: {
+ readonly asOrigin: OpalRuntimeOriginCaller;
+ readonly call: Call;
+ } & Struct;
+ readonly isForceBatch: boolean;
+ readonly asForceBatch: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly isWithWeight: boolean;
+ readonly asWithWeight: {
+ readonly call: Call;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'Batch' | 'AsDerivative' | 'BatchAll' | 'DispatchAs' | 'ForceBatch' | 'WithWeight';
+}
+
+/** @name PalletUtilityError */
+export interface PalletUtilityError extends Enum {
+ readonly isTooManyCalls: boolean;
+ readonly type: 'TooManyCalls';
+}
+
+/** @name PalletUtilityEvent */
+export interface PalletUtilityEvent extends Enum {
+ readonly isBatchInterrupted: boolean;
+ readonly asBatchInterrupted: {
+ readonly index: u32;
+ readonly error: SpRuntimeDispatchError;
+ } & Struct;
+ readonly isBatchCompleted: boolean;
+ readonly isBatchCompletedWithErrors: boolean;
+ readonly isItemCompleted: boolean;
+ readonly isItemFailed: boolean;
+ readonly asItemFailed: {
+ readonly error: SpRuntimeDispatchError;
+ } & Struct;
+ readonly isDispatchedAs: boolean;
+ readonly asDispatchedAs: {
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly type: 'BatchInterrupted' | 'BatchCompleted' | 'BatchCompletedWithErrors' | 'ItemCompleted' | 'ItemFailed' | 'DispatchedAs';
+}
+
+/** @name PalletXcmCall */
+export interface PalletXcmCall extends Enum {
+ readonly isSend: boolean;
+ readonly asSend: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly message: StagingXcmVersionedXcm;
+ } & Struct;
+ readonly isTeleportAssets: boolean;
+ readonly asTeleportAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ } & Struct;
+ readonly isReserveTransferAssets: boolean;
+ readonly asReserveTransferAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ } & Struct;
+ readonly isExecute: boolean;
+ readonly asExecute: {
+ readonly message: StagingXcmVersionedXcm;
+ readonly maxWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isForceXcmVersion: boolean;
+ readonly asForceXcmVersion: {
+ readonly location: StagingXcmV3MultiLocation;
+ readonly version: u32;
+ } & Struct;
+ readonly isForceDefaultXcmVersion: boolean;
+ readonly asForceDefaultXcmVersion: {
+ readonly maybeXcmVersion: Option<u32>;
+ } & Struct;
+ readonly isForceSubscribeVersionNotify: boolean;
+ readonly asForceSubscribeVersionNotify: {
+ readonly location: StagingXcmVersionedMultiLocation;
+ } & Struct;
+ readonly isForceUnsubscribeVersionNotify: boolean;
+ readonly asForceUnsubscribeVersionNotify: {
+ readonly location: StagingXcmVersionedMultiLocation;
+ } & Struct;
+ readonly isLimitedReserveTransferAssets: boolean;
+ readonly asLimitedReserveTransferAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isLimitedTeleportAssets: boolean;
+ readonly asLimitedTeleportAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isForceSuspension: boolean;
+ readonly asForceSuspension: {
+ readonly suspended: bool;
+ } & Struct;
+ readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets' | 'ForceSuspension';
+}
+
+/** @name PalletXcmError */
+export interface PalletXcmError extends Enum {
+ readonly isUnreachable: boolean;
+ readonly isSendFailure: boolean;
+ readonly isFiltered: boolean;
+ readonly isUnweighableMessage: boolean;
+ readonly isDestinationNotInvertible: boolean;
+ readonly isEmpty: boolean;
+ readonly isCannotReanchor: boolean;
+ readonly isTooManyAssets: boolean;
+ readonly isInvalidOrigin: boolean;
+ readonly isBadVersion: boolean;
+ readonly isBadLocation: boolean;
+ readonly isNoSubscription: boolean;
+ readonly isAlreadySubscribed: boolean;
+ readonly isInvalidAsset: boolean;
+ readonly isLowBalance: boolean;
+ readonly isTooManyLocks: boolean;
+ readonly isAccountNotSovereign: boolean;
+ readonly isFeesNotMet: boolean;
+ readonly isLockNotFound: boolean;
+ readonly isInUse: boolean;
+ readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed' | 'InvalidAsset' | 'LowBalance' | 'TooManyLocks' | 'AccountNotSovereign' | 'FeesNotMet' | 'LockNotFound' | 'InUse';
+}
+
+/** @name PalletXcmEvent */
+export interface PalletXcmEvent extends Enum {
+ readonly isAttempted: boolean;
+ readonly asAttempted: {
+ readonly outcome: StagingXcmV3TraitsOutcome;
+ } & Struct;
+ readonly isSent: boolean;
+ readonly asSent: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly message: StagingXcmV3Xcm;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isUnexpectedResponse: boolean;
+ readonly asUnexpectedResponse: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isResponseReady: boolean;
+ readonly asResponseReady: {
+ readonly queryId: u64;
+ readonly response: StagingXcmV3Response;
+ } & Struct;
+ readonly isNotified: boolean;
+ readonly asNotified: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ } & Struct;
+ readonly isNotifyOverweight: boolean;
+ readonly asNotifyOverweight: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ readonly actualWeight: SpWeightsWeightV2Weight;
+ readonly maxBudgetedWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isNotifyDispatchError: boolean;
+ readonly asNotifyDispatchError: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ } & Struct;
+ readonly isNotifyDecodeFailed: boolean;
+ readonly asNotifyDecodeFailed: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ } & Struct;
+ readonly isInvalidResponder: boolean;
+ readonly asInvalidResponder: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ readonly expectedLocation: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly isInvalidResponderVersion: boolean;
+ readonly asInvalidResponderVersion: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isResponseTaken: boolean;
+ readonly asResponseTaken: {
+ readonly queryId: u64;
+ } & Struct;
+ readonly isAssetsTrapped: boolean;
+ readonly asAssetsTrapped: {
+ readonly hash_: H256;
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ } & Struct;
+ readonly isVersionChangeNotified: boolean;
+ readonly asVersionChangeNotified: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly result: u32;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isSupportedVersionChanged: boolean;
+ readonly asSupportedVersionChanged: {
+ readonly location: StagingXcmV3MultiLocation;
+ readonly version: u32;
+ } & Struct;
+ readonly isNotifyTargetSendFail: boolean;
+ readonly asNotifyTargetSendFail: {
+ readonly location: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ readonly error: StagingXcmV3TraitsError;
+ } & Struct;
+ readonly isNotifyTargetMigrationFail: boolean;
+ readonly asNotifyTargetMigrationFail: {
+ readonly location: StagingXcmVersionedMultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isInvalidQuerierVersion: boolean;
+ readonly asInvalidQuerierVersion: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isInvalidQuerier: boolean;
+ readonly asInvalidQuerier: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ readonly expectedQuerier: StagingXcmV3MultiLocation;
+ readonly maybeActualQuerier: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly isVersionNotifyStarted: boolean;
+ readonly asVersionNotifyStarted: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isVersionNotifyRequested: boolean;
+ readonly asVersionNotifyRequested: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isVersionNotifyUnrequested: boolean;
+ readonly asVersionNotifyUnrequested: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isFeesPaid: boolean;
+ readonly asFeesPaid: {
+ readonly paying: StagingXcmV3MultiLocation;
+ readonly fees: StagingXcmV3MultiassetMultiAssets;
+ } & Struct;
+ readonly isAssetsClaimed: boolean;
+ readonly asAssetsClaimed: {
+ readonly hash_: H256;
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ } & Struct;
+ readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail' | 'InvalidQuerierVersion' | 'InvalidQuerier' | 'VersionNotifyStarted' | 'VersionNotifyRequested' | 'VersionNotifyUnrequested' | 'FeesPaid' | 'AssetsClaimed';
+}
+
+/** @name PalletXcmOrigin */
+export interface PalletXcmOrigin extends Enum {
+ readonly isXcm: boolean;
+ readonly asXcm: StagingXcmV3MultiLocation;
+ readonly isResponse: boolean;
+ readonly asResponse: StagingXcmV3MultiLocation;
+ readonly type: 'Xcm' | 'Response';
+}
+
+/** @name PalletXcmQueryStatus */
+export interface PalletXcmQueryStatus extends Enum {
+ readonly isPending: boolean;
+ readonly asPending: {
+ readonly responder: StagingXcmVersionedMultiLocation;
+ readonly maybeMatchQuerier: Option<StagingXcmVersionedMultiLocation>;
+ readonly maybeNotify: Option<ITuple<[u8, u8]>>;
+ readonly timeout: u32;
+ } & Struct;
+ readonly isVersionNotifier: boolean;
+ readonly asVersionNotifier: {
+ readonly origin: StagingXcmVersionedMultiLocation;
+ readonly isActive: bool;
+ } & Struct;
+ readonly isReady: boolean;
+ readonly asReady: {
+ readonly response: StagingXcmVersionedResponse;
+ readonly at: u32;
+ } & Struct;
+ readonly type: 'Pending' | 'VersionNotifier' | 'Ready';
+}
+
+/** @name PalletXcmRemoteLockedFungibleRecord */
+export interface PalletXcmRemoteLockedFungibleRecord extends Struct {
+ readonly amount: u128;
+ readonly owner: StagingXcmVersionedMultiLocation;
+ readonly locker: StagingXcmVersionedMultiLocation;
+ readonly consumers: Vec<ITuple<[Null, u128]>>;
+}
+
+/** @name PalletXcmVersionMigrationStage */
+export interface PalletXcmVersionMigrationStage extends Enum {
+ readonly isMigrateSupportedVersion: boolean;
+ readonly isMigrateVersionNotifiers: boolean;
+ readonly isNotifyCurrentTargets: boolean;
+ readonly asNotifyCurrentTargets: Option<Bytes>;
+ readonly isMigrateAndNotifyOldTargets: boolean;
+ readonly type: 'MigrateSupportedVersion' | 'MigrateVersionNotifiers' | 'NotifyCurrentTargets' | 'MigrateAndNotifyOldTargets';
+}
+
+/** @name ParachainInfoCall */
+export interface ParachainInfoCall extends Null {}
+
+/** @name PhantomTypeUpDataStructs */
+export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, UpPovEstimateRpcPovInfo]>> {}
+
+/** @name PolkadotCorePrimitivesInboundDownwardMessage */
+export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
+ readonly sentAt: u32;
+ readonly msg: Bytes;
+}
+
+/** @name PolkadotCorePrimitivesInboundHrmpMessage */
+export interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
+ readonly sentAt: u32;
+ readonly data: Bytes;
+}
+
+/** @name PolkadotCorePrimitivesOutboundHrmpMessage */
+export interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
+ readonly recipient: u32;
+ readonly data: Bytes;
+}
+
+/** @name PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat */
+export interface PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat extends Enum {
+ readonly isConcatenatedVersionedXcm: boolean;
+ readonly isConcatenatedEncodedBlob: boolean;
+ readonly isSignals: boolean;
+ readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
+}
+
+/** @name PolkadotPrimitivesV5AbridgedHostConfiguration */
+export interface PolkadotPrimitivesV5AbridgedHostConfiguration extends Struct {
+ readonly maxCodeSize: u32;
+ readonly maxHeadDataSize: u32;
+ readonly maxUpwardQueueCount: u32;
+ readonly maxUpwardQueueSize: u32;
+ readonly maxUpwardMessageSize: u32;
+ readonly maxUpwardMessageNumPerCandidate: u32;
+ readonly hrmpMaxMessageNumPerCandidate: u32;
+ readonly validationUpgradeCooldown: u32;
+ readonly validationUpgradeDelay: u32;
+ readonly asyncBackingParams: PolkadotPrimitivesVstagingAsyncBackingParams;
+}
+
+/** @name PolkadotPrimitivesV5AbridgedHrmpChannel */
+export interface PolkadotPrimitivesV5AbridgedHrmpChannel extends Struct {
+ readonly maxCapacity: u32;
+ readonly maxTotalSize: u32;
+ readonly maxMessageSize: u32;
+ readonly msgCount: u32;
+ readonly totalSize: u32;
+ readonly mqcHead: Option<H256>;
+}
+
+/** @name PolkadotPrimitivesV5PersistedValidationData */
+export interface PolkadotPrimitivesV5PersistedValidationData extends Struct {
+ readonly parentHead: Bytes;
+ readonly relayParentNumber: u32;
+ readonly relayParentStorageRoot: H256;
+ readonly maxPovSize: u32;
+}
+
+/** @name PolkadotPrimitivesV5UpgradeGoAhead */
+export interface PolkadotPrimitivesV5UpgradeGoAhead extends Enum {
+ readonly isAbort: boolean;
+ readonly isGoAhead: boolean;
+ readonly type: 'Abort' | 'GoAhead';
+}
+
+/** @name PolkadotPrimitivesV5UpgradeRestriction */
+export interface PolkadotPrimitivesV5UpgradeRestriction extends Enum {
+ readonly isPresent: boolean;
+ readonly type: 'Present';
+}
+
+/** @name PolkadotPrimitivesVstagingAsyncBackingParams */
+export interface PolkadotPrimitivesVstagingAsyncBackingParams extends Struct {
+ readonly maxCandidateDepth: u32;
+ readonly allowedAncestryLen: u32;
+}
+
+/** @name SpArithmeticArithmeticError */
+export interface SpArithmeticArithmeticError extends Enum {
+ readonly isUnderflow: boolean;
+ readonly isOverflow: boolean;
+ readonly isDivisionByZero: boolean;
+ readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero';
+}
+
+/** @name SpConsensusAuraSr25519AppSr25519Public */
+export interface SpConsensusAuraSr25519AppSr25519Public extends SpCoreSr25519Public {}
+
+/** @name SpCoreCryptoKeyTypeId */
+export interface SpCoreCryptoKeyTypeId extends U8aFixed {}
+
+/** @name SpCoreEcdsaSignature */
+export interface SpCoreEcdsaSignature extends U8aFixed {}
+
+/** @name SpCoreEd25519Signature */
+export interface SpCoreEd25519Signature extends U8aFixed {}
+
+/** @name SpCoreSr25519Public */
+export interface SpCoreSr25519Public extends U8aFixed {}
+
+/** @name SpCoreSr25519Signature */
+export interface SpCoreSr25519Signature extends U8aFixed {}
+
+/** @name SpCoreVoid */
+export interface SpCoreVoid extends Null {}
+
+/** @name SpRuntimeDigest */
+export interface SpRuntimeDigest extends Struct {
+ readonly logs: Vec<SpRuntimeDigestDigestItem>;
+}
+
+/** @name SpRuntimeDigestDigestItem */
+export interface SpRuntimeDigestDigestItem extends Enum {
+ readonly isOther: boolean;
+ readonly asOther: Bytes;
+ readonly isConsensus: boolean;
+ readonly asConsensus: ITuple<[U8aFixed, Bytes]>;
+ readonly isSeal: boolean;
+ readonly asSeal: ITuple<[U8aFixed, Bytes]>;
+ readonly isPreRuntime: boolean;
+ readonly asPreRuntime: ITuple<[U8aFixed, Bytes]>;
+ readonly isRuntimeEnvironmentUpdated: boolean;
+ readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated';
+}
+
+/** @name SpRuntimeDispatchError */
+export interface SpRuntimeDispatchError extends Enum {
+ readonly isOther: boolean;
+ readonly isCannotLookup: boolean;
+ readonly isBadOrigin: boolean;
+ readonly isModule: boolean;
+ readonly asModule: SpRuntimeModuleError;
+ readonly isConsumerRemaining: boolean;
+ readonly isNoProviders: boolean;
+ readonly isTooManyConsumers: boolean;
+ readonly isToken: boolean;
+ readonly asToken: SpRuntimeTokenError;
+ readonly isArithmetic: boolean;
+ readonly asArithmetic: SpArithmeticArithmeticError;
+ readonly isTransactional: boolean;
+ readonly asTransactional: SpRuntimeTransactionalError;
+ readonly isExhausted: boolean;
+ readonly isCorruption: boolean;
+ readonly isUnavailable: boolean;
+ readonly isRootNotAllowed: boolean;
+ readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional' | 'Exhausted' | 'Corruption' | 'Unavailable' | 'RootNotAllowed';
+}
+
+/** @name SpRuntimeModuleError */
+export interface SpRuntimeModuleError extends Struct {
+ readonly index: u8;
+ readonly error: U8aFixed;
+}
+
+/** @name SpRuntimeMultiSignature */
+export interface SpRuntimeMultiSignature extends Enum {
+ readonly isEd25519: boolean;
+ readonly asEd25519: SpCoreEd25519Signature;
+ readonly isSr25519: boolean;
+ readonly asSr25519: SpCoreSr25519Signature;
+ readonly isEcdsa: boolean;
+ readonly asEcdsa: SpCoreEcdsaSignature;
+ readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
+}
+
+/** @name SpRuntimeTokenError */
+export interface SpRuntimeTokenError extends Enum {
+ readonly isFundsUnavailable: boolean;
+ readonly isOnlyProvider: boolean;
+ readonly isBelowMinimum: boolean;
+ readonly isCannotCreate: boolean;
+ readonly isUnknownAsset: boolean;
+ readonly isFrozen: boolean;
+ readonly isUnsupported: boolean;
+ readonly isCannotCreateHold: boolean;
+ readonly isNotExpendable: boolean;
+ readonly isBlocked: boolean;
+ readonly type: 'FundsUnavailable' | 'OnlyProvider' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported' | 'CannotCreateHold' | 'NotExpendable' | 'Blocked';
+}
+
+/** @name SpRuntimeTransactionalError */
+export interface SpRuntimeTransactionalError extends Enum {
+ readonly isLimitReached: boolean;
+ readonly isNoLayer: boolean;
+ readonly type: 'LimitReached' | 'NoLayer';
+}
+
+/** @name SpRuntimeTransactionValidityInvalidTransaction */
+export interface SpRuntimeTransactionValidityInvalidTransaction extends Enum {
+ readonly isCall: boolean;
+ readonly isPayment: boolean;
+ readonly isFuture: boolean;
+ readonly isStale: boolean;
+ readonly isBadProof: boolean;
+ readonly isAncientBirthBlock: boolean;
+ readonly isExhaustsResources: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly isBadMandatory: boolean;
+ readonly isMandatoryValidation: boolean;
+ readonly isBadSigner: boolean;
+ readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner';
+}
+
+/** @name SpRuntimeTransactionValidityTransactionValidityError */
+export interface SpRuntimeTransactionValidityTransactionValidityError extends Enum {
+ readonly isInvalid: boolean;
+ readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction;
+ readonly isUnknown: boolean;
+ readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction;
+ readonly type: 'Invalid' | 'Unknown';
+}
+
+/** @name SpRuntimeTransactionValidityUnknownTransaction */
+export interface SpRuntimeTransactionValidityUnknownTransaction extends Enum {
+ readonly isCannotLookup: boolean;
+ readonly isNoUnsignedValidator: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom';
+}
+
+/** @name SpTrieStorageProof */
+export interface SpTrieStorageProof extends Struct {
+ readonly trieNodes: BTreeSet<Bytes>;
+}
+
+/** @name SpVersionRuntimeVersion */
+export interface SpVersionRuntimeVersion extends Struct {
+ readonly specName: Text;
+ readonly implName: Text;
+ readonly authoringVersion: u32;
+ readonly specVersion: u32;
+ readonly implVersion: u32;
+ readonly apis: Vec<ITuple<[U8aFixed, u32]>>;
+ readonly transactionVersion: u32;
+ readonly stateVersion: u8;
+}
+
+/** @name SpWeightsRuntimeDbWeight */
+export interface SpWeightsRuntimeDbWeight extends Struct {
+ readonly read: u64;
+ readonly write: u64;
+}
+
+/** @name SpWeightsWeightV2Weight */
+export interface SpWeightsWeightV2Weight extends Struct {
+ readonly refTime: Compact<u64>;
+ readonly proofSize: Compact<u64>;
+}
+
+/** @name StagingXcmDoubleEncoded */
+export interface StagingXcmDoubleEncoded extends Struct {
+ readonly encoded: Bytes;
+}
+
+/** @name StagingXcmV2BodyId */
+export interface StagingXcmV2BodyId extends Enum {
+ readonly isUnit: boolean;
+ readonly isNamed: boolean;
+ readonly asNamed: Bytes;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u32>;
+ readonly isExecutive: boolean;
+ readonly isTechnical: boolean;
+ readonly isLegislative: boolean;
+ readonly isJudicial: boolean;
+ readonly isDefense: boolean;
+ readonly isAdministration: boolean;
+ readonly isTreasury: boolean;
+ readonly type: 'Unit' | 'Named' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
+}
+
+/** @name StagingXcmV2BodyPart */
+export interface StagingXcmV2BodyPart extends Enum {
+ readonly isVoice: boolean;
+ readonly isMembers: boolean;
+ readonly asMembers: {
+ readonly count: Compact<u32>;
+ } & Struct;
+ readonly isFraction: boolean;
+ readonly asFraction: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isAtLeastProportion: boolean;
+ readonly asAtLeastProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isMoreThanProportion: boolean;
+ readonly asMoreThanProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
+}
+
+/** @name StagingXcmV2Instruction */
+export interface StagingXcmV2Instruction extends Enum {
+ readonly isWithdrawAsset: boolean;
+ readonly asWithdrawAsset: StagingXcmV2MultiassetMultiAssets;
+ readonly isReserveAssetDeposited: boolean;
+ readonly asReserveAssetDeposited: StagingXcmV2MultiassetMultiAssets;
+ readonly isReceiveTeleportedAsset: boolean;
+ readonly asReceiveTeleportedAsset: StagingXcmV2MultiassetMultiAssets;
+ readonly isQueryResponse: boolean;
+ readonly asQueryResponse: {
+ readonly queryId: Compact<u64>;
+ readonly response: StagingXcmV2Response;
+ readonly maxWeight: Compact<u64>;
+ } & Struct;
+ readonly isTransferAsset: boolean;
+ readonly asTransferAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssets;
+ readonly beneficiary: StagingXcmV2MultiLocation;
+ } & Struct;
+ readonly isTransferReserveAsset: boolean;
+ readonly asTransferReserveAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssets;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isTransact: boolean;
+ readonly asTransact: {
+ readonly originType: StagingXcmV2OriginKind;
+ readonly requireWeightAtMost: Compact<u64>;
+ readonly call: StagingXcmDoubleEncoded;
+ } & Struct;
+ readonly isHrmpNewChannelOpenRequest: boolean;
+ readonly asHrmpNewChannelOpenRequest: {
+ readonly sender: Compact<u32>;
+ readonly maxMessageSize: Compact<u32>;
+ readonly maxCapacity: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelAccepted: boolean;
+ readonly asHrmpChannelAccepted: {
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelClosing: boolean;
+ readonly asHrmpChannelClosing: {
+ readonly initiator: Compact<u32>;
+ readonly sender: Compact<u32>;
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isClearOrigin: boolean;
+ readonly isDescendOrigin: boolean;
+ readonly asDescendOrigin: StagingXcmV2MultilocationJunctions;
+ readonly isReportError: boolean;
+ readonly asReportError: {
+ readonly queryId: Compact<u64>;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly maxResponseWeight: Compact<u64>;
+ } & Struct;
+ readonly isDepositAsset: boolean;
+ readonly asDepositAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly maxAssets: Compact<u32>;
+ readonly beneficiary: StagingXcmV2MultiLocation;
+ } & Struct;
+ readonly isDepositReserveAsset: boolean;
+ readonly asDepositReserveAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly maxAssets: Compact<u32>;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isExchangeAsset: boolean;
+ readonly asExchangeAsset: {
+ readonly give: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly receive: StagingXcmV2MultiassetMultiAssets;
+ } & Struct;
+ readonly isInitiateReserveWithdraw: boolean;
+ readonly asInitiateReserveWithdraw: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly reserve: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isInitiateTeleport: boolean;
+ readonly asInitiateTeleport: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isQueryHolding: boolean;
+ readonly asQueryHolding: {
+ readonly queryId: Compact<u64>;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly maxResponseWeight: Compact<u64>;
+ } & Struct;
+ readonly isBuyExecution: boolean;
+ readonly asBuyExecution: {
+ readonly fees: StagingXcmV2MultiAsset;
+ readonly weightLimit: StagingXcmV2WeightLimit;
+ } & Struct;
+ readonly isRefundSurplus: boolean;
+ readonly isSetErrorHandler: boolean;
+ readonly asSetErrorHandler: StagingXcmV2Xcm;
+ readonly isSetAppendix: boolean;
+ readonly asSetAppendix: StagingXcmV2Xcm;
+ readonly isClearError: boolean;
+ readonly isClaimAsset: boolean;
+ readonly asClaimAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssets;
+ readonly ticket: StagingXcmV2MultiLocation;
+ } & Struct;
+ readonly isTrap: boolean;
+ readonly asTrap: Compact<u64>;
+ readonly isSubscribeVersion: boolean;
+ readonly asSubscribeVersion: {
+ readonly queryId: Compact<u64>;
+ readonly maxResponseWeight: Compact<u64>;
+ } & Struct;
+ readonly isUnsubscribeVersion: boolean;
+ readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion';
+}
+
+/** @name StagingXcmV2Junction */
+export interface StagingXcmV2Junction extends Enum {
+ readonly isParachain: boolean;
+ readonly asParachain: Compact<u32>;
+ readonly isAccountId32: boolean;
+ readonly asAccountId32: {
+ readonly network: StagingXcmV2NetworkId;
+ readonly id: U8aFixed;
+ } & Struct;
+ readonly isAccountIndex64: boolean;
+ readonly asAccountIndex64: {
+ readonly network: StagingXcmV2NetworkId;
+ readonly index: Compact<u64>;
+ } & Struct;
+ readonly isAccountKey20: boolean;
+ readonly asAccountKey20: {
+ readonly network: StagingXcmV2NetworkId;
+ readonly key: U8aFixed;
+ } & Struct;
+ readonly isPalletInstance: boolean;
+ readonly asPalletInstance: u8;
+ readonly isGeneralIndex: boolean;
+ readonly asGeneralIndex: Compact<u128>;
+ readonly isGeneralKey: boolean;
+ readonly asGeneralKey: Bytes;
+ readonly isOnlyChild: boolean;
+ readonly isPlurality: boolean;
+ readonly asPlurality: {
+ readonly id: StagingXcmV2BodyId;
+ readonly part: StagingXcmV2BodyPart;
+ } & Struct;
+ readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality';
+}
+
+/** @name StagingXcmV2MultiAsset */
+export interface StagingXcmV2MultiAsset extends Struct {
+ readonly id: StagingXcmV2MultiassetAssetId;
+ readonly fun: StagingXcmV2MultiassetFungibility;
+}
+
+/** @name StagingXcmV2MultiassetAssetId */
+export interface StagingXcmV2MultiassetAssetId extends Enum {
+ readonly isConcrete: boolean;
+ readonly asConcrete: StagingXcmV2MultiLocation;
+ readonly isAbstract: boolean;
+ readonly asAbstract: Bytes;
+ readonly type: 'Concrete' | 'Abstract';
+}
+
+/** @name StagingXcmV2MultiassetAssetInstance */
+export interface StagingXcmV2MultiassetAssetInstance extends Enum {
+ readonly isUndefined: boolean;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u128>;
+ readonly isArray4: boolean;
+ readonly asArray4: U8aFixed;
+ readonly isArray8: boolean;
+ readonly asArray8: U8aFixed;
+ readonly isArray16: boolean;
+ readonly asArray16: U8aFixed;
+ readonly isArray32: boolean;
+ readonly asArray32: U8aFixed;
+ readonly isBlob: boolean;
+ readonly asBlob: Bytes;
+ readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32' | 'Blob';
+}
+
+/** @name StagingXcmV2MultiassetFungibility */
+export interface StagingXcmV2MultiassetFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly asFungible: Compact<u128>;
+ readonly isNonFungible: boolean;
+ readonly asNonFungible: StagingXcmV2MultiassetAssetInstance;
+ readonly type: 'Fungible' | 'NonFungible';
+}
+
+/** @name StagingXcmV2MultiassetMultiAssetFilter */
+export interface StagingXcmV2MultiassetMultiAssetFilter extends Enum {
+ readonly isDefinite: boolean;
+ readonly asDefinite: StagingXcmV2MultiassetMultiAssets;
+ readonly isWild: boolean;
+ readonly asWild: StagingXcmV2MultiassetWildMultiAsset;
+ readonly type: 'Definite' | 'Wild';
+}
+
+/** @name StagingXcmV2MultiassetMultiAssets */
+export interface StagingXcmV2MultiassetMultiAssets extends Vec<StagingXcmV2MultiAsset> {}
+
+/** @name StagingXcmV2MultiassetWildFungibility */
+export interface StagingXcmV2MultiassetWildFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly isNonFungible: boolean;
+ readonly type: 'Fungible' | 'NonFungible';
+}
+
+/** @name StagingXcmV2MultiassetWildMultiAsset */
+export interface StagingXcmV2MultiassetWildMultiAsset extends Enum {
+ readonly isAll: boolean;
+ readonly isAllOf: boolean;
+ readonly asAllOf: {
+ readonly id: StagingXcmV2MultiassetAssetId;
+ readonly fun: StagingXcmV2MultiassetWildFungibility;
+ } & Struct;
+ readonly type: 'All' | 'AllOf';
+}
+
+/** @name StagingXcmV2MultiLocation */
+export interface StagingXcmV2MultiLocation extends Struct {
+ readonly parents: u8;
+ readonly interior: StagingXcmV2MultilocationJunctions;
+}
+
+/** @name StagingXcmV2MultilocationJunctions */
+export interface StagingXcmV2MultilocationJunctions extends Enum {
+ readonly isHere: boolean;
+ readonly isX1: boolean;
+ readonly asX1: StagingXcmV2Junction;
+ readonly isX2: boolean;
+ readonly asX2: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX3: boolean;
+ readonly asX3: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX4: boolean;
+ readonly asX4: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX5: boolean;
+ readonly asX5: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX6: boolean;
+ readonly asX6: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX7: boolean;
+ readonly asX7: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX8: boolean;
+ readonly asX8: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
+}
+
+/** @name StagingXcmV2NetworkId */
+export interface StagingXcmV2NetworkId extends Enum {
+ readonly isAny: boolean;
+ readonly isNamed: boolean;
+ readonly asNamed: Bytes;
+ readonly isPolkadot: boolean;
+ readonly isKusama: boolean;
+ readonly type: 'Any' | 'Named' | 'Polkadot' | 'Kusama';
+}
+
+/** @name StagingXcmV2OriginKind */
+export interface StagingXcmV2OriginKind extends Enum {
+ readonly isNative: boolean;
+ readonly isSovereignAccount: boolean;
+ readonly isSuperuser: boolean;
+ readonly isXcm: boolean;
+ readonly type: 'Native' | 'SovereignAccount' | 'Superuser' | 'Xcm';
+}
+
+/** @name StagingXcmV2Response */
+export interface StagingXcmV2Response extends Enum {
+ readonly isNull: boolean;
+ readonly isAssets: boolean;
+ readonly asAssets: StagingXcmV2MultiassetMultiAssets;
+ readonly isExecutionResult: boolean;
+ readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV2TraitsError]>>;
+ readonly isVersion: boolean;
+ readonly asVersion: u32;
+ readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version';
+}
+
+/** @name StagingXcmV2TraitsError */
+export interface StagingXcmV2TraitsError extends Enum {
+ readonly isOverflow: boolean;
+ readonly isUnimplemented: boolean;
+ readonly isUntrustedReserveLocation: boolean;
+ readonly isUntrustedTeleportLocation: boolean;
+ readonly isMultiLocationFull: boolean;
+ readonly isMultiLocationNotInvertible: boolean;
+ readonly isBadOrigin: boolean;
+ readonly isInvalidLocation: boolean;
+ readonly isAssetNotFound: boolean;
+ readonly isFailedToTransactAsset: boolean;
+ readonly isNotWithdrawable: boolean;
+ readonly isLocationCannotHold: boolean;
+ readonly isExceedsMaxMessageSize: boolean;
+ readonly isDestinationUnsupported: boolean;
+ readonly isTransport: boolean;
+ readonly isUnroutable: boolean;
+ readonly isUnknownClaim: boolean;
+ readonly isFailedToDecode: boolean;
+ readonly isMaxWeightInvalid: boolean;
+ readonly isNotHoldingFees: boolean;
+ readonly isTooExpensive: boolean;
+ readonly isTrap: boolean;
+ readonly asTrap: u64;
+ readonly isUnhandledXcmVersion: boolean;
+ readonly isWeightLimitReached: boolean;
+ readonly asWeightLimitReached: u64;
+ readonly isBarrier: boolean;
+ readonly isWeightNotComputable: boolean;
+ readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'MultiLocationFull' | 'MultiLocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable';
+}
+
+/** @name StagingXcmV2WeightLimit */
+export interface StagingXcmV2WeightLimit extends Enum {
+ readonly isUnlimited: boolean;
+ readonly isLimited: boolean;
+ readonly asLimited: Compact<u64>;
+ readonly type: 'Unlimited' | 'Limited';
+}
+
+/** @name StagingXcmV2Xcm */
+export interface StagingXcmV2Xcm extends Vec<StagingXcmV2Instruction> {}
+
+/** @name StagingXcmV3Instruction */
+export interface StagingXcmV3Instruction extends Enum {
+ readonly isWithdrawAsset: boolean;
+ readonly asWithdrawAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isReserveAssetDeposited: boolean;
+ readonly asReserveAssetDeposited: StagingXcmV3MultiassetMultiAssets;
+ readonly isReceiveTeleportedAsset: boolean;
+ readonly asReceiveTeleportedAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isQueryResponse: boolean;
+ readonly asQueryResponse: {
+ readonly queryId: Compact<u64>;
+ readonly response: StagingXcmV3Response;
+ readonly maxWeight: SpWeightsWeightV2Weight;
+ readonly querier: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly isTransferAsset: boolean;
+ readonly asTransferAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly beneficiary: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isTransferReserveAsset: boolean;
+ readonly asTransferReserveAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly dest: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isTransact: boolean;
+ readonly asTransact: {
+ readonly originKind: StagingXcmV2OriginKind;
+ readonly requireWeightAtMost: SpWeightsWeightV2Weight;
+ readonly call: StagingXcmDoubleEncoded;
+ } & Struct;
+ readonly isHrmpNewChannelOpenRequest: boolean;
+ readonly asHrmpNewChannelOpenRequest: {
+ readonly sender: Compact<u32>;
+ readonly maxMessageSize: Compact<u32>;
+ readonly maxCapacity: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelAccepted: boolean;
+ readonly asHrmpChannelAccepted: {
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelClosing: boolean;
+ readonly asHrmpChannelClosing: {
+ readonly initiator: Compact<u32>;
+ readonly sender: Compact<u32>;
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isClearOrigin: boolean;
+ readonly isDescendOrigin: boolean;
+ readonly asDescendOrigin: StagingXcmV3Junctions;
+ readonly isReportError: boolean;
+ readonly asReportError: StagingXcmV3QueryResponseInfo;
+ readonly isDepositAsset: boolean;
+ readonly asDepositAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly beneficiary: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isDepositReserveAsset: boolean;
+ readonly asDepositReserveAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly dest: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isExchangeAsset: boolean;
+ readonly asExchangeAsset: {
+ readonly give: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly want: StagingXcmV3MultiassetMultiAssets;
+ readonly maximal: bool;
+ } & Struct;
+ readonly isInitiateReserveWithdraw: boolean;
+ readonly asInitiateReserveWithdraw: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly reserve: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isInitiateTeleport: boolean;
+ readonly asInitiateTeleport: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly dest: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isReportHolding: boolean;
+ readonly asReportHolding: {
+ readonly responseInfo: StagingXcmV3QueryResponseInfo;
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ } & Struct;
+ readonly isBuyExecution: boolean;
+ readonly asBuyExecution: {
+ readonly fees: StagingXcmV3MultiAsset;
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isRefundSurplus: boolean;
+ readonly isSetErrorHandler: boolean;
+ readonly asSetErrorHandler: StagingXcmV3Xcm;
+ readonly isSetAppendix: boolean;
+ readonly asSetAppendix: StagingXcmV3Xcm;
+ readonly isClearError: boolean;
+ readonly isClaimAsset: boolean;
+ readonly asClaimAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly ticket: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isTrap: boolean;
+ readonly asTrap: Compact<u64>;
+ readonly isSubscribeVersion: boolean;
+ readonly asSubscribeVersion: {
+ readonly queryId: Compact<u64>;
+ readonly maxResponseWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isUnsubscribeVersion: boolean;
+ readonly isBurnAsset: boolean;
+ readonly asBurnAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isExpectAsset: boolean;
+ readonly asExpectAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isExpectOrigin: boolean;
+ readonly asExpectOrigin: Option<StagingXcmV3MultiLocation>;
+ readonly isExpectError: boolean;
+ readonly asExpectError: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
+ readonly isExpectTransactStatus: boolean;
+ readonly asExpectTransactStatus: StagingXcmV3MaybeErrorCode;
+ readonly isQueryPallet: boolean;
+ readonly asQueryPallet: {
+ readonly moduleName: Bytes;
+ readonly responseInfo: StagingXcmV3QueryResponseInfo;
+ } & Struct;
+ readonly isExpectPallet: boolean;
+ readonly asExpectPallet: {
+ readonly index: Compact<u32>;
+ readonly name: Bytes;
+ readonly moduleName: Bytes;
+ readonly crateMajor: Compact<u32>;
+ readonly minCrateMinor: Compact<u32>;
+ } & Struct;
+ readonly isReportTransactStatus: boolean;
+ readonly asReportTransactStatus: StagingXcmV3QueryResponseInfo;
+ readonly isClearTransactStatus: boolean;
+ readonly isUniversalOrigin: boolean;
+ readonly asUniversalOrigin: StagingXcmV3Junction;
+ readonly isExportMessage: boolean;
+ readonly asExportMessage: {
+ readonly network: StagingXcmV3JunctionNetworkId;
+ readonly destination: StagingXcmV3Junctions;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isLockAsset: boolean;
+ readonly asLockAsset: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly unlocker: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isUnlockAsset: boolean;
+ readonly asUnlockAsset: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly target: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isNoteUnlockable: boolean;
+ readonly asNoteUnlockable: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly owner: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isRequestUnlock: boolean;
+ readonly asRequestUnlock: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly locker: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isSetFeesMode: boolean;
+ readonly asSetFeesMode: {
+ readonly jitWithdraw: bool;
+ } & Struct;
+ readonly isSetTopic: boolean;
+ readonly asSetTopic: U8aFixed;
+ readonly isClearTopic: boolean;
+ readonly isAliasOrigin: boolean;
+ readonly asAliasOrigin: StagingXcmV3MultiLocation;
+ readonly isUnpaidExecution: boolean;
+ readonly asUnpaidExecution: {
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ readonly checkOrigin: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'ReportHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion' | 'BurnAsset' | 'ExpectAsset' | 'ExpectOrigin' | 'ExpectError' | 'ExpectTransactStatus' | 'QueryPallet' | 'ExpectPallet' | 'ReportTransactStatus' | 'ClearTransactStatus' | 'UniversalOrigin' | 'ExportMessage' | 'LockAsset' | 'UnlockAsset' | 'NoteUnlockable' | 'RequestUnlock' | 'SetFeesMode' | 'SetTopic' | 'ClearTopic' | 'AliasOrigin' | 'UnpaidExecution';
+}
+
+/** @name StagingXcmV3Junction */
+export interface StagingXcmV3Junction extends Enum {
+ readonly isParachain: boolean;
+ readonly asParachain: Compact<u32>;
+ readonly isAccountId32: boolean;
+ readonly asAccountId32: {
+ readonly network: Option<StagingXcmV3JunctionNetworkId>;
+ readonly id: U8aFixed;
+ } & Struct;
+ readonly isAccountIndex64: boolean;
+ readonly asAccountIndex64: {
+ readonly network: Option<StagingXcmV3JunctionNetworkId>;
+ readonly index: Compact<u64>;
+ } & Struct;
+ readonly isAccountKey20: boolean;
+ readonly asAccountKey20: {
+ readonly network: Option<StagingXcmV3JunctionNetworkId>;
+ readonly key: U8aFixed;
+ } & Struct;
+ readonly isPalletInstance: boolean;
+ readonly asPalletInstance: u8;
+ readonly isGeneralIndex: boolean;
+ readonly asGeneralIndex: Compact<u128>;
+ readonly isGeneralKey: boolean;
+ readonly asGeneralKey: {
+ readonly length: u8;
+ readonly data: U8aFixed;
+ } & Struct;
+ readonly isOnlyChild: boolean;
+ readonly isPlurality: boolean;
+ readonly asPlurality: {
+ readonly id: StagingXcmV3JunctionBodyId;
+ readonly part: StagingXcmV3JunctionBodyPart;
+ } & Struct;
+ readonly isGlobalConsensus: boolean;
+ readonly asGlobalConsensus: StagingXcmV3JunctionNetworkId;
+ readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality' | 'GlobalConsensus';
+}
+
+/** @name StagingXcmV3JunctionBodyId */
+export interface StagingXcmV3JunctionBodyId extends Enum {
+ readonly isUnit: boolean;
+ readonly isMoniker: boolean;
+ readonly asMoniker: U8aFixed;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u32>;
+ readonly isExecutive: boolean;
+ readonly isTechnical: boolean;
+ readonly isLegislative: boolean;
+ readonly isJudicial: boolean;
+ readonly isDefense: boolean;
+ readonly isAdministration: boolean;
+ readonly isTreasury: boolean;
+ readonly type: 'Unit' | 'Moniker' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
+}
+
+/** @name StagingXcmV3JunctionBodyPart */
+export interface StagingXcmV3JunctionBodyPart extends Enum {
+ readonly isVoice: boolean;
+ readonly isMembers: boolean;
+ readonly asMembers: {
+ readonly count: Compact<u32>;
+ } & Struct;
+ readonly isFraction: boolean;
+ readonly asFraction: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isAtLeastProportion: boolean;
+ readonly asAtLeastProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isMoreThanProportion: boolean;
+ readonly asMoreThanProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
+}
+
+/** @name StagingXcmV3JunctionNetworkId */
+export interface StagingXcmV3JunctionNetworkId extends Enum {
+ readonly isByGenesis: boolean;
+ readonly asByGenesis: U8aFixed;
+ readonly isByFork: boolean;
+ readonly asByFork: {
+ readonly blockNumber: u64;
+ readonly blockHash: U8aFixed;
+ } & Struct;
+ readonly isPolkadot: boolean;
+ readonly isKusama: boolean;
+ readonly isWestend: boolean;
+ readonly isRococo: boolean;
+ readonly isWococo: boolean;
+ readonly isEthereum: boolean;
+ readonly asEthereum: {
+ readonly chainId: Compact<u64>;
+ } & Struct;
+ readonly isBitcoinCore: boolean;
+ readonly isBitcoinCash: boolean;
+ readonly type: 'ByGenesis' | 'ByFork' | 'Polkadot' | 'Kusama' | 'Westend' | 'Rococo' | 'Wococo' | 'Ethereum' | 'BitcoinCore' | 'BitcoinCash';
+}
+
+/** @name StagingXcmV3Junctions */
+export interface StagingXcmV3Junctions extends Enum {
+ readonly isHere: boolean;
+ readonly isX1: boolean;
+ readonly asX1: StagingXcmV3Junction;
+ readonly isX2: boolean;
+ readonly asX2: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX3: boolean;
+ readonly asX3: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX4: boolean;
+ readonly asX4: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX5: boolean;
+ readonly asX5: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX6: boolean;
+ readonly asX6: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX7: boolean;
+ readonly asX7: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX8: boolean;
+ readonly asX8: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
+}
+
+/** @name StagingXcmV3MaybeErrorCode */
+export interface StagingXcmV3MaybeErrorCode extends Enum {
+ readonly isSuccess: boolean;
+ readonly isError: boolean;
+ readonly asError: Bytes;
+ readonly isTruncatedError: boolean;
+ readonly asTruncatedError: Bytes;
+ readonly type: 'Success' | 'Error' | 'TruncatedError';
+}
+
+/** @name StagingXcmV3MultiAsset */
+export interface StagingXcmV3MultiAsset extends Struct {
+ readonly id: StagingXcmV3MultiassetAssetId;
+ readonly fun: StagingXcmV3MultiassetFungibility;
+}
+
+/** @name StagingXcmV3MultiassetAssetId */
+export interface StagingXcmV3MultiassetAssetId extends Enum {
+ readonly isConcrete: boolean;
+ readonly asConcrete: StagingXcmV3MultiLocation;
+ readonly isAbstract: boolean;
+ readonly asAbstract: U8aFixed;
+ readonly type: 'Concrete' | 'Abstract';
+}
+
+/** @name StagingXcmV3MultiassetAssetInstance */
+export interface StagingXcmV3MultiassetAssetInstance extends Enum {
+ readonly isUndefined: boolean;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u128>;
+ readonly isArray4: boolean;
+ readonly asArray4: U8aFixed;
+ readonly isArray8: boolean;
+ readonly asArray8: U8aFixed;
+ readonly isArray16: boolean;
+ readonly asArray16: U8aFixed;
+ readonly isArray32: boolean;
+ readonly asArray32: U8aFixed;
+ readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32';
+}
+
+/** @name StagingXcmV3MultiassetFungibility */
+export interface StagingXcmV3MultiassetFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly asFungible: Compact<u128>;
+ readonly isNonFungible: boolean;
+ readonly asNonFungible: StagingXcmV3MultiassetAssetInstance;
+ readonly type: 'Fungible' | 'NonFungible';
+}
+
+/** @name StagingXcmV3MultiassetMultiAssetFilter */
+export interface StagingXcmV3MultiassetMultiAssetFilter extends Enum {
+ readonly isDefinite: boolean;
+ readonly asDefinite: StagingXcmV3MultiassetMultiAssets;
+ readonly isWild: boolean;
+ readonly asWild: StagingXcmV3MultiassetWildMultiAsset;
+ readonly type: 'Definite' | 'Wild';
+}
+
+/** @name StagingXcmV3MultiassetMultiAssets */
+export interface StagingXcmV3MultiassetMultiAssets extends Vec<StagingXcmV3MultiAsset> {}
+
+/** @name StagingXcmV3MultiassetWildFungibility */
+export interface StagingXcmV3MultiassetWildFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly isNonFungible: boolean;
+ readonly type: 'Fungible' | 'NonFungible';
+}
+
+/** @name StagingXcmV3MultiassetWildMultiAsset */
+export interface StagingXcmV3MultiassetWildMultiAsset extends Enum {
+ readonly isAll: boolean;
+ readonly isAllOf: boolean;
+ readonly asAllOf: {
+ readonly id: StagingXcmV3MultiassetAssetId;
+ readonly fun: StagingXcmV3MultiassetWildFungibility;
+ } & Struct;
+ readonly isAllCounted: boolean;
+ readonly asAllCounted: Compact<u32>;
+ readonly isAllOfCounted: boolean;
+ readonly asAllOfCounted: {
+ readonly id: StagingXcmV3MultiassetAssetId;
+ readonly fun: StagingXcmV3MultiassetWildFungibility;
+ readonly count: Compact<u32>;
+ } & Struct;
+ readonly type: 'All' | 'AllOf' | 'AllCounted' | 'AllOfCounted';
+}
+
+/** @name StagingXcmV3MultiLocation */
+export interface StagingXcmV3MultiLocation extends Struct {
+ readonly parents: u8;
+ readonly interior: StagingXcmV3Junctions;
+}
+
+/** @name StagingXcmV3PalletInfo */
+export interface StagingXcmV3PalletInfo extends Struct {
+ readonly index: Compact<u32>;
+ readonly name: Bytes;
+ readonly moduleName: Bytes;
+ readonly major: Compact<u32>;
+ readonly minor: Compact<u32>;
+ readonly patch: Compact<u32>;
+}
+
+/** @name StagingXcmV3QueryResponseInfo */
+export interface StagingXcmV3QueryResponseInfo extends Struct {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly queryId: Compact<u64>;
+ readonly maxWeight: SpWeightsWeightV2Weight;
+}
+
+/** @name StagingXcmV3Response */
+export interface StagingXcmV3Response extends Enum {
+ readonly isNull: boolean;
+ readonly isAssets: boolean;
+ readonly asAssets: StagingXcmV3MultiassetMultiAssets;
+ readonly isExecutionResult: boolean;
+ readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
+ readonly isVersion: boolean;
+ readonly asVersion: u32;
+ readonly isPalletsInfo: boolean;
+ readonly asPalletsInfo: Vec<StagingXcmV3PalletInfo>;
+ readonly isDispatchResult: boolean;
+ readonly asDispatchResult: StagingXcmV3MaybeErrorCode;
+ readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version' | 'PalletsInfo' | 'DispatchResult';
+}
+
+/** @name StagingXcmV3TraitsError */
+export interface StagingXcmV3TraitsError extends Enum {
+ readonly isOverflow: boolean;
+ readonly isUnimplemented: boolean;
+ readonly isUntrustedReserveLocation: boolean;
+ readonly isUntrustedTeleportLocation: boolean;
+ readonly isLocationFull: boolean;
+ readonly isLocationNotInvertible: boolean;
+ readonly isBadOrigin: boolean;
+ readonly isInvalidLocation: boolean;
+ readonly isAssetNotFound: boolean;
+ readonly isFailedToTransactAsset: boolean;
+ readonly isNotWithdrawable: boolean;
+ readonly isLocationCannotHold: boolean;
+ readonly isExceedsMaxMessageSize: boolean;
+ readonly isDestinationUnsupported: boolean;
+ readonly isTransport: boolean;
+ readonly isUnroutable: boolean;
+ readonly isUnknownClaim: boolean;
+ readonly isFailedToDecode: boolean;
+ readonly isMaxWeightInvalid: boolean;
+ readonly isNotHoldingFees: boolean;
+ readonly isTooExpensive: boolean;
+ readonly isTrap: boolean;
+ readonly asTrap: u64;
+ readonly isExpectationFalse: boolean;
+ readonly isPalletNotFound: boolean;
+ readonly isNameMismatch: boolean;
+ readonly isVersionIncompatible: boolean;
+ readonly isHoldingWouldOverflow: boolean;
+ readonly isExportError: boolean;
+ readonly isReanchorFailed: boolean;
+ readonly isNoDeal: boolean;
+ readonly isFeesNotMet: boolean;
+ readonly isLockError: boolean;
+ readonly isNoPermission: boolean;
+ readonly isUnanchored: boolean;
+ readonly isNotDepositable: boolean;
+ readonly isUnhandledXcmVersion: boolean;
+ readonly isWeightLimitReached: boolean;
+ readonly asWeightLimitReached: SpWeightsWeightV2Weight;
+ readonly isBarrier: boolean;
+ readonly isWeightNotComputable: boolean;
+ readonly isExceedsStackLimit: boolean;
+ readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'LocationFull' | 'LocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'ExpectationFalse' | 'PalletNotFound' | 'NameMismatch' | 'VersionIncompatible' | 'HoldingWouldOverflow' | 'ExportError' | 'ReanchorFailed' | 'NoDeal' | 'FeesNotMet' | 'LockError' | 'NoPermission' | 'Unanchored' | 'NotDepositable' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable' | 'ExceedsStackLimit';
+}
+
+/** @name StagingXcmV3TraitsOutcome */
+export interface StagingXcmV3TraitsOutcome extends Enum {
+ readonly isComplete: boolean;
+ readonly asComplete: SpWeightsWeightV2Weight;
+ readonly isIncomplete: boolean;
+ readonly asIncomplete: ITuple<[SpWeightsWeightV2Weight, StagingXcmV3TraitsError]>;
+ readonly isError: boolean;
+ readonly asError: StagingXcmV3TraitsError;
+ readonly type: 'Complete' | 'Incomplete' | 'Error';
+}
+
+/** @name StagingXcmV3WeightLimit */
+export interface StagingXcmV3WeightLimit extends Enum {
+ readonly isUnlimited: boolean;
+ readonly isLimited: boolean;
+ readonly asLimited: SpWeightsWeightV2Weight;
+ readonly type: 'Unlimited' | 'Limited';
+}
+
+/** @name StagingXcmV3Xcm */
+export interface StagingXcmV3Xcm extends Vec<StagingXcmV3Instruction> {}
+
+/** @name StagingXcmVersionedAssetId */
+export interface StagingXcmVersionedAssetId extends Enum {
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiassetAssetId;
+ readonly type: 'V3';
+}
+
+/** @name StagingXcmVersionedMultiAsset */
+export interface StagingXcmVersionedMultiAsset extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2MultiAsset;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiAsset;
+ readonly type: 'V2' | 'V3';
+}
+
+/** @name StagingXcmVersionedMultiAssets */
+export interface StagingXcmVersionedMultiAssets extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2MultiassetMultiAssets;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiassetMultiAssets;
+ readonly type: 'V2' | 'V3';
+}
+
+/** @name StagingXcmVersionedMultiLocation */
+export interface StagingXcmVersionedMultiLocation extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2MultiLocation;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiLocation;
+ readonly type: 'V2' | 'V3';
+}
+
+/** @name StagingXcmVersionedResponse */
+export interface StagingXcmVersionedResponse extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2Response;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3Response;
+ readonly type: 'V2' | 'V3';
+}
+
+/** @name StagingXcmVersionedXcm */
+export interface StagingXcmVersionedXcm extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2Xcm;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3Xcm;
+ readonly type: 'V2' | 'V3';
+}
+
+/** @name UpDataStructsAccessMode */
+export interface UpDataStructsAccessMode extends Enum {
+ readonly isNormal: boolean;
+ readonly isAllowList: boolean;
+ readonly type: 'Normal' | 'AllowList';
+}
+
+/** @name UpDataStructsCollection */
+export interface UpDataStructsCollection extends Struct {
+ readonly owner: AccountId32;
+ readonly mode: UpDataStructsCollectionMode;
+ readonly name: Vec<u16>;
+ readonly description: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
+ readonly limits: UpDataStructsCollectionLimits;
+ readonly permissions: UpDataStructsCollectionPermissions;
+ readonly flags: U8aFixed;
+}
+
+/** @name UpDataStructsCollectionLimits */
+export interface UpDataStructsCollectionLimits extends Struct {
+ readonly accountTokenOwnershipLimit: Option<u32>;
+ readonly sponsoredDataSize: Option<u32>;
+ readonly sponsoredDataRateLimit: Option<UpDataStructsSponsoringRateLimit>;
+ readonly tokenLimit: Option<u32>;
+ readonly sponsorTransferTimeout: Option<u32>;
+ readonly sponsorApproveTimeout: Option<u32>;
+ readonly ownerCanTransfer: Option<bool>;
+ readonly ownerCanDestroy: Option<bool>;
+ readonly transfersEnabled: Option<bool>;
+}
+
+/** @name UpDataStructsCollectionMode */
+export interface UpDataStructsCollectionMode extends Enum {
+ readonly isNft: boolean;
+ readonly isFungible: boolean;
+ readonly asFungible: u8;
+ readonly isReFungible: boolean;
+ readonly type: 'Nft' | 'Fungible' | 'ReFungible';
+}
+
+/** @name UpDataStructsCollectionPermissions */
+export interface UpDataStructsCollectionPermissions extends Struct {
+ readonly access: Option<UpDataStructsAccessMode>;
+ readonly mintMode: Option<bool>;
+ readonly nesting: Option<UpDataStructsNestingPermissions>;
+}
+
+/** @name UpDataStructsCollectionStats */
+export interface UpDataStructsCollectionStats extends Struct {
+ readonly created: u32;
+ readonly destroyed: u32;
+ readonly alive: u32;
+}
+
+/** @name UpDataStructsCreateCollectionData */
+export interface UpDataStructsCreateCollectionData extends Struct {
+ readonly mode: UpDataStructsCollectionMode;
+ readonly access: Option<UpDataStructsAccessMode>;
+ readonly name: Vec<u16>;
+ readonly description: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly limits: Option<UpDataStructsCollectionLimits>;
+ readonly permissions: Option<UpDataStructsCollectionPermissions>;
+ readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly adminList: Vec<PalletEvmAccountBasicCrossAccountIdRepr>;
+ readonly pendingSponsor: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
+ readonly flags: U8aFixed;
+}
+
+/** @name UpDataStructsCreateFungibleData */
+export interface UpDataStructsCreateFungibleData extends Struct {
+ readonly value: u128;
+}
+
+/** @name UpDataStructsCreateItemData */
+export interface UpDataStructsCreateItemData extends Enum {
+ readonly isNft: boolean;
+ readonly asNft: UpDataStructsCreateNftData;
+ readonly isFungible: boolean;
+ readonly asFungible: UpDataStructsCreateFungibleData;
+ readonly isReFungible: boolean;
+ readonly asReFungible: UpDataStructsCreateReFungibleData;
+ readonly type: 'Nft' | 'Fungible' | 'ReFungible';
+}
+
+/** @name UpDataStructsCreateItemExData */
+export interface UpDataStructsCreateItemExData extends Enum {
+ readonly isNft: boolean;
+ readonly asNft: Vec<UpDataStructsCreateNftExData>;
+ readonly isFungible: boolean;
+ readonly asFungible: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr,u128>;
+ readonly isRefungibleMultipleItems: boolean;
+ readonly asRefungibleMultipleItems: Vec<UpDataStructsCreateRefungibleExSingleOwner>;
+ readonly isRefungibleMultipleOwners: boolean;
+ readonly asRefungibleMultipleOwners: UpDataStructsCreateRefungibleExMultipleOwners;
+ readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
+}
+
+/** @name UpDataStructsCreateNftData */
+export interface UpDataStructsCreateNftData extends Struct {
+ readonly properties: Vec<UpDataStructsProperty>;
+}
+
+/** @name UpDataStructsCreateNftExData */
+export interface UpDataStructsCreateNftExData extends Struct {
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+}
+
+/** @name UpDataStructsCreateReFungibleData */
+export interface UpDataStructsCreateReFungibleData extends Struct {
+ readonly pieces: u128;
+ readonly properties: Vec<UpDataStructsProperty>;
+}
+
+/** @name UpDataStructsCreateRefungibleExMultipleOwners */
+export interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
+ readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
+ readonly properties: Vec<UpDataStructsProperty>;
+}
+
+/** @name UpDataStructsCreateRefungibleExSingleOwner */
+export interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
+ readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly pieces: u128;
+ readonly properties: Vec<UpDataStructsProperty>;
+}
+
+/** @name UpDataStructsNestingPermissions */
+export interface UpDataStructsNestingPermissions extends Struct {
+ readonly tokenOwner: bool;
+ readonly collectionAdmin: bool;
+ readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
+}
+
+/** @name UpDataStructsOwnerRestrictedSet */
+export interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
+
+/** @name UpDataStructsProperties */
+export interface UpDataStructsProperties extends Struct {
+ readonly map: UpDataStructsPropertiesMapBoundedVec;
+ readonly consumedSpace: u32;
+ readonly reserved: u32;
+}
+
+/** @name UpDataStructsPropertiesMapBoundedVec */
+export interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
+
+/** @name UpDataStructsPropertiesMapPropertyPermission */
+export interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
+
+/** @name UpDataStructsProperty */
+export interface UpDataStructsProperty extends Struct {
+ readonly key: Bytes;
+ readonly value: Bytes;
+}
+
+/** @name UpDataStructsPropertyKeyPermission */
+export interface UpDataStructsPropertyKeyPermission extends Struct {
+ readonly key: Bytes;
+ readonly permission: UpDataStructsPropertyPermission;
+}
+
+/** @name UpDataStructsPropertyPermission */
+export interface UpDataStructsPropertyPermission extends Struct {
+ readonly mutable: bool;
+ readonly collectionAdmin: bool;
+ readonly tokenOwner: bool;
+}
+
+/** @name UpDataStructsPropertyScope */
+export interface UpDataStructsPropertyScope extends Enum {
+ readonly isNone: boolean;
+ readonly isRmrk: boolean;
+ readonly type: 'None' | 'Rmrk';
+}
+
+/** @name UpDataStructsRpcCollection */
+export interface UpDataStructsRpcCollection extends Struct {
+ readonly owner: AccountId32;
+ readonly mode: UpDataStructsCollectionMode;
+ readonly name: Vec<u16>;
+ readonly description: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
+ readonly limits: UpDataStructsCollectionLimits;
+ readonly permissions: UpDataStructsCollectionPermissions;
+ readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly readOnly: bool;
+ readonly flags: UpDataStructsRpcCollectionFlags;
+}
+
+/** @name UpDataStructsRpcCollectionFlags */
+export interface UpDataStructsRpcCollectionFlags extends Struct {
+ readonly foreign: bool;
+ readonly erc721metadata: bool;
+}
+
+/** @name UpDataStructsSponsoringRateLimit */
+export interface UpDataStructsSponsoringRateLimit extends Enum {
+ readonly isSponsoringDisabled: boolean;
+ readonly isBlocks: boolean;
+ readonly asBlocks: u32;
+ readonly type: 'SponsoringDisabled' | 'Blocks';
+}
+
+/** @name UpDataStructsSponsorshipStateAccountId32 */
+export interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
+ readonly isDisabled: boolean;
+ readonly isUnconfirmed: boolean;
+ readonly asUnconfirmed: AccountId32;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: AccountId32;
+ readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
+}
+
+/** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr */
+export interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
+ readonly isDisabled: boolean;
+ readonly isUnconfirmed: boolean;
+ readonly asUnconfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
+}
+
+/** @name UpDataStructsTokenChild */
+export interface UpDataStructsTokenChild extends Struct {
+ readonly token: u32;
+ readonly collection: u32;
+}
+
+/** @name UpDataStructsTokenData */
+export interface UpDataStructsTokenData extends Struct {
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
+ readonly pieces: u128;
+}
+
+/** @name UpPovEstimateRpcPovInfo */
+export interface UpPovEstimateRpcPovInfo extends Struct {
+ readonly proofSize: u64;
+ readonly compactProofSize: u64;
+ readonly compressedProofSize: u64;
+ readonly results: Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>;
+ readonly keyValues: Vec<UpPovEstimateRpcTrieKeyValue>;
+}
+
+/** @name UpPovEstimateRpcTrieKeyValue */
+export interface UpPovEstimateRpcTrieKeyValue extends Struct {
+ readonly key: Bytes;
+ readonly value: Bytes;
+}
+
+export type PHANTOM_DEFAULT = 'default';
js-packages/types/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/definitions.ts
@@ -0,0 +1,20 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+export {default as unique} from './unique/definitions.js';
+export {default as appPromotion} from './appPromotion/definitions.js';
+export {default as povinfo} from './povinfo/definitions.js';
+export {default as default} from './default/definitions.js';
js-packages/types/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/index.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './types.js';
js-packages/types/lookup.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/lookup.ts
@@ -0,0 +1,5165 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+/* eslint-disable sort-keys */
+
+export default {
+ /**
+ * Lookup3: frame_system::AccountInfo<Nonce, pallet_balances::types::AccountData<Balance>>
+ **/
+ FrameSystemAccountInfo: {
+ nonce: 'u32',
+ consumers: 'u32',
+ providers: 'u32',
+ sufficients: 'u32',
+ data: 'PalletBalancesAccountData'
+ },
+ /**
+ * Lookup5: pallet_balances::types::AccountData<Balance>
+ **/
+ PalletBalancesAccountData: {
+ free: 'u128',
+ reserved: 'u128',
+ frozen: 'u128',
+ flags: 'u128'
+ },
+ /**
+ * Lookup8: frame_support::dispatch::PerDispatchClass<sp_weights::weight_v2::Weight>
+ **/
+ FrameSupportDispatchPerDispatchClassWeight: {
+ normal: 'SpWeightsWeightV2Weight',
+ operational: 'SpWeightsWeightV2Weight',
+ mandatory: 'SpWeightsWeightV2Weight'
+ },
+ /**
+ * Lookup9: sp_weights::weight_v2::Weight
+ **/
+ SpWeightsWeightV2Weight: {
+ refTime: 'Compact<u64>',
+ proofSize: 'Compact<u64>'
+ },
+ /**
+ * Lookup14: sp_runtime::generic::digest::Digest
+ **/
+ SpRuntimeDigest: {
+ logs: 'Vec<SpRuntimeDigestDigestItem>'
+ },
+ /**
+ * Lookup16: sp_runtime::generic::digest::DigestItem
+ **/
+ SpRuntimeDigestDigestItem: {
+ _enum: {
+ Other: 'Bytes',
+ __Unused1: 'Null',
+ __Unused2: 'Null',
+ __Unused3: 'Null',
+ Consensus: '([u8;4],Bytes)',
+ Seal: '([u8;4],Bytes)',
+ PreRuntime: '([u8;4],Bytes)',
+ __Unused7: 'Null',
+ RuntimeEnvironmentUpdated: 'Null'
+ }
+ },
+ /**
+ * Lookup19: frame_system::EventRecord<opal_runtime::RuntimeEvent, primitive_types::H256>
+ **/
+ FrameSystemEventRecord: {
+ phase: 'FrameSystemPhase',
+ event: 'Event',
+ topics: 'Vec<H256>'
+ },
+ /**
+ * Lookup21: frame_system::pallet::Event<T>
+ **/
+ FrameSystemEvent: {
+ _enum: {
+ ExtrinsicSuccess: {
+ dispatchInfo: 'FrameSupportDispatchDispatchInfo',
+ },
+ ExtrinsicFailed: {
+ dispatchError: 'SpRuntimeDispatchError',
+ dispatchInfo: 'FrameSupportDispatchDispatchInfo',
+ },
+ CodeUpdated: 'Null',
+ NewAccount: {
+ account: 'AccountId32',
+ },
+ KilledAccount: {
+ account: 'AccountId32',
+ },
+ Remarked: {
+ _alias: {
+ hash_: 'hash',
+ },
+ sender: 'AccountId32',
+ hash_: 'H256'
+ }
+ }
+ },
+ /**
+ * Lookup22: frame_support::dispatch::DispatchInfo
+ **/
+ FrameSupportDispatchDispatchInfo: {
+ weight: 'SpWeightsWeightV2Weight',
+ class: 'FrameSupportDispatchDispatchClass',
+ paysFee: 'FrameSupportDispatchPays'
+ },
+ /**
+ * Lookup23: frame_support::dispatch::DispatchClass
+ **/
+ FrameSupportDispatchDispatchClass: {
+ _enum: ['Normal', 'Operational', 'Mandatory']
+ },
+ /**
+ * Lookup24: frame_support::dispatch::Pays
+ **/
+ FrameSupportDispatchPays: {
+ _enum: ['Yes', 'No']
+ },
+ /**
+ * Lookup25: sp_runtime::DispatchError
+ **/
+ SpRuntimeDispatchError: {
+ _enum: {
+ Other: 'Null',
+ CannotLookup: 'Null',
+ BadOrigin: 'Null',
+ Module: 'SpRuntimeModuleError',
+ ConsumerRemaining: 'Null',
+ NoProviders: 'Null',
+ TooManyConsumers: 'Null',
+ Token: 'SpRuntimeTokenError',
+ Arithmetic: 'SpArithmeticArithmeticError',
+ Transactional: 'SpRuntimeTransactionalError',
+ Exhausted: 'Null',
+ Corruption: 'Null',
+ Unavailable: 'Null',
+ RootNotAllowed: 'Null'
+ }
+ },
+ /**
+ * Lookup26: sp_runtime::ModuleError
+ **/
+ SpRuntimeModuleError: {
+ index: 'u8',
+ error: '[u8;4]'
+ },
+ /**
+ * Lookup27: sp_runtime::TokenError
+ **/
+ SpRuntimeTokenError: {
+ _enum: ['FundsUnavailable', 'OnlyProvider', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported', 'CannotCreateHold', 'NotExpendable', 'Blocked']
+ },
+ /**
+ * Lookup28: sp_arithmetic::ArithmeticError
+ **/
+ SpArithmeticArithmeticError: {
+ _enum: ['Underflow', 'Overflow', 'DivisionByZero']
+ },
+ /**
+ * Lookup29: sp_runtime::TransactionalError
+ **/
+ SpRuntimeTransactionalError: {
+ _enum: ['LimitReached', 'NoLayer']
+ },
+ /**
+ * Lookup30: pallet_state_trie_migration::pallet::Event<T>
+ **/
+ PalletStateTrieMigrationEvent: {
+ _enum: {
+ Migrated: {
+ top: 'u32',
+ child: 'u32',
+ compute: 'PalletStateTrieMigrationMigrationCompute',
+ },
+ Slashed: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ AutoMigrationFinished: 'Null',
+ Halted: {
+ error: 'PalletStateTrieMigrationError'
+ }
+ }
+ },
+ /**
+ * Lookup31: pallet_state_trie_migration::pallet::MigrationCompute
+ **/
+ PalletStateTrieMigrationMigrationCompute: {
+ _enum: ['Signed', 'Auto']
+ },
+ /**
+ * Lookup32: pallet_state_trie_migration::pallet::Error<T>
+ **/
+ PalletStateTrieMigrationError: {
+ _enum: ['MaxSignedLimits', 'KeyTooLong', 'NotEnoughFunds', 'BadWitness', 'SignedMigrationNotAllowed', 'BadChildRoot']
+ },
+ /**
+ * Lookup33: cumulus_pallet_parachain_system::pallet::Event<T>
+ **/
+ CumulusPalletParachainSystemEvent: {
+ _enum: {
+ ValidationFunctionStored: 'Null',
+ ValidationFunctionApplied: {
+ relayChainBlockNum: 'u32',
+ },
+ ValidationFunctionDiscarded: 'Null',
+ UpgradeAuthorized: {
+ codeHash: 'H256',
+ },
+ DownwardMessagesReceived: {
+ count: 'u32',
+ },
+ DownwardMessagesProcessed: {
+ weightUsed: 'SpWeightsWeightV2Weight',
+ dmqHead: 'H256',
+ },
+ UpwardMessageSent: {
+ messageHash: 'Option<[u8;32]>'
+ }
+ }
+ },
+ /**
+ * Lookup35: pallet_collator_selection::pallet::Event<T>
+ **/
+ PalletCollatorSelectionEvent: {
+ _enum: {
+ InvulnerableAdded: {
+ invulnerable: 'AccountId32',
+ },
+ InvulnerableRemoved: {
+ invulnerable: 'AccountId32',
+ },
+ LicenseObtained: {
+ accountId: 'AccountId32',
+ deposit: 'u128',
+ },
+ LicenseReleased: {
+ accountId: 'AccountId32',
+ depositReturned: 'u128',
+ },
+ CandidateAdded: {
+ accountId: 'AccountId32',
+ },
+ CandidateRemoved: {
+ accountId: 'AccountId32'
+ }
+ }
+ },
+ /**
+ * Lookup36: pallet_session::pallet::Event
+ **/
+ PalletSessionEvent: {
+ _enum: {
+ NewSession: {
+ sessionIndex: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup37: pallet_balances::pallet::Event<T, I>
+ **/
+ PalletBalancesEvent: {
+ _enum: {
+ Endowed: {
+ account: 'AccountId32',
+ freeBalance: 'u128',
+ },
+ DustLost: {
+ account: 'AccountId32',
+ amount: 'u128',
+ },
+ Transfer: {
+ from: 'AccountId32',
+ to: 'AccountId32',
+ amount: 'u128',
+ },
+ BalanceSet: {
+ who: 'AccountId32',
+ free: 'u128',
+ },
+ Reserved: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Unreserved: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ ReserveRepatriated: {
+ from: 'AccountId32',
+ to: 'AccountId32',
+ amount: 'u128',
+ destinationStatus: 'FrameSupportTokensMiscBalanceStatus',
+ },
+ Deposit: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Withdraw: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Slashed: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Minted: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Burned: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Suspended: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Restored: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Upgraded: {
+ who: 'AccountId32',
+ },
+ Issued: {
+ amount: 'u128',
+ },
+ Rescinded: {
+ amount: 'u128',
+ },
+ Locked: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Unlocked: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Frozen: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Thawed: {
+ who: 'AccountId32',
+ amount: 'u128'
+ }
+ }
+ },
+ /**
+ * Lookup38: frame_support::traits::tokens::misc::BalanceStatus
+ **/
+ FrameSupportTokensMiscBalanceStatus: {
+ _enum: ['Free', 'Reserved']
+ },
+ /**
+ * Lookup39: pallet_transaction_payment::pallet::Event<T>
+ **/
+ PalletTransactionPaymentEvent: {
+ _enum: {
+ TransactionFeePaid: {
+ who: 'AccountId32',
+ actualFee: 'u128',
+ tip: 'u128'
+ }
+ }
+ },
+ /**
+ * Lookup40: pallet_treasury::pallet::Event<T, I>
+ **/
+ PalletTreasuryEvent: {
+ _enum: {
+ Proposed: {
+ proposalIndex: 'u32',
+ },
+ Spending: {
+ budgetRemaining: 'u128',
+ },
+ Awarded: {
+ proposalIndex: 'u32',
+ award: 'u128',
+ account: 'AccountId32',
+ },
+ Rejected: {
+ proposalIndex: 'u32',
+ slashed: 'u128',
+ },
+ Burnt: {
+ burntFunds: 'u128',
+ },
+ Rollover: {
+ rolloverBalance: 'u128',
+ },
+ Deposit: {
+ value: 'u128',
+ },
+ SpendApproved: {
+ proposalIndex: 'u32',
+ amount: 'u128',
+ beneficiary: 'AccountId32',
+ },
+ UpdatedInactive: {
+ reactivated: 'u128',
+ deactivated: 'u128'
+ }
+ }
+ },
+ /**
+ * Lookup41: pallet_sudo::pallet::Event<T>
+ **/
+ PalletSudoEvent: {
+ _enum: {
+ Sudid: {
+ sudoResult: 'Result<Null, SpRuntimeDispatchError>',
+ },
+ KeyChanged: {
+ oldSudoer: 'Option<AccountId32>',
+ },
+ SudoAsDone: {
+ sudoResult: 'Result<Null, SpRuntimeDispatchError>'
+ }
+ }
+ },
+ /**
+ * Lookup45: orml_vesting::module::Event<T>
+ **/
+ OrmlVestingModuleEvent: {
+ _enum: {
+ VestingScheduleAdded: {
+ from: 'AccountId32',
+ to: 'AccountId32',
+ vestingSchedule: 'OrmlVestingVestingSchedule',
+ },
+ Claimed: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ VestingSchedulesUpdated: {
+ who: 'AccountId32'
+ }
+ }
+ },
+ /**
+ * Lookup46: orml_vesting::VestingSchedule<BlockNumber, Balance>
+ **/
+ OrmlVestingVestingSchedule: {
+ start: 'u32',
+ period: 'u32',
+ periodCount: 'u32',
+ perPeriod: 'Compact<u128>'
+ },
+ /**
+ * Lookup48: orml_xtokens::module::Event<T>
+ **/
+ OrmlXtokensModuleEvent: {
+ _enum: {
+ TransferredMultiAssets: {
+ sender: 'AccountId32',
+ assets: 'StagingXcmV3MultiassetMultiAssets',
+ fee: 'StagingXcmV3MultiAsset',
+ dest: 'StagingXcmV3MultiLocation'
+ }
+ }
+ },
+ /**
+ * Lookup49: staging_xcm::v3::multiasset::MultiAssets
+ **/
+ StagingXcmV3MultiassetMultiAssets: 'Vec<StagingXcmV3MultiAsset>',
+ /**
+ * Lookup51: staging_xcm::v3::multiasset::MultiAsset
+ **/
+ StagingXcmV3MultiAsset: {
+ id: 'StagingXcmV3MultiassetAssetId',
+ fun: 'StagingXcmV3MultiassetFungibility'
+ },
+ /**
+ * Lookup52: staging_xcm::v3::multiasset::AssetId
+ **/
+ StagingXcmV3MultiassetAssetId: {
+ _enum: {
+ Concrete: 'StagingXcmV3MultiLocation',
+ Abstract: '[u8;32]'
+ }
+ },
+ /**
+ * Lookup53: staging_xcm::v3::multilocation::MultiLocation
+ **/
+ StagingXcmV3MultiLocation: {
+ parents: 'u8',
+ interior: 'StagingXcmV3Junctions'
+ },
+ /**
+ * Lookup54: staging_xcm::v3::junctions::Junctions
+ **/
+ StagingXcmV3Junctions: {
+ _enum: {
+ Here: 'Null',
+ X1: 'StagingXcmV3Junction',
+ X2: '(StagingXcmV3Junction,StagingXcmV3Junction)',
+ X3: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
+ X4: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
+ X5: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
+ X6: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
+ X7: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
+ X8: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)'
+ }
+ },
+ /**
+ * Lookup55: staging_xcm::v3::junction::Junction
+ **/
+ StagingXcmV3Junction: {
+ _enum: {
+ Parachain: 'Compact<u32>',
+ AccountId32: {
+ network: 'Option<StagingXcmV3JunctionNetworkId>',
+ id: '[u8;32]',
+ },
+ AccountIndex64: {
+ network: 'Option<StagingXcmV3JunctionNetworkId>',
+ index: 'Compact<u64>',
+ },
+ AccountKey20: {
+ network: 'Option<StagingXcmV3JunctionNetworkId>',
+ key: '[u8;20]',
+ },
+ PalletInstance: 'u8',
+ GeneralIndex: 'Compact<u128>',
+ GeneralKey: {
+ length: 'u8',
+ data: '[u8;32]',
+ },
+ OnlyChild: 'Null',
+ Plurality: {
+ id: 'StagingXcmV3JunctionBodyId',
+ part: 'StagingXcmV3JunctionBodyPart',
+ },
+ GlobalConsensus: 'StagingXcmV3JunctionNetworkId'
+ }
+ },
+ /**
+ * Lookup58: staging_xcm::v3::junction::NetworkId
+ **/
+ StagingXcmV3JunctionNetworkId: {
+ _enum: {
+ ByGenesis: '[u8;32]',
+ ByFork: {
+ blockNumber: 'u64',
+ blockHash: '[u8;32]',
+ },
+ Polkadot: 'Null',
+ Kusama: 'Null',
+ Westend: 'Null',
+ Rococo: 'Null',
+ Wococo: 'Null',
+ Ethereum: {
+ chainId: 'Compact<u64>',
+ },
+ BitcoinCore: 'Null',
+ BitcoinCash: 'Null'
+ }
+ },
+ /**
+ * Lookup60: staging_xcm::v3::junction::BodyId
+ **/
+ StagingXcmV3JunctionBodyId: {
+ _enum: {
+ Unit: 'Null',
+ Moniker: '[u8;4]',
+ Index: 'Compact<u32>',
+ Executive: 'Null',
+ Technical: 'Null',
+ Legislative: 'Null',
+ Judicial: 'Null',
+ Defense: 'Null',
+ Administration: 'Null',
+ Treasury: 'Null'
+ }
+ },
+ /**
+ * Lookup61: staging_xcm::v3::junction::BodyPart
+ **/
+ StagingXcmV3JunctionBodyPart: {
+ _enum: {
+ Voice: 'Null',
+ Members: {
+ count: 'Compact<u32>',
+ },
+ Fraction: {
+ nom: 'Compact<u32>',
+ denom: 'Compact<u32>',
+ },
+ AtLeastProportion: {
+ nom: 'Compact<u32>',
+ denom: 'Compact<u32>',
+ },
+ MoreThanProportion: {
+ nom: 'Compact<u32>',
+ denom: 'Compact<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup62: staging_xcm::v3::multiasset::Fungibility
+ **/
+ StagingXcmV3MultiassetFungibility: {
+ _enum: {
+ Fungible: 'Compact<u128>',
+ NonFungible: 'StagingXcmV3MultiassetAssetInstance'
+ }
+ },
+ /**
+ * Lookup63: staging_xcm::v3::multiasset::AssetInstance
+ **/
+ StagingXcmV3MultiassetAssetInstance: {
+ _enum: {
+ Undefined: 'Null',
+ Index: 'Compact<u128>',
+ Array4: '[u8;4]',
+ Array8: '[u8;8]',
+ Array16: '[u8;16]',
+ Array32: '[u8;32]'
+ }
+ },
+ /**
+ * Lookup66: orml_tokens::module::Event<T>
+ **/
+ OrmlTokensModuleEvent: {
+ _enum: {
+ Endowed: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ DustLost: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Transfer: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ from: 'AccountId32',
+ to: 'AccountId32',
+ amount: 'u128',
+ },
+ Reserved: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Unreserved: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ ReserveRepatriated: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ from: 'AccountId32',
+ to: 'AccountId32',
+ amount: 'u128',
+ status: 'FrameSupportTokensMiscBalanceStatus',
+ },
+ BalanceSet: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ free: 'u128',
+ reserved: 'u128',
+ },
+ TotalIssuanceSet: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'u128',
+ },
+ Withdrawn: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Slashed: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ freeAmount: 'u128',
+ reservedAmount: 'u128',
+ },
+ Deposited: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ LockSet: {
+ lockId: '[u8;8]',
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ LockRemoved: {
+ lockId: '[u8;8]',
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ },
+ Locked: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Unlocked: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ Issued: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'u128',
+ },
+ Rescinded: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'u128'
+ }
+ }
+ },
+ /**
+ * Lookup67: pallet_foreign_assets::AssetId
+ **/
+ PalletForeignAssetsAssetId: {
+ _enum: {
+ ForeignAssetId: 'u32',
+ NativeAssetId: 'PalletForeignAssetsNativeCurrency'
+ }
+ },
+ /**
+ * Lookup68: pallet_foreign_assets::NativeCurrency
+ **/
+ PalletForeignAssetsNativeCurrency: {
+ _enum: ['Here', 'Parent']
+ },
+ /**
+ * Lookup69: pallet_identity::pallet::Event<T>
+ **/
+ PalletIdentityEvent: {
+ _enum: {
+ IdentitySet: {
+ who: 'AccountId32',
+ },
+ IdentityCleared: {
+ who: 'AccountId32',
+ deposit: 'u128',
+ },
+ IdentityKilled: {
+ who: 'AccountId32',
+ deposit: 'u128',
+ },
+ IdentitiesInserted: {
+ amount: 'u32',
+ },
+ IdentitiesRemoved: {
+ amount: 'u32',
+ },
+ JudgementRequested: {
+ who: 'AccountId32',
+ registrarIndex: 'u32',
+ },
+ JudgementUnrequested: {
+ who: 'AccountId32',
+ registrarIndex: 'u32',
+ },
+ JudgementGiven: {
+ target: 'AccountId32',
+ registrarIndex: 'u32',
+ },
+ RegistrarAdded: {
+ registrarIndex: 'u32',
+ },
+ SubIdentityAdded: {
+ sub: 'AccountId32',
+ main: 'AccountId32',
+ deposit: 'u128',
+ },
+ SubIdentityRemoved: {
+ sub: 'AccountId32',
+ main: 'AccountId32',
+ deposit: 'u128',
+ },
+ SubIdentityRevoked: {
+ sub: 'AccountId32',
+ main: 'AccountId32',
+ deposit: 'u128',
+ },
+ SubIdentitiesInserted: {
+ amount: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup70: pallet_preimage::pallet::Event<T>
+ **/
+ PalletPreimageEvent: {
+ _enum: {
+ Noted: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ },
+ Requested: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ },
+ Cleared: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256'
+ }
+ }
+ },
+ /**
+ * Lookup71: pallet_democracy::pallet::Event<T>
+ **/
+ PalletDemocracyEvent: {
+ _enum: {
+ Proposed: {
+ proposalIndex: 'u32',
+ deposit: 'u128',
+ },
+ Tabled: {
+ proposalIndex: 'u32',
+ deposit: 'u128',
+ },
+ ExternalTabled: 'Null',
+ Started: {
+ refIndex: 'u32',
+ threshold: 'PalletDemocracyVoteThreshold',
+ },
+ Passed: {
+ refIndex: 'u32',
+ },
+ NotPassed: {
+ refIndex: 'u32',
+ },
+ Cancelled: {
+ refIndex: 'u32',
+ },
+ Delegated: {
+ who: 'AccountId32',
+ target: 'AccountId32',
+ },
+ Undelegated: {
+ account: 'AccountId32',
+ },
+ Vetoed: {
+ who: 'AccountId32',
+ proposalHash: 'H256',
+ until: 'u32',
+ },
+ Blacklisted: {
+ proposalHash: 'H256',
+ },
+ Voted: {
+ voter: 'AccountId32',
+ refIndex: 'u32',
+ vote: 'PalletDemocracyVoteAccountVote',
+ },
+ Seconded: {
+ seconder: 'AccountId32',
+ propIndex: 'u32',
+ },
+ ProposalCanceled: {
+ propIndex: 'u32',
+ },
+ MetadataSet: {
+ _alias: {
+ hash_: 'hash',
+ },
+ owner: 'PalletDemocracyMetadataOwner',
+ hash_: 'H256',
+ },
+ MetadataCleared: {
+ _alias: {
+ hash_: 'hash',
+ },
+ owner: 'PalletDemocracyMetadataOwner',
+ hash_: 'H256',
+ },
+ MetadataTransferred: {
+ _alias: {
+ hash_: 'hash',
+ },
+ prevOwner: 'PalletDemocracyMetadataOwner',
+ owner: 'PalletDemocracyMetadataOwner',
+ hash_: 'H256'
+ }
+ }
+ },
+ /**
+ * Lookup72: pallet_democracy::vote_threshold::VoteThreshold
+ **/
+ PalletDemocracyVoteThreshold: {
+ _enum: ['SuperMajorityApprove', 'SuperMajorityAgainst', 'SimpleMajority']
+ },
+ /**
+ * Lookup73: pallet_democracy::vote::AccountVote<Balance>
+ **/
+ PalletDemocracyVoteAccountVote: {
+ _enum: {
+ Standard: {
+ vote: 'Vote',
+ balance: 'u128',
+ },
+ Split: {
+ aye: 'u128',
+ nay: 'u128'
+ }
+ }
+ },
+ /**
+ * Lookup75: pallet_democracy::types::MetadataOwner
+ **/
+ PalletDemocracyMetadataOwner: {
+ _enum: {
+ External: 'Null',
+ Proposal: 'u32',
+ Referendum: 'u32'
+ }
+ },
+ /**
+ * Lookup76: pallet_collective::pallet::Event<T, I>
+ **/
+ PalletCollectiveEvent: {
+ _enum: {
+ Proposed: {
+ account: 'AccountId32',
+ proposalIndex: 'u32',
+ proposalHash: 'H256',
+ threshold: 'u32',
+ },
+ Voted: {
+ account: 'AccountId32',
+ proposalHash: 'H256',
+ voted: 'bool',
+ yes: 'u32',
+ no: 'u32',
+ },
+ Approved: {
+ proposalHash: 'H256',
+ },
+ Disapproved: {
+ proposalHash: 'H256',
+ },
+ Executed: {
+ proposalHash: 'H256',
+ result: 'Result<Null, SpRuntimeDispatchError>',
+ },
+ MemberExecuted: {
+ proposalHash: 'H256',
+ result: 'Result<Null, SpRuntimeDispatchError>',
+ },
+ Closed: {
+ proposalHash: 'H256',
+ yes: 'u32',
+ no: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup79: pallet_membership::pallet::Event<T, I>
+ **/
+ PalletMembershipEvent: {
+ _enum: ['MemberAdded', 'MemberRemoved', 'MembersSwapped', 'MembersReset', 'KeyChanged', 'Dummy']
+ },
+ /**
+ * Lookup81: pallet_ranked_collective::pallet::Event<T, I>
+ **/
+ PalletRankedCollectiveEvent: {
+ _enum: {
+ MemberAdded: {
+ who: 'AccountId32',
+ },
+ RankChanged: {
+ who: 'AccountId32',
+ rank: 'u16',
+ },
+ MemberRemoved: {
+ who: 'AccountId32',
+ rank: 'u16',
+ },
+ Voted: {
+ who: 'AccountId32',
+ poll: 'u32',
+ vote: 'PalletRankedCollectiveVoteRecord',
+ tally: 'PalletRankedCollectiveTally'
+ }
+ }
+ },
+ /**
+ * Lookup83: pallet_ranked_collective::VoteRecord
+ **/
+ PalletRankedCollectiveVoteRecord: {
+ _enum: {
+ Aye: 'u32',
+ Nay: 'u32'
+ }
+ },
+ /**
+ * Lookup84: pallet_ranked_collective::Tally<T, I, M>
+ **/
+ PalletRankedCollectiveTally: {
+ bareAyes: 'u32',
+ ayes: 'u32',
+ nays: 'u32'
+ },
+ /**
+ * Lookup85: pallet_referenda::pallet::Event<T, I>
+ **/
+ PalletReferendaEvent: {
+ _enum: {
+ Submitted: {
+ index: 'u32',
+ track: 'u16',
+ proposal: 'FrameSupportPreimagesBounded',
+ },
+ DecisionDepositPlaced: {
+ index: 'u32',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ DecisionDepositRefunded: {
+ index: 'u32',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ DepositSlashed: {
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ DecisionStarted: {
+ index: 'u32',
+ track: 'u16',
+ proposal: 'FrameSupportPreimagesBounded',
+ tally: 'PalletRankedCollectiveTally',
+ },
+ ConfirmStarted: {
+ index: 'u32',
+ },
+ ConfirmAborted: {
+ index: 'u32',
+ },
+ Confirmed: {
+ index: 'u32',
+ tally: 'PalletRankedCollectiveTally',
+ },
+ Approved: {
+ index: 'u32',
+ },
+ Rejected: {
+ index: 'u32',
+ tally: 'PalletRankedCollectiveTally',
+ },
+ TimedOut: {
+ index: 'u32',
+ tally: 'PalletRankedCollectiveTally',
+ },
+ Cancelled: {
+ index: 'u32',
+ tally: 'PalletRankedCollectiveTally',
+ },
+ Killed: {
+ index: 'u32',
+ tally: 'PalletRankedCollectiveTally',
+ },
+ SubmissionDepositRefunded: {
+ index: 'u32',
+ who: 'AccountId32',
+ amount: 'u128',
+ },
+ MetadataSet: {
+ _alias: {
+ hash_: 'hash',
+ },
+ index: 'u32',
+ hash_: 'H256',
+ },
+ MetadataCleared: {
+ _alias: {
+ hash_: 'hash',
+ },
+ index: 'u32',
+ hash_: 'H256'
+ }
+ }
+ },
+ /**
+ * Lookup86: frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>
+ **/
+ FrameSupportPreimagesBounded: {
+ _enum: {
+ Legacy: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ },
+ Inline: 'Bytes',
+ Lookup: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ len: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup88: frame_system::pallet::Call<T>
+ **/
+ FrameSystemCall: {
+ _enum: {
+ remark: {
+ remark: 'Bytes',
+ },
+ set_heap_pages: {
+ pages: 'u64',
+ },
+ set_code: {
+ code: 'Bytes',
+ },
+ set_code_without_checks: {
+ code: 'Bytes',
+ },
+ set_storage: {
+ items: 'Vec<(Bytes,Bytes)>',
+ },
+ kill_storage: {
+ _alias: {
+ keys_: 'keys',
+ },
+ keys_: 'Vec<Bytes>',
+ },
+ kill_prefix: {
+ prefix: 'Bytes',
+ subkeys: 'u32',
+ },
+ remark_with_event: {
+ remark: 'Bytes'
+ }
+ }
+ },
+ /**
+ * Lookup92: pallet_state_trie_migration::pallet::Call<T>
+ **/
+ PalletStateTrieMigrationCall: {
+ _enum: {
+ control_auto_migration: {
+ maybeConfig: 'Option<PalletStateTrieMigrationMigrationLimits>',
+ },
+ continue_migrate: {
+ limits: 'PalletStateTrieMigrationMigrationLimits',
+ realSizeUpper: 'u32',
+ witnessTask: 'PalletStateTrieMigrationMigrationTask',
+ },
+ migrate_custom_top: {
+ _alias: {
+ keys_: 'keys',
+ },
+ keys_: 'Vec<Bytes>',
+ witnessSize: 'u32',
+ },
+ migrate_custom_child: {
+ root: 'Bytes',
+ childKeys: 'Vec<Bytes>',
+ totalSize: 'u32',
+ },
+ set_signed_max_limits: {
+ limits: 'PalletStateTrieMigrationMigrationLimits',
+ },
+ force_set_progress: {
+ progressTop: 'PalletStateTrieMigrationProgress',
+ progressChild: 'PalletStateTrieMigrationProgress'
+ }
+ }
+ },
+ /**
+ * Lookup94: pallet_state_trie_migration::pallet::MigrationLimits
+ **/
+ PalletStateTrieMigrationMigrationLimits: {
+ _alias: {
+ size_: 'size'
+ },
+ size_: 'u32',
+ item: 'u32'
+ },
+ /**
+ * Lookup95: pallet_state_trie_migration::pallet::MigrationTask<T>
+ **/
+ PalletStateTrieMigrationMigrationTask: {
+ _alias: {
+ size_: 'size'
+ },
+ progressTop: 'PalletStateTrieMigrationProgress',
+ progressChild: 'PalletStateTrieMigrationProgress',
+ size_: 'u32',
+ topItems: 'u32',
+ childItems: 'u32'
+ },
+ /**
+ * Lookup96: pallet_state_trie_migration::pallet::Progress<MaxKeyLen>
+ **/
+ PalletStateTrieMigrationProgress: {
+ _enum: {
+ ToStart: 'Null',
+ LastKey: 'Bytes',
+ Complete: 'Null'
+ }
+ },
+ /**
+ * Lookup98: cumulus_pallet_parachain_system::pallet::Call<T>
+ **/
+ CumulusPalletParachainSystemCall: {
+ _enum: {
+ set_validation_data: {
+ data: 'CumulusPrimitivesParachainInherentParachainInherentData',
+ },
+ sudo_send_upward_message: {
+ message: 'Bytes',
+ },
+ authorize_upgrade: {
+ codeHash: 'H256',
+ checkVersion: 'bool',
+ },
+ enact_authorized_upgrade: {
+ code: 'Bytes'
+ }
+ }
+ },
+ /**
+ * Lookup99: cumulus_primitives_parachain_inherent::ParachainInherentData
+ **/
+ CumulusPrimitivesParachainInherentParachainInherentData: {
+ validationData: 'PolkadotPrimitivesV5PersistedValidationData',
+ relayChainState: 'SpTrieStorageProof',
+ downwardMessages: 'Vec<PolkadotCorePrimitivesInboundDownwardMessage>',
+ horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'
+ },
+ /**
+ * Lookup100: polkadot_primitives::v5::PersistedValidationData<primitive_types::H256, N>
+ **/
+ PolkadotPrimitivesV5PersistedValidationData: {
+ parentHead: 'Bytes',
+ relayParentNumber: 'u32',
+ relayParentStorageRoot: 'H256',
+ maxPovSize: 'u32'
+ },
+ /**
+ * Lookup102: sp_trie::storage_proof::StorageProof
+ **/
+ SpTrieStorageProof: {
+ trieNodes: 'BTreeSet<Bytes>'
+ },
+ /**
+ * Lookup105: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
+ **/
+ PolkadotCorePrimitivesInboundDownwardMessage: {
+ sentAt: 'u32',
+ msg: 'Bytes'
+ },
+ /**
+ * Lookup109: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
+ **/
+ PolkadotCorePrimitivesInboundHrmpMessage: {
+ sentAt: 'u32',
+ data: 'Bytes'
+ },
+ /**
+ * Lookup112: parachain_info::pallet::Call<T>
+ **/
+ ParachainInfoCall: 'Null',
+ /**
+ * Lookup113: pallet_collator_selection::pallet::Call<T>
+ **/
+ PalletCollatorSelectionCall: {
+ _enum: {
+ add_invulnerable: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'AccountId32',
+ },
+ remove_invulnerable: {
+ who: 'AccountId32',
+ },
+ get_license: 'Null',
+ onboard: 'Null',
+ offboard: 'Null',
+ release_license: 'Null',
+ force_release_license: {
+ who: 'AccountId32'
+ }
+ }
+ },
+ /**
+ * Lookup114: pallet_session::pallet::Call<T>
+ **/
+ PalletSessionCall: {
+ _enum: {
+ set_keys: {
+ _alias: {
+ keys_: 'keys',
+ },
+ keys_: 'OpalRuntimeRuntimeCommonSessionKeys',
+ proof: 'Bytes',
+ },
+ purge_keys: 'Null'
+ }
+ },
+ /**
+ * Lookup115: opal_runtime::runtime_common::SessionKeys
+ **/
+ OpalRuntimeRuntimeCommonSessionKeys: {
+ aura: 'SpConsensusAuraSr25519AppSr25519Public'
+ },
+ /**
+ * Lookup116: sp_consensus_aura::sr25519::app_sr25519::Public
+ **/
+ SpConsensusAuraSr25519AppSr25519Public: 'SpCoreSr25519Public',
+ /**
+ * Lookup117: sp_core::sr25519::Public
+ **/
+ SpCoreSr25519Public: '[u8;32]',
+ /**
+ * Lookup118: pallet_balances::pallet::Call<T, I>
+ **/
+ PalletBalancesCall: {
+ _enum: {
+ transfer_allow_death: {
+ dest: 'MultiAddress',
+ value: 'Compact<u128>',
+ },
+ set_balance_deprecated: {
+ who: 'MultiAddress',
+ newFree: 'Compact<u128>',
+ oldReserved: 'Compact<u128>',
+ },
+ force_transfer: {
+ source: 'MultiAddress',
+ dest: 'MultiAddress',
+ value: 'Compact<u128>',
+ },
+ transfer_keep_alive: {
+ dest: 'MultiAddress',
+ value: 'Compact<u128>',
+ },
+ transfer_all: {
+ dest: 'MultiAddress',
+ keepAlive: 'bool',
+ },
+ force_unreserve: {
+ who: 'MultiAddress',
+ amount: 'u128',
+ },
+ upgrade_accounts: {
+ who: 'Vec<AccountId32>',
+ },
+ transfer: {
+ dest: 'MultiAddress',
+ value: 'Compact<u128>',
+ },
+ force_set_balance: {
+ who: 'MultiAddress',
+ newFree: 'Compact<u128>'
+ }
+ }
+ },
+ /**
+ * Lookup122: pallet_timestamp::pallet::Call<T>
+ **/
+ PalletTimestampCall: {
+ _enum: {
+ set: {
+ now: 'Compact<u64>'
+ }
+ }
+ },
+ /**
+ * Lookup123: pallet_treasury::pallet::Call<T, I>
+ **/
+ PalletTreasuryCall: {
+ _enum: {
+ propose_spend: {
+ value: 'Compact<u128>',
+ beneficiary: 'MultiAddress',
+ },
+ reject_proposal: {
+ proposalId: 'Compact<u32>',
+ },
+ approve_proposal: {
+ proposalId: 'Compact<u32>',
+ },
+ spend: {
+ amount: 'Compact<u128>',
+ beneficiary: 'MultiAddress',
+ },
+ remove_approval: {
+ proposalId: 'Compact<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup124: pallet_sudo::pallet::Call<T>
+ **/
+ PalletSudoCall: {
+ _enum: {
+ sudo: {
+ call: 'Call',
+ },
+ sudo_unchecked_weight: {
+ call: 'Call',
+ weight: 'SpWeightsWeightV2Weight',
+ },
+ set_key: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'MultiAddress',
+ },
+ sudo_as: {
+ who: 'MultiAddress',
+ call: 'Call'
+ }
+ }
+ },
+ /**
+ * Lookup125: orml_vesting::module::Call<T>
+ **/
+ OrmlVestingModuleCall: {
+ _enum: {
+ claim: 'Null',
+ vested_transfer: {
+ dest: 'MultiAddress',
+ schedule: 'OrmlVestingVestingSchedule',
+ },
+ update_vesting_schedules: {
+ who: 'MultiAddress',
+ vestingSchedules: 'Vec<OrmlVestingVestingSchedule>',
+ },
+ claim_for: {
+ dest: 'MultiAddress'
+ }
+ }
+ },
+ /**
+ * Lookup127: orml_xtokens::module::Call<T>
+ **/
+ OrmlXtokensModuleCall: {
+ _enum: {
+ transfer: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'u128',
+ dest: 'StagingXcmVersionedMultiLocation',
+ destWeightLimit: 'StagingXcmV3WeightLimit',
+ },
+ transfer_multiasset: {
+ asset: 'StagingXcmVersionedMultiAsset',
+ dest: 'StagingXcmVersionedMultiLocation',
+ destWeightLimit: 'StagingXcmV3WeightLimit',
+ },
+ transfer_with_fee: {
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'u128',
+ fee: 'u128',
+ dest: 'StagingXcmVersionedMultiLocation',
+ destWeightLimit: 'StagingXcmV3WeightLimit',
+ },
+ transfer_multiasset_with_fee: {
+ asset: 'StagingXcmVersionedMultiAsset',
+ fee: 'StagingXcmVersionedMultiAsset',
+ dest: 'StagingXcmVersionedMultiLocation',
+ destWeightLimit: 'StagingXcmV3WeightLimit',
+ },
+ transfer_multicurrencies: {
+ currencies: 'Vec<(PalletForeignAssetsAssetId,u128)>',
+ feeItem: 'u32',
+ dest: 'StagingXcmVersionedMultiLocation',
+ destWeightLimit: 'StagingXcmV3WeightLimit',
+ },
+ transfer_multiassets: {
+ assets: 'StagingXcmVersionedMultiAssets',
+ feeItem: 'u32',
+ dest: 'StagingXcmVersionedMultiLocation',
+ destWeightLimit: 'StagingXcmV3WeightLimit'
+ }
+ }
+ },
+ /**
+ * Lookup128: staging_xcm::VersionedMultiLocation
+ **/
+ StagingXcmVersionedMultiLocation: {
+ _enum: {
+ __Unused0: 'Null',
+ V2: 'StagingXcmV2MultiLocation',
+ __Unused2: 'Null',
+ V3: 'StagingXcmV3MultiLocation'
+ }
+ },
+ /**
+ * Lookup129: staging_xcm::v2::multilocation::MultiLocation
+ **/
+ StagingXcmV2MultiLocation: {
+ parents: 'u8',
+ interior: 'StagingXcmV2MultilocationJunctions'
+ },
+ /**
+ * Lookup130: staging_xcm::v2::multilocation::Junctions
+ **/
+ StagingXcmV2MultilocationJunctions: {
+ _enum: {
+ Here: 'Null',
+ X1: 'StagingXcmV2Junction',
+ X2: '(StagingXcmV2Junction,StagingXcmV2Junction)',
+ X3: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
+ X4: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
+ X5: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
+ X6: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
+ X7: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
+ X8: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)'
+ }
+ },
+ /**
+ * Lookup131: staging_xcm::v2::junction::Junction
+ **/
+ StagingXcmV2Junction: {
+ _enum: {
+ Parachain: 'Compact<u32>',
+ AccountId32: {
+ network: 'StagingXcmV2NetworkId',
+ id: '[u8;32]',
+ },
+ AccountIndex64: {
+ network: 'StagingXcmV2NetworkId',
+ index: 'Compact<u64>',
+ },
+ AccountKey20: {
+ network: 'StagingXcmV2NetworkId',
+ key: '[u8;20]',
+ },
+ PalletInstance: 'u8',
+ GeneralIndex: 'Compact<u128>',
+ GeneralKey: 'Bytes',
+ OnlyChild: 'Null',
+ Plurality: {
+ id: 'StagingXcmV2BodyId',
+ part: 'StagingXcmV2BodyPart'
+ }
+ }
+ },
+ /**
+ * Lookup132: staging_xcm::v2::NetworkId
+ **/
+ StagingXcmV2NetworkId: {
+ _enum: {
+ Any: 'Null',
+ Named: 'Bytes',
+ Polkadot: 'Null',
+ Kusama: 'Null'
+ }
+ },
+ /**
+ * Lookup134: staging_xcm::v2::BodyId
+ **/
+ StagingXcmV2BodyId: {
+ _enum: {
+ Unit: 'Null',
+ Named: 'Bytes',
+ Index: 'Compact<u32>',
+ Executive: 'Null',
+ Technical: 'Null',
+ Legislative: 'Null',
+ Judicial: 'Null',
+ Defense: 'Null',
+ Administration: 'Null',
+ Treasury: 'Null'
+ }
+ },
+ /**
+ * Lookup135: staging_xcm::v2::BodyPart
+ **/
+ StagingXcmV2BodyPart: {
+ _enum: {
+ Voice: 'Null',
+ Members: {
+ count: 'Compact<u32>',
+ },
+ Fraction: {
+ nom: 'Compact<u32>',
+ denom: 'Compact<u32>',
+ },
+ AtLeastProportion: {
+ nom: 'Compact<u32>',
+ denom: 'Compact<u32>',
+ },
+ MoreThanProportion: {
+ nom: 'Compact<u32>',
+ denom: 'Compact<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup136: staging_xcm::v3::WeightLimit
+ **/
+ StagingXcmV3WeightLimit: {
+ _enum: {
+ Unlimited: 'Null',
+ Limited: 'SpWeightsWeightV2Weight'
+ }
+ },
+ /**
+ * Lookup137: staging_xcm::VersionedMultiAsset
+ **/
+ StagingXcmVersionedMultiAsset: {
+ _enum: {
+ __Unused0: 'Null',
+ V2: 'StagingXcmV2MultiAsset',
+ __Unused2: 'Null',
+ V3: 'StagingXcmV3MultiAsset'
+ }
+ },
+ /**
+ * Lookup138: staging_xcm::v2::multiasset::MultiAsset
+ **/
+ StagingXcmV2MultiAsset: {
+ id: 'StagingXcmV2MultiassetAssetId',
+ fun: 'StagingXcmV2MultiassetFungibility'
+ },
+ /**
+ * Lookup139: staging_xcm::v2::multiasset::AssetId
+ **/
+ StagingXcmV2MultiassetAssetId: {
+ _enum: {
+ Concrete: 'StagingXcmV2MultiLocation',
+ Abstract: 'Bytes'
+ }
+ },
+ /**
+ * Lookup140: staging_xcm::v2::multiasset::Fungibility
+ **/
+ StagingXcmV2MultiassetFungibility: {
+ _enum: {
+ Fungible: 'Compact<u128>',
+ NonFungible: 'StagingXcmV2MultiassetAssetInstance'
+ }
+ },
+ /**
+ * Lookup141: staging_xcm::v2::multiasset::AssetInstance
+ **/
+ StagingXcmV2MultiassetAssetInstance: {
+ _enum: {
+ Undefined: 'Null',
+ Index: 'Compact<u128>',
+ Array4: '[u8;4]',
+ Array8: '[u8;8]',
+ Array16: '[u8;16]',
+ Array32: '[u8;32]',
+ Blob: 'Bytes'
+ }
+ },
+ /**
+ * Lookup144: staging_xcm::VersionedMultiAssets
+ **/
+ StagingXcmVersionedMultiAssets: {
+ _enum: {
+ __Unused0: 'Null',
+ V2: 'StagingXcmV2MultiassetMultiAssets',
+ __Unused2: 'Null',
+ V3: 'StagingXcmV3MultiassetMultiAssets'
+ }
+ },
+ /**
+ * Lookup145: staging_xcm::v2::multiasset::MultiAssets
+ **/
+ StagingXcmV2MultiassetMultiAssets: 'Vec<StagingXcmV2MultiAsset>',
+ /**
+ * Lookup147: orml_tokens::module::Call<T>
+ **/
+ OrmlTokensModuleCall: {
+ _enum: {
+ transfer: {
+ dest: 'MultiAddress',
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'Compact<u128>',
+ },
+ transfer_all: {
+ dest: 'MultiAddress',
+ currencyId: 'PalletForeignAssetsAssetId',
+ keepAlive: 'bool',
+ },
+ transfer_keep_alive: {
+ dest: 'MultiAddress',
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'Compact<u128>',
+ },
+ force_transfer: {
+ source: 'MultiAddress',
+ dest: 'MultiAddress',
+ currencyId: 'PalletForeignAssetsAssetId',
+ amount: 'Compact<u128>',
+ },
+ set_balance: {
+ who: 'MultiAddress',
+ currencyId: 'PalletForeignAssetsAssetId',
+ newFree: 'Compact<u128>',
+ newReserved: 'Compact<u128>'
+ }
+ }
+ },
+ /**
+ * Lookup148: pallet_identity::pallet::Call<T>
+ **/
+ PalletIdentityCall: {
+ _enum: {
+ add_registrar: {
+ account: 'MultiAddress',
+ },
+ set_identity: {
+ info: 'PalletIdentityIdentityInfo',
+ },
+ set_subs: {
+ subs: 'Vec<(AccountId32,Data)>',
+ },
+ clear_identity: 'Null',
+ request_judgement: {
+ regIndex: 'Compact<u32>',
+ maxFee: 'Compact<u128>',
+ },
+ cancel_request: {
+ regIndex: 'u32',
+ },
+ set_fee: {
+ index: 'Compact<u32>',
+ fee: 'Compact<u128>',
+ },
+ set_account_id: {
+ _alias: {
+ new_: 'new',
+ },
+ index: 'Compact<u32>',
+ new_: 'MultiAddress',
+ },
+ set_fields: {
+ index: 'Compact<u32>',
+ fields: 'PalletIdentityBitFlags',
+ },
+ provide_judgement: {
+ regIndex: 'Compact<u32>',
+ target: 'MultiAddress',
+ judgement: 'PalletIdentityJudgement',
+ identity: 'H256',
+ },
+ kill_identity: {
+ target: 'MultiAddress',
+ },
+ add_sub: {
+ sub: 'MultiAddress',
+ data: 'Data',
+ },
+ rename_sub: {
+ sub: 'MultiAddress',
+ data: 'Data',
+ },
+ remove_sub: {
+ sub: 'MultiAddress',
+ },
+ quit_sub: 'Null',
+ force_insert_identities: {
+ identities: 'Vec<(AccountId32,PalletIdentityRegistration)>',
+ },
+ force_remove_identities: {
+ identities: 'Vec<AccountId32>',
+ },
+ force_set_subs: {
+ subs: 'Vec<(AccountId32,(u128,Vec<(AccountId32,Data)>))>'
+ }
+ }
+ },
+ /**
+ * Lookup149: pallet_identity::types::IdentityInfo<FieldLimit>
+ **/
+ PalletIdentityIdentityInfo: {
+ additional: 'Vec<(Data,Data)>',
+ display: 'Data',
+ legal: 'Data',
+ web: 'Data',
+ riot: 'Data',
+ email: 'Data',
+ pgpFingerprint: 'Option<[u8;20]>',
+ image: 'Data',
+ twitter: 'Data'
+ },
+ /**
+ * Lookup185: pallet_identity::types::BitFlags<pallet_identity::types::IdentityField>
+ **/
+ PalletIdentityBitFlags: {
+ _bitLength: 64,
+ Display: 1,
+ Legal: 2,
+ Web: 4,
+ Riot: 8,
+ Email: 16,
+ PgpFingerprint: 32,
+ Image: 64,
+ Twitter: 128
+ },
+ /**
+ * Lookup186: pallet_identity::types::IdentityField
+ **/
+ PalletIdentityIdentityField: {
+ _enum: ['__Unused0', 'Display', 'Legal', '__Unused3', 'Web', '__Unused5', '__Unused6', '__Unused7', 'Riot', '__Unused9', '__Unused10', '__Unused11', '__Unused12', '__Unused13', '__Unused14', '__Unused15', 'Email', '__Unused17', '__Unused18', '__Unused19', '__Unused20', '__Unused21', '__Unused22', '__Unused23', '__Unused24', '__Unused25', '__Unused26', '__Unused27', '__Unused28', '__Unused29', '__Unused30', '__Unused31', 'PgpFingerprint', '__Unused33', '__Unused34', '__Unused35', '__Unused36', '__Unused37', '__Unused38', '__Unused39', '__Unused40', '__Unused41', '__Unused42', '__Unused43', '__Unused44', '__Unused45', '__Unused46', '__Unused47', '__Unused48', '__Unused49', '__Unused50', '__Unused51', '__Unused52', '__Unused53', '__Unused54', '__Unused55', '__Unused56', '__Unused57', '__Unused58', '__Unused59', '__Unused60', '__Unused61', '__Unused62', '__Unused63', 'Image', '__Unused65', '__Unused66', '__Unused67', '__Unused68', '__Unused69', '__Unused70', '__Unused71', '__Unused72', '__Unused73', '__Unused74', '__Unused75', '__Unused76', '__Unused77', '__Unused78', '__Unused79', '__Unused80', '__Unused81', '__Unused82', '__Unused83', '__Unused84', '__Unused85', '__Unused86', '__Unused87', '__Unused88', '__Unused89', '__Unused90', '__Unused91', '__Unused92', '__Unused93', '__Unused94', '__Unused95', '__Unused96', '__Unused97', '__Unused98', '__Unused99', '__Unused100', '__Unused101', '__Unused102', '__Unused103', '__Unused104', '__Unused105', '__Unused106', '__Unused107', '__Unused108', '__Unused109', '__Unused110', '__Unused111', '__Unused112', '__Unused113', '__Unused114', '__Unused115', '__Unused116', '__Unused117', '__Unused118', '__Unused119', '__Unused120', '__Unused121', '__Unused122', '__Unused123', '__Unused124', '__Unused125', '__Unused126', '__Unused127', 'Twitter']
+ },
+ /**
+ * Lookup187: pallet_identity::types::Judgement<Balance>
+ **/
+ PalletIdentityJudgement: {
+ _enum: {
+ Unknown: 'Null',
+ FeePaid: 'u128',
+ Reasonable: 'Null',
+ KnownGood: 'Null',
+ OutOfDate: 'Null',
+ LowQuality: 'Null',
+ Erroneous: 'Null'
+ }
+ },
+ /**
+ * Lookup190: pallet_identity::types::Registration<Balance, MaxJudgements, MaxAdditionalFields>
+ **/
+ PalletIdentityRegistration: {
+ judgements: 'Vec<(u32,PalletIdentityJudgement)>',
+ deposit: 'u128',
+ info: 'PalletIdentityIdentityInfo'
+ },
+ /**
+ * Lookup198: pallet_preimage::pallet::Call<T>
+ **/
+ PalletPreimageCall: {
+ _enum: {
+ note_preimage: {
+ bytes: 'Bytes',
+ },
+ unnote_preimage: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ },
+ request_preimage: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ },
+ unrequest_preimage: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256'
+ }
+ }
+ },
+ /**
+ * Lookup199: pallet_democracy::pallet::Call<T>
+ **/
+ PalletDemocracyCall: {
+ _enum: {
+ propose: {
+ proposal: 'FrameSupportPreimagesBounded',
+ value: 'Compact<u128>',
+ },
+ second: {
+ proposal: 'Compact<u32>',
+ },
+ vote: {
+ refIndex: 'Compact<u32>',
+ vote: 'PalletDemocracyVoteAccountVote',
+ },
+ emergency_cancel: {
+ refIndex: 'u32',
+ },
+ external_propose: {
+ proposal: 'FrameSupportPreimagesBounded',
+ },
+ external_propose_majority: {
+ proposal: 'FrameSupportPreimagesBounded',
+ },
+ external_propose_default: {
+ proposal: 'FrameSupportPreimagesBounded',
+ },
+ fast_track: {
+ proposalHash: 'H256',
+ votingPeriod: 'u32',
+ delay: 'u32',
+ },
+ veto_external: {
+ proposalHash: 'H256',
+ },
+ cancel_referendum: {
+ refIndex: 'Compact<u32>',
+ },
+ delegate: {
+ to: 'MultiAddress',
+ conviction: 'PalletDemocracyConviction',
+ balance: 'u128',
+ },
+ undelegate: 'Null',
+ clear_public_proposals: 'Null',
+ unlock: {
+ target: 'MultiAddress',
+ },
+ remove_vote: {
+ index: 'u32',
+ },
+ remove_other_vote: {
+ target: 'MultiAddress',
+ index: 'u32',
+ },
+ blacklist: {
+ proposalHash: 'H256',
+ maybeRefIndex: 'Option<u32>',
+ },
+ cancel_proposal: {
+ propIndex: 'Compact<u32>',
+ },
+ set_metadata: {
+ owner: 'PalletDemocracyMetadataOwner',
+ maybeHash: 'Option<H256>'
+ }
+ }
+ },
+ /**
+ * Lookup200: pallet_democracy::conviction::Conviction
+ **/
+ PalletDemocracyConviction: {
+ _enum: ['None', 'Locked1x', 'Locked2x', 'Locked3x', 'Locked4x', 'Locked5x', 'Locked6x']
+ },
+ /**
+ * Lookup203: pallet_collective::pallet::Call<T, I>
+ **/
+ PalletCollectiveCall: {
+ _enum: {
+ set_members: {
+ newMembers: 'Vec<AccountId32>',
+ prime: 'Option<AccountId32>',
+ oldCount: 'u32',
+ },
+ execute: {
+ proposal: 'Call',
+ lengthBound: 'Compact<u32>',
+ },
+ propose: {
+ threshold: 'Compact<u32>',
+ proposal: 'Call',
+ lengthBound: 'Compact<u32>',
+ },
+ vote: {
+ proposal: 'H256',
+ index: 'Compact<u32>',
+ approve: 'bool',
+ },
+ __Unused4: 'Null',
+ disapprove_proposal: {
+ proposalHash: 'H256',
+ },
+ close: {
+ proposalHash: 'H256',
+ index: 'Compact<u32>',
+ proposalWeightBound: 'SpWeightsWeightV2Weight',
+ lengthBound: 'Compact<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup205: pallet_membership::pallet::Call<T, I>
+ **/
+ PalletMembershipCall: {
+ _enum: {
+ add_member: {
+ who: 'MultiAddress',
+ },
+ remove_member: {
+ who: 'MultiAddress',
+ },
+ swap_member: {
+ remove: 'MultiAddress',
+ add: 'MultiAddress',
+ },
+ reset_members: {
+ members: 'Vec<AccountId32>',
+ },
+ change_key: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'MultiAddress',
+ },
+ set_prime: {
+ who: 'MultiAddress',
+ },
+ clear_prime: 'Null'
+ }
+ },
+ /**
+ * Lookup207: pallet_ranked_collective::pallet::Call<T, I>
+ **/
+ PalletRankedCollectiveCall: {
+ _enum: {
+ add_member: {
+ who: 'MultiAddress',
+ },
+ promote_member: {
+ who: 'MultiAddress',
+ },
+ demote_member: {
+ who: 'MultiAddress',
+ },
+ remove_member: {
+ who: 'MultiAddress',
+ minRank: 'u16',
+ },
+ vote: {
+ poll: 'u32',
+ aye: 'bool',
+ },
+ cleanup_poll: {
+ pollIndex: 'u32',
+ max: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup208: pallet_referenda::pallet::Call<T, I>
+ **/
+ PalletReferendaCall: {
+ _enum: {
+ submit: {
+ proposalOrigin: 'OpalRuntimeOriginCaller',
+ proposal: 'FrameSupportPreimagesBounded',
+ enactmentMoment: 'FrameSupportScheduleDispatchTime',
+ },
+ place_decision_deposit: {
+ index: 'u32',
+ },
+ refund_decision_deposit: {
+ index: 'u32',
+ },
+ cancel: {
+ index: 'u32',
+ },
+ kill: {
+ index: 'u32',
+ },
+ nudge_referendum: {
+ index: 'u32',
+ },
+ one_fewer_deciding: {
+ track: 'u16',
+ },
+ refund_submission_deposit: {
+ index: 'u32',
+ },
+ set_metadata: {
+ index: 'u32',
+ maybeHash: 'Option<H256>'
+ }
+ }
+ },
+ /**
+ * Lookup209: opal_runtime::OriginCaller
+ **/
+ OpalRuntimeOriginCaller: {
+ _enum: {
+ system: 'FrameSupportDispatchRawOrigin',
+ __Unused1: 'Null',
+ __Unused2: 'Null',
+ __Unused3: 'Null',
+ __Unused4: 'Null',
+ __Unused5: 'Null',
+ __Unused6: 'Null',
+ Void: 'SpCoreVoid',
+ __Unused8: 'Null',
+ __Unused9: 'Null',
+ __Unused10: 'Null',
+ __Unused11: 'Null',
+ __Unused12: 'Null',
+ __Unused13: 'Null',
+ __Unused14: 'Null',
+ __Unused15: 'Null',
+ __Unused16: 'Null',
+ __Unused17: 'Null',
+ __Unused18: 'Null',
+ __Unused19: 'Null',
+ __Unused20: 'Null',
+ __Unused21: 'Null',
+ __Unused22: 'Null',
+ __Unused23: 'Null',
+ __Unused24: 'Null',
+ __Unused25: 'Null',
+ __Unused26: 'Null',
+ __Unused27: 'Null',
+ __Unused28: 'Null',
+ __Unused29: 'Null',
+ __Unused30: 'Null',
+ __Unused31: 'Null',
+ __Unused32: 'Null',
+ __Unused33: 'Null',
+ __Unused34: 'Null',
+ __Unused35: 'Null',
+ __Unused36: 'Null',
+ __Unused37: 'Null',
+ __Unused38: 'Null',
+ __Unused39: 'Null',
+ __Unused40: 'Null',
+ __Unused41: 'Null',
+ __Unused42: 'Null',
+ Council: 'PalletCollectiveRawOrigin',
+ TechnicalCommittee: 'PalletCollectiveRawOrigin',
+ __Unused45: 'Null',
+ __Unused46: 'Null',
+ __Unused47: 'Null',
+ __Unused48: 'Null',
+ __Unused49: 'Null',
+ __Unused50: 'Null',
+ PolkadotXcm: 'PalletXcmOrigin',
+ CumulusXcm: 'CumulusPalletXcmOrigin',
+ __Unused53: 'Null',
+ __Unused54: 'Null',
+ __Unused55: 'Null',
+ __Unused56: 'Null',
+ __Unused57: 'Null',
+ __Unused58: 'Null',
+ __Unused59: 'Null',
+ __Unused60: 'Null',
+ __Unused61: 'Null',
+ __Unused62: 'Null',
+ __Unused63: 'Null',
+ __Unused64: 'Null',
+ __Unused65: 'Null',
+ __Unused66: 'Null',
+ __Unused67: 'Null',
+ __Unused68: 'Null',
+ __Unused69: 'Null',
+ __Unused70: 'Null',
+ __Unused71: 'Null',
+ __Unused72: 'Null',
+ __Unused73: 'Null',
+ __Unused74: 'Null',
+ __Unused75: 'Null',
+ __Unused76: 'Null',
+ __Unused77: 'Null',
+ __Unused78: 'Null',
+ __Unused79: 'Null',
+ __Unused80: 'Null',
+ __Unused81: 'Null',
+ __Unused82: 'Null',
+ __Unused83: 'Null',
+ __Unused84: 'Null',
+ __Unused85: 'Null',
+ __Unused86: 'Null',
+ __Unused87: 'Null',
+ __Unused88: 'Null',
+ __Unused89: 'Null',
+ __Unused90: 'Null',
+ __Unused91: 'Null',
+ __Unused92: 'Null',
+ __Unused93: 'Null',
+ __Unused94: 'Null',
+ __Unused95: 'Null',
+ __Unused96: 'Null',
+ __Unused97: 'Null',
+ __Unused98: 'Null',
+ Origins: 'PalletGovOriginsOrigin',
+ __Unused100: 'Null',
+ Ethereum: 'PalletEthereumRawOrigin'
+ }
+ },
+ /**
+ * Lookup210: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
+ **/
+ FrameSupportDispatchRawOrigin: {
+ _enum: {
+ Root: 'Null',
+ Signed: 'AccountId32',
+ None: 'Null'
+ }
+ },
+ /**
+ * Lookup211: pallet_collective::RawOrigin<sp_core::crypto::AccountId32, I>
+ **/
+ PalletCollectiveRawOrigin: {
+ _enum: {
+ Members: '(u32,u32)',
+ Member: 'AccountId32',
+ _Phantom: 'Null'
+ }
+ },
+ /**
+ * Lookup213: pallet_gov_origins::pallet::Origin
+ **/
+ PalletGovOriginsOrigin: {
+ _enum: ['FellowshipProposition']
+ },
+ /**
+ * Lookup214: pallet_xcm::pallet::Origin
+ **/
+ PalletXcmOrigin: {
+ _enum: {
+ Xcm: 'StagingXcmV3MultiLocation',
+ Response: 'StagingXcmV3MultiLocation'
+ }
+ },
+ /**
+ * Lookup215: cumulus_pallet_xcm::pallet::Origin
+ **/
+ CumulusPalletXcmOrigin: {
+ _enum: {
+ Relay: 'Null',
+ SiblingParachain: 'u32'
+ }
+ },
+ /**
+ * Lookup216: pallet_ethereum::RawOrigin
+ **/
+ PalletEthereumRawOrigin: {
+ _enum: {
+ EthereumTransaction: 'H160'
+ }
+ },
+ /**
+ * Lookup218: sp_core::Void
+ **/
+ SpCoreVoid: 'Null',
+ /**
+ * Lookup219: frame_support::traits::schedule::DispatchTime<BlockNumber>
+ **/
+ FrameSupportScheduleDispatchTime: {
+ _enum: {
+ At: 'u32',
+ After: 'u32'
+ }
+ },
+ /**
+ * Lookup220: pallet_scheduler::pallet::Call<T>
+ **/
+ PalletSchedulerCall: {
+ _enum: {
+ schedule: {
+ when: 'u32',
+ maybePeriodic: 'Option<(u32,u32)>',
+ priority: 'u8',
+ call: 'Call',
+ },
+ cancel: {
+ when: 'u32',
+ index: 'u32',
+ },
+ schedule_named: {
+ id: '[u8;32]',
+ when: 'u32',
+ maybePeriodic: 'Option<(u32,u32)>',
+ priority: 'u8',
+ call: 'Call',
+ },
+ cancel_named: {
+ id: '[u8;32]',
+ },
+ schedule_after: {
+ after: 'u32',
+ maybePeriodic: 'Option<(u32,u32)>',
+ priority: 'u8',
+ call: 'Call',
+ },
+ schedule_named_after: {
+ id: '[u8;32]',
+ after: 'u32',
+ maybePeriodic: 'Option<(u32,u32)>',
+ priority: 'u8',
+ call: 'Call'
+ }
+ }
+ },
+ /**
+ * Lookup223: cumulus_pallet_xcmp_queue::pallet::Call<T>
+ **/
+ CumulusPalletXcmpQueueCall: {
+ _enum: {
+ service_overweight: {
+ index: 'u64',
+ weightLimit: 'SpWeightsWeightV2Weight',
+ },
+ suspend_xcm_execution: 'Null',
+ resume_xcm_execution: 'Null',
+ update_suspend_threshold: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'u32',
+ },
+ update_drop_threshold: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'u32',
+ },
+ update_resume_threshold: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'u32',
+ },
+ update_threshold_weight: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'SpWeightsWeightV2Weight',
+ },
+ update_weight_restrict_decay: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'SpWeightsWeightV2Weight',
+ },
+ update_xcmp_max_individual_weight: {
+ _alias: {
+ new_: 'new',
+ },
+ new_: 'SpWeightsWeightV2Weight'
+ }
+ }
+ },
+ /**
+ * Lookup224: pallet_xcm::pallet::Call<T>
+ **/
+ PalletXcmCall: {
+ _enum: {
+ send: {
+ dest: 'StagingXcmVersionedMultiLocation',
+ message: 'StagingXcmVersionedXcm',
+ },
+ teleport_assets: {
+ dest: 'StagingXcmVersionedMultiLocation',
+ beneficiary: 'StagingXcmVersionedMultiLocation',
+ assets: 'StagingXcmVersionedMultiAssets',
+ feeAssetItem: 'u32',
+ },
+ reserve_transfer_assets: {
+ dest: 'StagingXcmVersionedMultiLocation',
+ beneficiary: 'StagingXcmVersionedMultiLocation',
+ assets: 'StagingXcmVersionedMultiAssets',
+ feeAssetItem: 'u32',
+ },
+ execute: {
+ message: 'StagingXcmVersionedXcm',
+ maxWeight: 'SpWeightsWeightV2Weight',
+ },
+ force_xcm_version: {
+ location: 'StagingXcmV3MultiLocation',
+ version: 'u32',
+ },
+ force_default_xcm_version: {
+ maybeXcmVersion: 'Option<u32>',
+ },
+ force_subscribe_version_notify: {
+ location: 'StagingXcmVersionedMultiLocation',
+ },
+ force_unsubscribe_version_notify: {
+ location: 'StagingXcmVersionedMultiLocation',
+ },
+ limited_reserve_transfer_assets: {
+ dest: 'StagingXcmVersionedMultiLocation',
+ beneficiary: 'StagingXcmVersionedMultiLocation',
+ assets: 'StagingXcmVersionedMultiAssets',
+ feeAssetItem: 'u32',
+ weightLimit: 'StagingXcmV3WeightLimit',
+ },
+ limited_teleport_assets: {
+ dest: 'StagingXcmVersionedMultiLocation',
+ beneficiary: 'StagingXcmVersionedMultiLocation',
+ assets: 'StagingXcmVersionedMultiAssets',
+ feeAssetItem: 'u32',
+ weightLimit: 'StagingXcmV3WeightLimit',
+ },
+ force_suspension: {
+ suspended: 'bool'
+ }
+ }
+ },
+ /**
+ * Lookup225: staging_xcm::VersionedXcm<RuntimeCall>
+ **/
+ StagingXcmVersionedXcm: {
+ _enum: {
+ __Unused0: 'Null',
+ __Unused1: 'Null',
+ V2: 'StagingXcmV2Xcm',
+ V3: 'StagingXcmV3Xcm'
+ }
+ },
+ /**
+ * Lookup226: staging_xcm::v2::Xcm<RuntimeCall>
+ **/
+ StagingXcmV2Xcm: 'Vec<StagingXcmV2Instruction>',
+ /**
+ * Lookup228: staging_xcm::v2::Instruction<RuntimeCall>
+ **/
+ StagingXcmV2Instruction: {
+ _enum: {
+ WithdrawAsset: 'StagingXcmV2MultiassetMultiAssets',
+ ReserveAssetDeposited: 'StagingXcmV2MultiassetMultiAssets',
+ ReceiveTeleportedAsset: 'StagingXcmV2MultiassetMultiAssets',
+ QueryResponse: {
+ queryId: 'Compact<u64>',
+ response: 'StagingXcmV2Response',
+ maxWeight: 'Compact<u64>',
+ },
+ TransferAsset: {
+ assets: 'StagingXcmV2MultiassetMultiAssets',
+ beneficiary: 'StagingXcmV2MultiLocation',
+ },
+ TransferReserveAsset: {
+ assets: 'StagingXcmV2MultiassetMultiAssets',
+ dest: 'StagingXcmV2MultiLocation',
+ xcm: 'StagingXcmV2Xcm',
+ },
+ Transact: {
+ originType: 'StagingXcmV2OriginKind',
+ requireWeightAtMost: 'Compact<u64>',
+ call: 'StagingXcmDoubleEncoded',
+ },
+ HrmpNewChannelOpenRequest: {
+ sender: 'Compact<u32>',
+ maxMessageSize: 'Compact<u32>',
+ maxCapacity: 'Compact<u32>',
+ },
+ HrmpChannelAccepted: {
+ recipient: 'Compact<u32>',
+ },
+ HrmpChannelClosing: {
+ initiator: 'Compact<u32>',
+ sender: 'Compact<u32>',
+ recipient: 'Compact<u32>',
+ },
+ ClearOrigin: 'Null',
+ DescendOrigin: 'StagingXcmV2MultilocationJunctions',
+ ReportError: {
+ queryId: 'Compact<u64>',
+ dest: 'StagingXcmV2MultiLocation',
+ maxResponseWeight: 'Compact<u64>',
+ },
+ DepositAsset: {
+ assets: 'StagingXcmV2MultiassetMultiAssetFilter',
+ maxAssets: 'Compact<u32>',
+ beneficiary: 'StagingXcmV2MultiLocation',
+ },
+ DepositReserveAsset: {
+ assets: 'StagingXcmV2MultiassetMultiAssetFilter',
+ maxAssets: 'Compact<u32>',
+ dest: 'StagingXcmV2MultiLocation',
+ xcm: 'StagingXcmV2Xcm',
+ },
+ ExchangeAsset: {
+ give: 'StagingXcmV2MultiassetMultiAssetFilter',
+ receive: 'StagingXcmV2MultiassetMultiAssets',
+ },
+ InitiateReserveWithdraw: {
+ assets: 'StagingXcmV2MultiassetMultiAssetFilter',
+ reserve: 'StagingXcmV2MultiLocation',
+ xcm: 'StagingXcmV2Xcm',
+ },
+ InitiateTeleport: {
+ assets: 'StagingXcmV2MultiassetMultiAssetFilter',
+ dest: 'StagingXcmV2MultiLocation',
+ xcm: 'StagingXcmV2Xcm',
+ },
+ QueryHolding: {
+ queryId: 'Compact<u64>',
+ dest: 'StagingXcmV2MultiLocation',
+ assets: 'StagingXcmV2MultiassetMultiAssetFilter',
+ maxResponseWeight: 'Compact<u64>',
+ },
+ BuyExecution: {
+ fees: 'StagingXcmV2MultiAsset',
+ weightLimit: 'StagingXcmV2WeightLimit',
+ },
+ RefundSurplus: 'Null',
+ SetErrorHandler: 'StagingXcmV2Xcm',
+ SetAppendix: 'StagingXcmV2Xcm',
+ ClearError: 'Null',
+ ClaimAsset: {
+ assets: 'StagingXcmV2MultiassetMultiAssets',
+ ticket: 'StagingXcmV2MultiLocation',
+ },
+ Trap: 'Compact<u64>',
+ SubscribeVersion: {
+ queryId: 'Compact<u64>',
+ maxResponseWeight: 'Compact<u64>',
+ },
+ UnsubscribeVersion: 'Null'
+ }
+ },
+ /**
+ * Lookup229: staging_xcm::v2::Response
+ **/
+ StagingXcmV2Response: {
+ _enum: {
+ Null: 'Null',
+ Assets: 'StagingXcmV2MultiassetMultiAssets',
+ ExecutionResult: 'Option<(u32,StagingXcmV2TraitsError)>',
+ Version: 'u32'
+ }
+ },
+ /**
+ * Lookup232: staging_xcm::v2::traits::Error
+ **/
+ StagingXcmV2TraitsError: {
+ _enum: {
+ Overflow: 'Null',
+ Unimplemented: 'Null',
+ UntrustedReserveLocation: 'Null',
+ UntrustedTeleportLocation: 'Null',
+ MultiLocationFull: 'Null',
+ MultiLocationNotInvertible: 'Null',
+ BadOrigin: 'Null',
+ InvalidLocation: 'Null',
+ AssetNotFound: 'Null',
+ FailedToTransactAsset: 'Null',
+ NotWithdrawable: 'Null',
+ LocationCannotHold: 'Null',
+ ExceedsMaxMessageSize: 'Null',
+ DestinationUnsupported: 'Null',
+ Transport: 'Null',
+ Unroutable: 'Null',
+ UnknownClaim: 'Null',
+ FailedToDecode: 'Null',
+ MaxWeightInvalid: 'Null',
+ NotHoldingFees: 'Null',
+ TooExpensive: 'Null',
+ Trap: 'u64',
+ UnhandledXcmVersion: 'Null',
+ WeightLimitReached: 'u64',
+ Barrier: 'Null',
+ WeightNotComputable: 'Null'
+ }
+ },
+ /**
+ * Lookup233: staging_xcm::v2::OriginKind
+ **/
+ StagingXcmV2OriginKind: {
+ _enum: ['Native', 'SovereignAccount', 'Superuser', 'Xcm']
+ },
+ /**
+ * Lookup234: staging_xcm::double_encoded::DoubleEncoded<T>
+ **/
+ StagingXcmDoubleEncoded: {
+ encoded: 'Bytes'
+ },
+ /**
+ * Lookup235: staging_xcm::v2::multiasset::MultiAssetFilter
+ **/
+ StagingXcmV2MultiassetMultiAssetFilter: {
+ _enum: {
+ Definite: 'StagingXcmV2MultiassetMultiAssets',
+ Wild: 'StagingXcmV2MultiassetWildMultiAsset'
+ }
+ },
+ /**
+ * Lookup236: staging_xcm::v2::multiasset::WildMultiAsset
+ **/
+ StagingXcmV2MultiassetWildMultiAsset: {
+ _enum: {
+ All: 'Null',
+ AllOf: {
+ id: 'StagingXcmV2MultiassetAssetId',
+ fun: 'StagingXcmV2MultiassetWildFungibility'
+ }
+ }
+ },
+ /**
+ * Lookup237: staging_xcm::v2::multiasset::WildFungibility
+ **/
+ StagingXcmV2MultiassetWildFungibility: {
+ _enum: ['Fungible', 'NonFungible']
+ },
+ /**
+ * Lookup238: staging_xcm::v2::WeightLimit
+ **/
+ StagingXcmV2WeightLimit: {
+ _enum: {
+ Unlimited: 'Null',
+ Limited: 'Compact<u64>'
+ }
+ },
+ /**
+ * Lookup239: staging_xcm::v3::Xcm<Call>
+ **/
+ StagingXcmV3Xcm: 'Vec<StagingXcmV3Instruction>',
+ /**
+ * Lookup241: staging_xcm::v3::Instruction<Call>
+ **/
+ StagingXcmV3Instruction: {
+ _enum: {
+ WithdrawAsset: 'StagingXcmV3MultiassetMultiAssets',
+ ReserveAssetDeposited: 'StagingXcmV3MultiassetMultiAssets',
+ ReceiveTeleportedAsset: 'StagingXcmV3MultiassetMultiAssets',
+ QueryResponse: {
+ queryId: 'Compact<u64>',
+ response: 'StagingXcmV3Response',
+ maxWeight: 'SpWeightsWeightV2Weight',
+ querier: 'Option<StagingXcmV3MultiLocation>',
+ },
+ TransferAsset: {
+ assets: 'StagingXcmV3MultiassetMultiAssets',
+ beneficiary: 'StagingXcmV3MultiLocation',
+ },
+ TransferReserveAsset: {
+ assets: 'StagingXcmV3MultiassetMultiAssets',
+ dest: 'StagingXcmV3MultiLocation',
+ xcm: 'StagingXcmV3Xcm',
+ },
+ Transact: {
+ originKind: 'StagingXcmV2OriginKind',
+ requireWeightAtMost: 'SpWeightsWeightV2Weight',
+ call: 'StagingXcmDoubleEncoded',
+ },
+ HrmpNewChannelOpenRequest: {
+ sender: 'Compact<u32>',
+ maxMessageSize: 'Compact<u32>',
+ maxCapacity: 'Compact<u32>',
+ },
+ HrmpChannelAccepted: {
+ recipient: 'Compact<u32>',
+ },
+ HrmpChannelClosing: {
+ initiator: 'Compact<u32>',
+ sender: 'Compact<u32>',
+ recipient: 'Compact<u32>',
+ },
+ ClearOrigin: 'Null',
+ DescendOrigin: 'StagingXcmV3Junctions',
+ ReportError: 'StagingXcmV3QueryResponseInfo',
+ DepositAsset: {
+ assets: 'StagingXcmV3MultiassetMultiAssetFilter',
+ beneficiary: 'StagingXcmV3MultiLocation',
+ },
+ DepositReserveAsset: {
+ assets: 'StagingXcmV3MultiassetMultiAssetFilter',
+ dest: 'StagingXcmV3MultiLocation',
+ xcm: 'StagingXcmV3Xcm',
+ },
+ ExchangeAsset: {
+ give: 'StagingXcmV3MultiassetMultiAssetFilter',
+ want: 'StagingXcmV3MultiassetMultiAssets',
+ maximal: 'bool',
+ },
+ InitiateReserveWithdraw: {
+ assets: 'StagingXcmV3MultiassetMultiAssetFilter',
+ reserve: 'StagingXcmV3MultiLocation',
+ xcm: 'StagingXcmV3Xcm',
+ },
+ InitiateTeleport: {
+ assets: 'StagingXcmV3MultiassetMultiAssetFilter',
+ dest: 'StagingXcmV3MultiLocation',
+ xcm: 'StagingXcmV3Xcm',
+ },
+ ReportHolding: {
+ responseInfo: 'StagingXcmV3QueryResponseInfo',
+ assets: 'StagingXcmV3MultiassetMultiAssetFilter',
+ },
+ BuyExecution: {
+ fees: 'StagingXcmV3MultiAsset',
+ weightLimit: 'StagingXcmV3WeightLimit',
+ },
+ RefundSurplus: 'Null',
+ SetErrorHandler: 'StagingXcmV3Xcm',
+ SetAppendix: 'StagingXcmV3Xcm',
+ ClearError: 'Null',
+ ClaimAsset: {
+ assets: 'StagingXcmV3MultiassetMultiAssets',
+ ticket: 'StagingXcmV3MultiLocation',
+ },
+ Trap: 'Compact<u64>',
+ SubscribeVersion: {
+ queryId: 'Compact<u64>',
+ maxResponseWeight: 'SpWeightsWeightV2Weight',
+ },
+ UnsubscribeVersion: 'Null',
+ BurnAsset: 'StagingXcmV3MultiassetMultiAssets',
+ ExpectAsset: 'StagingXcmV3MultiassetMultiAssets',
+ ExpectOrigin: 'Option<StagingXcmV3MultiLocation>',
+ ExpectError: 'Option<(u32,StagingXcmV3TraitsError)>',
+ ExpectTransactStatus: 'StagingXcmV3MaybeErrorCode',
+ QueryPallet: {
+ moduleName: 'Bytes',
+ responseInfo: 'StagingXcmV3QueryResponseInfo',
+ },
+ ExpectPallet: {
+ index: 'Compact<u32>',
+ name: 'Bytes',
+ moduleName: 'Bytes',
+ crateMajor: 'Compact<u32>',
+ minCrateMinor: 'Compact<u32>',
+ },
+ ReportTransactStatus: 'StagingXcmV3QueryResponseInfo',
+ ClearTransactStatus: 'Null',
+ UniversalOrigin: 'StagingXcmV3Junction',
+ ExportMessage: {
+ network: 'StagingXcmV3JunctionNetworkId',
+ destination: 'StagingXcmV3Junctions',
+ xcm: 'StagingXcmV3Xcm',
+ },
+ LockAsset: {
+ asset: 'StagingXcmV3MultiAsset',
+ unlocker: 'StagingXcmV3MultiLocation',
+ },
+ UnlockAsset: {
+ asset: 'StagingXcmV3MultiAsset',
+ target: 'StagingXcmV3MultiLocation',
+ },
+ NoteUnlockable: {
+ asset: 'StagingXcmV3MultiAsset',
+ owner: 'StagingXcmV3MultiLocation',
+ },
+ RequestUnlock: {
+ asset: 'StagingXcmV3MultiAsset',
+ locker: 'StagingXcmV3MultiLocation',
+ },
+ SetFeesMode: {
+ jitWithdraw: 'bool',
+ },
+ SetTopic: '[u8;32]',
+ ClearTopic: 'Null',
+ AliasOrigin: 'StagingXcmV3MultiLocation',
+ UnpaidExecution: {
+ weightLimit: 'StagingXcmV3WeightLimit',
+ checkOrigin: 'Option<StagingXcmV3MultiLocation>'
+ }
+ }
+ },
+ /**
+ * Lookup242: staging_xcm::v3::Response
+ **/
+ StagingXcmV3Response: {
+ _enum: {
+ Null: 'Null',
+ Assets: 'StagingXcmV3MultiassetMultiAssets',
+ ExecutionResult: 'Option<(u32,StagingXcmV3TraitsError)>',
+ Version: 'u32',
+ PalletsInfo: 'Vec<StagingXcmV3PalletInfo>',
+ DispatchResult: 'StagingXcmV3MaybeErrorCode'
+ }
+ },
+ /**
+ * Lookup245: staging_xcm::v3::traits::Error
+ **/
+ StagingXcmV3TraitsError: {
+ _enum: {
+ Overflow: 'Null',
+ Unimplemented: 'Null',
+ UntrustedReserveLocation: 'Null',
+ UntrustedTeleportLocation: 'Null',
+ LocationFull: 'Null',
+ LocationNotInvertible: 'Null',
+ BadOrigin: 'Null',
+ InvalidLocation: 'Null',
+ AssetNotFound: 'Null',
+ FailedToTransactAsset: 'Null',
+ NotWithdrawable: 'Null',
+ LocationCannotHold: 'Null',
+ ExceedsMaxMessageSize: 'Null',
+ DestinationUnsupported: 'Null',
+ Transport: 'Null',
+ Unroutable: 'Null',
+ UnknownClaim: 'Null',
+ FailedToDecode: 'Null',
+ MaxWeightInvalid: 'Null',
+ NotHoldingFees: 'Null',
+ TooExpensive: 'Null',
+ Trap: 'u64',
+ ExpectationFalse: 'Null',
+ PalletNotFound: 'Null',
+ NameMismatch: 'Null',
+ VersionIncompatible: 'Null',
+ HoldingWouldOverflow: 'Null',
+ ExportError: 'Null',
+ ReanchorFailed: 'Null',
+ NoDeal: 'Null',
+ FeesNotMet: 'Null',
+ LockError: 'Null',
+ NoPermission: 'Null',
+ Unanchored: 'Null',
+ NotDepositable: 'Null',
+ UnhandledXcmVersion: 'Null',
+ WeightLimitReached: 'SpWeightsWeightV2Weight',
+ Barrier: 'Null',
+ WeightNotComputable: 'Null',
+ ExceedsStackLimit: 'Null'
+ }
+ },
+ /**
+ * Lookup247: staging_xcm::v3::PalletInfo
+ **/
+ StagingXcmV3PalletInfo: {
+ index: 'Compact<u32>',
+ name: 'Bytes',
+ moduleName: 'Bytes',
+ major: 'Compact<u32>',
+ minor: 'Compact<u32>',
+ patch: 'Compact<u32>'
+ },
+ /**
+ * Lookup250: staging_xcm::v3::MaybeErrorCode
+ **/
+ StagingXcmV3MaybeErrorCode: {
+ _enum: {
+ Success: 'Null',
+ Error: 'Bytes',
+ TruncatedError: 'Bytes'
+ }
+ },
+ /**
+ * Lookup253: staging_xcm::v3::QueryResponseInfo
+ **/
+ StagingXcmV3QueryResponseInfo: {
+ destination: 'StagingXcmV3MultiLocation',
+ queryId: 'Compact<u64>',
+ maxWeight: 'SpWeightsWeightV2Weight'
+ },
+ /**
+ * Lookup254: staging_xcm::v3::multiasset::MultiAssetFilter
+ **/
+ StagingXcmV3MultiassetMultiAssetFilter: {
+ _enum: {
+ Definite: 'StagingXcmV3MultiassetMultiAssets',
+ Wild: 'StagingXcmV3MultiassetWildMultiAsset'
+ }
+ },
+ /**
+ * Lookup255: staging_xcm::v3::multiasset::WildMultiAsset
+ **/
+ StagingXcmV3MultiassetWildMultiAsset: {
+ _enum: {
+ All: 'Null',
+ AllOf: {
+ id: 'StagingXcmV3MultiassetAssetId',
+ fun: 'StagingXcmV3MultiassetWildFungibility',
+ },
+ AllCounted: 'Compact<u32>',
+ AllOfCounted: {
+ id: 'StagingXcmV3MultiassetAssetId',
+ fun: 'StagingXcmV3MultiassetWildFungibility',
+ count: 'Compact<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup256: staging_xcm::v3::multiasset::WildFungibility
+ **/
+ StagingXcmV3MultiassetWildFungibility: {
+ _enum: ['Fungible', 'NonFungible']
+ },
+ /**
+ * Lookup265: cumulus_pallet_xcm::pallet::Call<T>
+ **/
+ CumulusPalletXcmCall: 'Null',
+ /**
+ * Lookup266: cumulus_pallet_dmp_queue::pallet::Call<T>
+ **/
+ CumulusPalletDmpQueueCall: {
+ _enum: {
+ service_overweight: {
+ index: 'u64',
+ weightLimit: 'SpWeightsWeightV2Weight'
+ }
+ }
+ },
+ /**
+ * Lookup267: pallet_inflation::pallet::Call<T>
+ **/
+ PalletInflationCall: {
+ _enum: {
+ start_inflation: {
+ inflationStartRelayBlock: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup268: pallet_unique::pallet::Call<T>
+ **/
+ PalletUniqueCall: {
+ _enum: {
+ create_collection: {
+ collectionName: 'Vec<u16>',
+ collectionDescription: 'Vec<u16>',
+ tokenPrefix: 'Bytes',
+ mode: 'UpDataStructsCollectionMode',
+ },
+ create_collection_ex: {
+ data: 'UpDataStructsCreateCollectionData',
+ },
+ destroy_collection: {
+ collectionId: 'u32',
+ },
+ add_to_allow_list: {
+ collectionId: 'u32',
+ address: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ },
+ remove_from_allow_list: {
+ collectionId: 'u32',
+ address: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ },
+ change_collection_owner: {
+ collectionId: 'u32',
+ newOwner: 'AccountId32',
+ },
+ add_collection_admin: {
+ collectionId: 'u32',
+ newAdminId: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ },
+ remove_collection_admin: {
+ collectionId: 'u32',
+ accountId: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ },
+ set_collection_sponsor: {
+ collectionId: 'u32',
+ newSponsor: 'AccountId32',
+ },
+ confirm_sponsorship: {
+ collectionId: 'u32',
+ },
+ remove_collection_sponsor: {
+ collectionId: 'u32',
+ },
+ create_item: {
+ collectionId: 'u32',
+ owner: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ data: 'UpDataStructsCreateItemData',
+ },
+ create_multiple_items: {
+ collectionId: 'u32',
+ owner: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ itemsData: 'Vec<UpDataStructsCreateItemData>',
+ },
+ set_collection_properties: {
+ collectionId: 'u32',
+ properties: 'Vec<UpDataStructsProperty>',
+ },
+ delete_collection_properties: {
+ collectionId: 'u32',
+ propertyKeys: 'Vec<Bytes>',
+ },
+ set_token_properties: {
+ collectionId: 'u32',
+ tokenId: 'u32',
+ properties: 'Vec<UpDataStructsProperty>',
+ },
+ delete_token_properties: {
+ collectionId: 'u32',
+ tokenId: 'u32',
+ propertyKeys: 'Vec<Bytes>',
+ },
+ set_token_property_permissions: {
+ collectionId: 'u32',
+ propertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
+ },
+ create_multiple_items_ex: {
+ collectionId: 'u32',
+ data: 'UpDataStructsCreateItemExData',
+ },
+ set_transfers_enabled_flag: {
+ collectionId: 'u32',
+ value: 'bool',
+ },
+ burn_item: {
+ collectionId: 'u32',
+ itemId: 'u32',
+ value: 'u128',
+ },
+ burn_from: {
+ collectionId: 'u32',
+ from: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ itemId: 'u32',
+ value: 'u128',
+ },
+ transfer: {
+ recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ collectionId: 'u32',
+ itemId: 'u32',
+ value: 'u128',
+ },
+ approve: {
+ spender: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ collectionId: 'u32',
+ itemId: 'u32',
+ amount: 'u128',
+ },
+ approve_from: {
+ from: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ to: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ collectionId: 'u32',
+ itemId: 'u32',
+ amount: 'u128',
+ },
+ transfer_from: {
+ from: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ collectionId: 'u32',
+ itemId: 'u32',
+ value: 'u128',
+ },
+ set_collection_limits: {
+ collectionId: 'u32',
+ newLimit: 'UpDataStructsCollectionLimits',
+ },
+ set_collection_permissions: {
+ collectionId: 'u32',
+ newPermission: 'UpDataStructsCollectionPermissions',
+ },
+ repartition: {
+ collectionId: 'u32',
+ tokenId: 'u32',
+ amount: 'u128',
+ },
+ set_allowance_for_all: {
+ collectionId: 'u32',
+ operator: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ approve: 'bool',
+ },
+ force_repair_collection: {
+ collectionId: 'u32',
+ },
+ force_repair_item: {
+ collectionId: 'u32',
+ itemId: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup273: up_data_structs::CollectionMode
+ **/
+ UpDataStructsCollectionMode: {
+ _enum: {
+ NFT: 'Null',
+ Fungible: 'u8',
+ ReFungible: 'Null'
+ }
+ },
+ /**
+ * Lookup274: up_data_structs::CreateCollectionData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsCreateCollectionData: {
+ mode: 'UpDataStructsCollectionMode',
+ access: 'Option<UpDataStructsAccessMode>',
+ name: 'Vec<u16>',
+ description: 'Vec<u16>',
+ tokenPrefix: 'Bytes',
+ limits: 'Option<UpDataStructsCollectionLimits>',
+ permissions: 'Option<UpDataStructsCollectionPermissions>',
+ tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
+ properties: 'Vec<UpDataStructsProperty>',
+ adminList: 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
+ pendingSponsor: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>',
+ flags: '[u8;1]'
+ },
+ /**
+ * Lookup275: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>
+ **/
+ PalletEvmAccountBasicCrossAccountIdRepr: {
+ _enum: {
+ Substrate: 'AccountId32',
+ Ethereum: 'H160'
+ }
+ },
+ /**
+ * Lookup277: up_data_structs::AccessMode
+ **/
+ UpDataStructsAccessMode: {
+ _enum: ['Normal', 'AllowList']
+ },
+ /**
+ * Lookup279: up_data_structs::CollectionLimits
+ **/
+ UpDataStructsCollectionLimits: {
+ accountTokenOwnershipLimit: 'Option<u32>',
+ sponsoredDataSize: 'Option<u32>',
+ sponsoredDataRateLimit: 'Option<UpDataStructsSponsoringRateLimit>',
+ tokenLimit: 'Option<u32>',
+ sponsorTransferTimeout: 'Option<u32>',
+ sponsorApproveTimeout: 'Option<u32>',
+ ownerCanTransfer: 'Option<bool>',
+ ownerCanDestroy: 'Option<bool>',
+ transfersEnabled: 'Option<bool>'
+ },
+ /**
+ * Lookup281: up_data_structs::SponsoringRateLimit
+ **/
+ UpDataStructsSponsoringRateLimit: {
+ _enum: {
+ SponsoringDisabled: 'Null',
+ Blocks: 'u32'
+ }
+ },
+ /**
+ * Lookup284: up_data_structs::CollectionPermissions
+ **/
+ UpDataStructsCollectionPermissions: {
+ access: 'Option<UpDataStructsAccessMode>',
+ mintMode: 'Option<bool>',
+ nesting: 'Option<UpDataStructsNestingPermissions>'
+ },
+ /**
+ * Lookup286: up_data_structs::NestingPermissions
+ **/
+ UpDataStructsNestingPermissions: {
+ tokenOwner: 'bool',
+ collectionAdmin: 'bool',
+ restricted: 'Option<UpDataStructsOwnerRestrictedSet>'
+ },
+ /**
+ * Lookup288: up_data_structs::OwnerRestrictedSet
+ **/
+ UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',
+ /**
+ * Lookup294: up_data_structs::PropertyKeyPermission
+ **/
+ UpDataStructsPropertyKeyPermission: {
+ key: 'Bytes',
+ permission: 'UpDataStructsPropertyPermission'
+ },
+ /**
+ * Lookup296: up_data_structs::PropertyPermission
+ **/
+ UpDataStructsPropertyPermission: {
+ mutable: 'bool',
+ collectionAdmin: 'bool',
+ tokenOwner: 'bool'
+ },
+ /**
+ * Lookup299: up_data_structs::Property
+ **/
+ UpDataStructsProperty: {
+ key: 'Bytes',
+ value: 'Bytes'
+ },
+ /**
+ * Lookup304: up_data_structs::CreateItemData
+ **/
+ UpDataStructsCreateItemData: {
+ _enum: {
+ NFT: 'UpDataStructsCreateNftData',
+ Fungible: 'UpDataStructsCreateFungibleData',
+ ReFungible: 'UpDataStructsCreateReFungibleData'
+ }
+ },
+ /**
+ * Lookup305: up_data_structs::CreateNftData
+ **/
+ UpDataStructsCreateNftData: {
+ properties: 'Vec<UpDataStructsProperty>'
+ },
+ /**
+ * Lookup306: up_data_structs::CreateFungibleData
+ **/
+ UpDataStructsCreateFungibleData: {
+ value: 'u128'
+ },
+ /**
+ * Lookup307: up_data_structs::CreateReFungibleData
+ **/
+ UpDataStructsCreateReFungibleData: {
+ pieces: 'u128',
+ properties: 'Vec<UpDataStructsProperty>'
+ },
+ /**
+ * Lookup311: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsCreateItemExData: {
+ _enum: {
+ NFT: 'Vec<UpDataStructsCreateNftExData>',
+ Fungible: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
+ RefungibleMultipleItems: 'Vec<UpDataStructsCreateRefungibleExSingleOwner>',
+ RefungibleMultipleOwners: 'UpDataStructsCreateRefungibleExMultipleOwners'
+ }
+ },
+ /**
+ * Lookup313: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsCreateNftExData: {
+ properties: 'Vec<UpDataStructsProperty>',
+ owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
+ },
+ /**
+ * Lookup320: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsCreateRefungibleExSingleOwner: {
+ user: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ pieces: 'u128',
+ properties: 'Vec<UpDataStructsProperty>'
+ },
+ /**
+ * Lookup322: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsCreateRefungibleExMultipleOwners: {
+ users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
+ properties: 'Vec<UpDataStructsProperty>'
+ },
+ /**
+ * Lookup323: pallet_configuration::pallet::Call<T>
+ **/
+ PalletConfigurationCall: {
+ _enum: {
+ set_weight_to_fee_coefficient_override: {
+ coeff: 'Option<u64>',
+ },
+ set_min_gas_price_override: {
+ coeff: 'Option<u64>',
+ },
+ __Unused2: 'Null',
+ set_app_promotion_configuration_override: {
+ configuration: 'PalletConfigurationAppPromotionConfiguration',
+ },
+ set_collator_selection_desired_collators: {
+ max: 'Option<u32>',
+ },
+ set_collator_selection_license_bond: {
+ amount: 'Option<u128>',
+ },
+ set_collator_selection_kick_threshold: {
+ threshold: 'Option<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup325: pallet_configuration::AppPromotionConfiguration<BlockNumber>
+ **/
+ PalletConfigurationAppPromotionConfiguration: {
+ recalculationInterval: 'Option<u32>',
+ pendingInterval: 'Option<u32>',
+ intervalIncome: 'Option<Perbill>',
+ maxStakersPerCalculation: 'Option<u8>'
+ },
+ /**
+ * Lookup330: pallet_structure::pallet::Call<T>
+ **/
+ PalletStructureCall: 'Null',
+ /**
+ * Lookup331: pallet_app_promotion::pallet::Call<T>
+ **/
+ PalletAppPromotionCall: {
+ _enum: {
+ set_admin_address: {
+ admin: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ },
+ stake: {
+ amount: 'u128',
+ },
+ unstake_all: 'Null',
+ sponsor_collection: {
+ collectionId: 'u32',
+ },
+ stop_sponsoring_collection: {
+ collectionId: 'u32',
+ },
+ sponsor_contract: {
+ contractId: 'H160',
+ },
+ stop_sponsoring_contract: {
+ contractId: 'H160',
+ },
+ payout_stakers: {
+ stakersNumber: 'Option<u8>',
+ },
+ unstake_partial: {
+ amount: 'u128',
+ },
+ force_unstake: {
+ pendingBlocks: 'Vec<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup333: pallet_foreign_assets::module::Call<T>
+ **/
+ PalletForeignAssetsModuleCall: {
+ _enum: {
+ register_foreign_asset: {
+ owner: 'AccountId32',
+ location: 'StagingXcmVersionedMultiLocation',
+ metadata: 'PalletForeignAssetsModuleAssetMetadata',
+ },
+ update_foreign_asset: {
+ foreignAssetId: 'u32',
+ location: 'StagingXcmVersionedMultiLocation',
+ metadata: 'PalletForeignAssetsModuleAssetMetadata'
+ }
+ }
+ },
+ /**
+ * Lookup334: pallet_foreign_assets::module::AssetMetadata<Balance>
+ **/
+ PalletForeignAssetsModuleAssetMetadata: {
+ name: 'Bytes',
+ symbol: 'Bytes',
+ decimals: 'u8',
+ minimalBalance: 'u128'
+ },
+ /**
+ * Lookup337: pallet_evm::pallet::Call<T>
+ **/
+ PalletEvmCall: {
+ _enum: {
+ withdraw: {
+ address: 'H160',
+ value: 'u128',
+ },
+ call: {
+ source: 'H160',
+ target: 'H160',
+ input: 'Bytes',
+ value: 'U256',
+ gasLimit: 'u64',
+ maxFeePerGas: 'U256',
+ maxPriorityFeePerGas: 'Option<U256>',
+ nonce: 'Option<U256>',
+ accessList: 'Vec<(H160,Vec<H256>)>',
+ },
+ create: {
+ source: 'H160',
+ init: 'Bytes',
+ value: 'U256',
+ gasLimit: 'u64',
+ maxFeePerGas: 'U256',
+ maxPriorityFeePerGas: 'Option<U256>',
+ nonce: 'Option<U256>',
+ accessList: 'Vec<(H160,Vec<H256>)>',
+ },
+ create2: {
+ source: 'H160',
+ init: 'Bytes',
+ salt: 'H256',
+ value: 'U256',
+ gasLimit: 'u64',
+ maxFeePerGas: 'U256',
+ maxPriorityFeePerGas: 'Option<U256>',
+ nonce: 'Option<U256>',
+ accessList: 'Vec<(H160,Vec<H256>)>'
+ }
+ }
+ },
+ /**
+ * Lookup344: pallet_ethereum::pallet::Call<T>
+ **/
+ PalletEthereumCall: {
+ _enum: {
+ transact: {
+ transaction: 'EthereumTransactionTransactionV2'
+ }
+ }
+ },
+ /**
+ * Lookup345: ethereum::transaction::TransactionV2
+ **/
+ EthereumTransactionTransactionV2: {
+ _enum: {
+ Legacy: 'EthereumTransactionLegacyTransaction',
+ EIP2930: 'EthereumTransactionEip2930Transaction',
+ EIP1559: 'EthereumTransactionEip1559Transaction'
+ }
+ },
+ /**
+ * Lookup346: ethereum::transaction::LegacyTransaction
+ **/
+ EthereumTransactionLegacyTransaction: {
+ nonce: 'U256',
+ gasPrice: 'U256',
+ gasLimit: 'U256',
+ action: 'EthereumTransactionTransactionAction',
+ value: 'U256',
+ input: 'Bytes',
+ signature: 'EthereumTransactionTransactionSignature'
+ },
+ /**
+ * Lookup347: ethereum::transaction::TransactionAction
+ **/
+ EthereumTransactionTransactionAction: {
+ _enum: {
+ Call: 'H160',
+ Create: 'Null'
+ }
+ },
+ /**
+ * Lookup348: ethereum::transaction::TransactionSignature
+ **/
+ EthereumTransactionTransactionSignature: {
+ v: 'u64',
+ r: 'H256',
+ s: 'H256'
+ },
+ /**
+ * Lookup350: ethereum::transaction::EIP2930Transaction
+ **/
+ EthereumTransactionEip2930Transaction: {
+ chainId: 'u64',
+ nonce: 'U256',
+ gasPrice: 'U256',
+ gasLimit: 'U256',
+ action: 'EthereumTransactionTransactionAction',
+ value: 'U256',
+ input: 'Bytes',
+ accessList: 'Vec<EthereumTransactionAccessListItem>',
+ oddYParity: 'bool',
+ r: 'H256',
+ s: 'H256'
+ },
+ /**
+ * Lookup352: ethereum::transaction::AccessListItem
+ **/
+ EthereumTransactionAccessListItem: {
+ address: 'H160',
+ storageKeys: 'Vec<H256>'
+ },
+ /**
+ * Lookup353: ethereum::transaction::EIP1559Transaction
+ **/
+ EthereumTransactionEip1559Transaction: {
+ chainId: 'u64',
+ nonce: 'U256',
+ maxPriorityFeePerGas: 'U256',
+ maxFeePerGas: 'U256',
+ gasLimit: 'U256',
+ action: 'EthereumTransactionTransactionAction',
+ value: 'U256',
+ input: 'Bytes',
+ accessList: 'Vec<EthereumTransactionAccessListItem>',
+ oddYParity: 'bool',
+ r: 'H256',
+ s: 'H256'
+ },
+ /**
+ * Lookup354: pallet_evm_contract_helpers::pallet::Call<T>
+ **/
+ PalletEvmContractHelpersCall: {
+ _enum: {
+ migrate_from_self_sponsoring: {
+ addresses: 'Vec<H160>'
+ }
+ }
+ },
+ /**
+ * Lookup356: pallet_evm_migration::pallet::Call<T>
+ **/
+ PalletEvmMigrationCall: {
+ _enum: {
+ begin: {
+ address: 'H160',
+ },
+ set_data: {
+ address: 'H160',
+ data: 'Vec<(H256,H256)>',
+ },
+ finish: {
+ address: 'H160',
+ code: 'Bytes',
+ },
+ insert_eth_logs: {
+ logs: 'Vec<EthereumLog>',
+ },
+ insert_events: {
+ events: 'Vec<Bytes>',
+ },
+ remove_rmrk_data: 'Null'
+ }
+ },
+ /**
+ * Lookup360: ethereum::log::Log
+ **/
+ EthereumLog: {
+ address: 'H160',
+ topics: 'Vec<H256>',
+ data: 'Bytes'
+ },
+ /**
+ * Lookup361: pallet_maintenance::pallet::Call<T>
+ **/
+ PalletMaintenanceCall: {
+ _enum: ['enable', 'disable']
+ },
+ /**
+ * Lookup362: pallet_utility::pallet::Call<T>
+ **/
+ PalletUtilityCall: {
+ _enum: {
+ batch: {
+ calls: 'Vec<Call>',
+ },
+ as_derivative: {
+ index: 'u16',
+ call: 'Call',
+ },
+ batch_all: {
+ calls: 'Vec<Call>',
+ },
+ dispatch_as: {
+ asOrigin: 'OpalRuntimeOriginCaller',
+ call: 'Call',
+ },
+ force_batch: {
+ calls: 'Vec<Call>',
+ },
+ with_weight: {
+ call: 'Call',
+ weight: 'SpWeightsWeightV2Weight'
+ }
+ }
+ },
+ /**
+ * Lookup364: pallet_test_utils::pallet::Call<T>
+ **/
+ PalletTestUtilsCall: {
+ _enum: {
+ enable: 'Null',
+ set_test_value: {
+ value: 'u32',
+ },
+ set_test_value_and_rollback: {
+ value: 'u32',
+ },
+ inc_test_value: 'Null',
+ just_take_fee: 'Null',
+ batch_all: {
+ calls: 'Vec<Call>'
+ }
+ }
+ },
+ /**
+ * Lookup366: pallet_scheduler::pallet::Event<T>
+ **/
+ PalletSchedulerEvent: {
+ _enum: {
+ Scheduled: {
+ when: 'u32',
+ index: 'u32',
+ },
+ Canceled: {
+ when: 'u32',
+ index: 'u32',
+ },
+ Dispatched: {
+ task: '(u32,u32)',
+ id: 'Option<[u8;32]>',
+ result: 'Result<Null, SpRuntimeDispatchError>',
+ },
+ CallUnavailable: {
+ task: '(u32,u32)',
+ id: 'Option<[u8;32]>',
+ },
+ PeriodicFailed: {
+ task: '(u32,u32)',
+ id: 'Option<[u8;32]>',
+ },
+ PermanentlyOverweight: {
+ task: '(u32,u32)',
+ id: 'Option<[u8;32]>'
+ }
+ }
+ },
+ /**
+ * Lookup367: cumulus_pallet_xcmp_queue::pallet::Event<T>
+ **/
+ CumulusPalletXcmpQueueEvent: {
+ _enum: {
+ Success: {
+ messageHash: '[u8;32]',
+ messageId: '[u8;32]',
+ weight: 'SpWeightsWeightV2Weight',
+ },
+ Fail: {
+ messageHash: '[u8;32]',
+ messageId: '[u8;32]',
+ error: 'StagingXcmV3TraitsError',
+ weight: 'SpWeightsWeightV2Weight',
+ },
+ BadVersion: {
+ messageHash: '[u8;32]',
+ },
+ BadFormat: {
+ messageHash: '[u8;32]',
+ },
+ XcmpMessageSent: {
+ messageHash: '[u8;32]',
+ },
+ OverweightEnqueued: {
+ sender: 'u32',
+ sentAt: 'u32',
+ index: 'u64',
+ required: 'SpWeightsWeightV2Weight',
+ },
+ OverweightServiced: {
+ index: 'u64',
+ used: 'SpWeightsWeightV2Weight'
+ }
+ }
+ },
+ /**
+ * Lookup368: pallet_xcm::pallet::Event<T>
+ **/
+ PalletXcmEvent: {
+ _enum: {
+ Attempted: {
+ outcome: 'StagingXcmV3TraitsOutcome',
+ },
+ Sent: {
+ origin: 'StagingXcmV3MultiLocation',
+ destination: 'StagingXcmV3MultiLocation',
+ message: 'StagingXcmV3Xcm',
+ messageId: '[u8;32]',
+ },
+ UnexpectedResponse: {
+ origin: 'StagingXcmV3MultiLocation',
+ queryId: 'u64',
+ },
+ ResponseReady: {
+ queryId: 'u64',
+ response: 'StagingXcmV3Response',
+ },
+ Notified: {
+ queryId: 'u64',
+ palletIndex: 'u8',
+ callIndex: 'u8',
+ },
+ NotifyOverweight: {
+ queryId: 'u64',
+ palletIndex: 'u8',
+ callIndex: 'u8',
+ actualWeight: 'SpWeightsWeightV2Weight',
+ maxBudgetedWeight: 'SpWeightsWeightV2Weight',
+ },
+ NotifyDispatchError: {
+ queryId: 'u64',
+ palletIndex: 'u8',
+ callIndex: 'u8',
+ },
+ NotifyDecodeFailed: {
+ queryId: 'u64',
+ palletIndex: 'u8',
+ callIndex: 'u8',
+ },
+ InvalidResponder: {
+ origin: 'StagingXcmV3MultiLocation',
+ queryId: 'u64',
+ expectedLocation: 'Option<StagingXcmV3MultiLocation>',
+ },
+ InvalidResponderVersion: {
+ origin: 'StagingXcmV3MultiLocation',
+ queryId: 'u64',
+ },
+ ResponseTaken: {
+ queryId: 'u64',
+ },
+ AssetsTrapped: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ origin: 'StagingXcmV3MultiLocation',
+ assets: 'StagingXcmVersionedMultiAssets',
+ },
+ VersionChangeNotified: {
+ destination: 'StagingXcmV3MultiLocation',
+ result: 'u32',
+ cost: 'StagingXcmV3MultiassetMultiAssets',
+ messageId: '[u8;32]',
+ },
+ SupportedVersionChanged: {
+ location: 'StagingXcmV3MultiLocation',
+ version: 'u32',
+ },
+ NotifyTargetSendFail: {
+ location: 'StagingXcmV3MultiLocation',
+ queryId: 'u64',
+ error: 'StagingXcmV3TraitsError',
+ },
+ NotifyTargetMigrationFail: {
+ location: 'StagingXcmVersionedMultiLocation',
+ queryId: 'u64',
+ },
+ InvalidQuerierVersion: {
+ origin: 'StagingXcmV3MultiLocation',
+ queryId: 'u64',
+ },
+ InvalidQuerier: {
+ origin: 'StagingXcmV3MultiLocation',
+ queryId: 'u64',
+ expectedQuerier: 'StagingXcmV3MultiLocation',
+ maybeActualQuerier: 'Option<StagingXcmV3MultiLocation>',
+ },
+ VersionNotifyStarted: {
+ destination: 'StagingXcmV3MultiLocation',
+ cost: 'StagingXcmV3MultiassetMultiAssets',
+ messageId: '[u8;32]',
+ },
+ VersionNotifyRequested: {
+ destination: 'StagingXcmV3MultiLocation',
+ cost: 'StagingXcmV3MultiassetMultiAssets',
+ messageId: '[u8;32]',
+ },
+ VersionNotifyUnrequested: {
+ destination: 'StagingXcmV3MultiLocation',
+ cost: 'StagingXcmV3MultiassetMultiAssets',
+ messageId: '[u8;32]',
+ },
+ FeesPaid: {
+ paying: 'StagingXcmV3MultiLocation',
+ fees: 'StagingXcmV3MultiassetMultiAssets',
+ },
+ AssetsClaimed: {
+ _alias: {
+ hash_: 'hash',
+ },
+ hash_: 'H256',
+ origin: 'StagingXcmV3MultiLocation',
+ assets: 'StagingXcmVersionedMultiAssets'
+ }
+ }
+ },
+ /**
+ * Lookup369: staging_xcm::v3::traits::Outcome
+ **/
+ StagingXcmV3TraitsOutcome: {
+ _enum: {
+ Complete: 'SpWeightsWeightV2Weight',
+ Incomplete: '(SpWeightsWeightV2Weight,StagingXcmV3TraitsError)',
+ Error: 'StagingXcmV3TraitsError'
+ }
+ },
+ /**
+ * Lookup370: cumulus_pallet_xcm::pallet::Event<T>
+ **/
+ CumulusPalletXcmEvent: {
+ _enum: {
+ InvalidFormat: '[u8;32]',
+ UnsupportedVersion: '[u8;32]',
+ ExecutedDownward: '([u8;32],StagingXcmV3TraitsOutcome)'
+ }
+ },
+ /**
+ * Lookup371: cumulus_pallet_dmp_queue::pallet::Event<T>
+ **/
+ CumulusPalletDmpQueueEvent: {
+ _enum: {
+ InvalidFormat: {
+ messageHash: '[u8;32]',
+ },
+ UnsupportedVersion: {
+ messageHash: '[u8;32]',
+ },
+ ExecutedDownward: {
+ messageHash: '[u8;32]',
+ messageId: '[u8;32]',
+ outcome: 'StagingXcmV3TraitsOutcome',
+ },
+ WeightExhausted: {
+ messageHash: '[u8;32]',
+ messageId: '[u8;32]',
+ remainingWeight: 'SpWeightsWeightV2Weight',
+ requiredWeight: 'SpWeightsWeightV2Weight',
+ },
+ OverweightEnqueued: {
+ messageHash: '[u8;32]',
+ messageId: '[u8;32]',
+ overweightIndex: 'u64',
+ requiredWeight: 'SpWeightsWeightV2Weight',
+ },
+ OverweightServiced: {
+ overweightIndex: 'u64',
+ weightUsed: 'SpWeightsWeightV2Weight',
+ },
+ MaxMessagesExhausted: {
+ messageHash: '[u8;32]'
+ }
+ }
+ },
+ /**
+ * Lookup372: pallet_configuration::pallet::Event<T>
+ **/
+ PalletConfigurationEvent: {
+ _enum: {
+ NewDesiredCollators: {
+ desiredCollators: 'Option<u32>',
+ },
+ NewCollatorLicenseBond: {
+ bondCost: 'Option<u128>',
+ },
+ NewCollatorKickThreshold: {
+ lengthInBlocks: 'Option<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup373: pallet_common::pallet::Event<T>
+ **/
+ PalletCommonEvent: {
+ _enum: {
+ CollectionCreated: '(u32,u8,AccountId32)',
+ CollectionDestroyed: 'u32',
+ ItemCreated: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
+ ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
+ Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
+ Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
+ ApprovedForAll: '(u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,bool)',
+ CollectionPropertySet: '(u32,Bytes)',
+ CollectionPropertyDeleted: '(u32,Bytes)',
+ TokenPropertySet: '(u32,u32,Bytes)',
+ TokenPropertyDeleted: '(u32,u32,Bytes)',
+ PropertyPermissionSet: '(u32,Bytes)',
+ AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+ AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+ CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+ CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+ CollectionLimitSet: 'u32',
+ CollectionOwnerChanged: '(u32,AccountId32)',
+ CollectionPermissionSet: 'u32',
+ CollectionSponsorSet: '(u32,AccountId32)',
+ SponsorshipConfirmed: '(u32,AccountId32)',
+ CollectionSponsorRemoved: 'u32'
+ }
+ },
+ /**
+ * Lookup374: pallet_structure::pallet::Event<T>
+ **/
+ PalletStructureEvent: {
+ _enum: {
+ Executed: 'Result<Null, SpRuntimeDispatchError>'
+ }
+ },
+ /**
+ * Lookup375: pallet_app_promotion::pallet::Event<T>
+ **/
+ PalletAppPromotionEvent: {
+ _enum: {
+ StakingRecalculation: '(AccountId32,u128,u128)',
+ Stake: '(AccountId32,u128)',
+ Unstake: '(AccountId32,u128)',
+ SetAdmin: 'AccountId32'
+ }
+ },
+ /**
+ * Lookup376: pallet_foreign_assets::module::Event<T>
+ **/
+ PalletForeignAssetsModuleEvent: {
+ _enum: {
+ ForeignAssetRegistered: {
+ assetId: 'u32',
+ assetAddress: 'StagingXcmV3MultiLocation',
+ metadata: 'PalletForeignAssetsModuleAssetMetadata',
+ },
+ ForeignAssetUpdated: {
+ assetId: 'u32',
+ assetAddress: 'StagingXcmV3MultiLocation',
+ metadata: 'PalletForeignAssetsModuleAssetMetadata',
+ },
+ AssetRegistered: {
+ assetId: 'PalletForeignAssetsAssetId',
+ metadata: 'PalletForeignAssetsModuleAssetMetadata',
+ },
+ AssetUpdated: {
+ assetId: 'PalletForeignAssetsAssetId',
+ metadata: 'PalletForeignAssetsModuleAssetMetadata'
+ }
+ }
+ },
+ /**
+ * Lookup377: pallet_evm::pallet::Event<T>
+ **/
+ PalletEvmEvent: {
+ _enum: {
+ Log: {
+ log: 'EthereumLog',
+ },
+ Created: {
+ address: 'H160',
+ },
+ CreatedFailed: {
+ address: 'H160',
+ },
+ Executed: {
+ address: 'H160',
+ },
+ ExecutedFailed: {
+ address: 'H160'
+ }
+ }
+ },
+ /**
+ * Lookup378: pallet_ethereum::pallet::Event
+ **/
+ PalletEthereumEvent: {
+ _enum: {
+ Executed: {
+ from: 'H160',
+ to: 'H160',
+ transactionHash: 'H256',
+ exitReason: 'EvmCoreErrorExitReason',
+ extraData: 'Bytes'
+ }
+ }
+ },
+ /**
+ * Lookup379: evm_core::error::ExitReason
+ **/
+ EvmCoreErrorExitReason: {
+ _enum: {
+ Succeed: 'EvmCoreErrorExitSucceed',
+ Error: 'EvmCoreErrorExitError',
+ Revert: 'EvmCoreErrorExitRevert',
+ Fatal: 'EvmCoreErrorExitFatal'
+ }
+ },
+ /**
+ * Lookup380: evm_core::error::ExitSucceed
+ **/
+ EvmCoreErrorExitSucceed: {
+ _enum: ['Stopped', 'Returned', 'Suicided']
+ },
+ /**
+ * Lookup381: evm_core::error::ExitError
+ **/
+ EvmCoreErrorExitError: {
+ _enum: {
+ StackUnderflow: 'Null',
+ StackOverflow: 'Null',
+ InvalidJump: 'Null',
+ InvalidRange: 'Null',
+ DesignatedInvalid: 'Null',
+ CallTooDeep: 'Null',
+ CreateCollision: 'Null',
+ CreateContractLimit: 'Null',
+ OutOfOffset: 'Null',
+ OutOfGas: 'Null',
+ OutOfFund: 'Null',
+ PCUnderflow: 'Null',
+ CreateEmpty: 'Null',
+ Other: 'Text',
+ MaxNonce: 'Null',
+ InvalidCode: 'u8'
+ }
+ },
+ /**
+ * Lookup385: evm_core::error::ExitRevert
+ **/
+ EvmCoreErrorExitRevert: {
+ _enum: ['Reverted']
+ },
+ /**
+ * Lookup386: evm_core::error::ExitFatal
+ **/
+ EvmCoreErrorExitFatal: {
+ _enum: {
+ NotSupported: 'Null',
+ UnhandledInterrupt: 'Null',
+ CallErrorAsFatal: 'EvmCoreErrorExitError',
+ Other: 'Text'
+ }
+ },
+ /**
+ * Lookup387: pallet_evm_contract_helpers::pallet::Event<T>
+ **/
+ PalletEvmContractHelpersEvent: {
+ _enum: {
+ ContractSponsorSet: '(H160,AccountId32)',
+ ContractSponsorshipConfirmed: '(H160,AccountId32)',
+ ContractSponsorRemoved: 'H160'
+ }
+ },
+ /**
+ * Lookup388: pallet_evm_migration::pallet::Event<T>
+ **/
+ PalletEvmMigrationEvent: {
+ _enum: ['TestEvent']
+ },
+ /**
+ * Lookup389: pallet_maintenance::pallet::Event<T>
+ **/
+ PalletMaintenanceEvent: {
+ _enum: ['MaintenanceEnabled', 'MaintenanceDisabled']
+ },
+ /**
+ * Lookup390: pallet_utility::pallet::Event
+ **/
+ PalletUtilityEvent: {
+ _enum: {
+ BatchInterrupted: {
+ index: 'u32',
+ error: 'SpRuntimeDispatchError',
+ },
+ BatchCompleted: 'Null',
+ BatchCompletedWithErrors: 'Null',
+ ItemCompleted: 'Null',
+ ItemFailed: {
+ error: 'SpRuntimeDispatchError',
+ },
+ DispatchedAs: {
+ result: 'Result<Null, SpRuntimeDispatchError>'
+ }
+ }
+ },
+ /**
+ * Lookup391: pallet_test_utils::pallet::Event<T>
+ **/
+ PalletTestUtilsEvent: {
+ _enum: ['ValueIsSet', 'ShouldRollback', 'BatchCompleted']
+ },
+ /**
+ * Lookup392: frame_system::Phase
+ **/
+ FrameSystemPhase: {
+ _enum: {
+ ApplyExtrinsic: 'u32',
+ Finalization: 'Null',
+ Initialization: 'Null'
+ }
+ },
+ /**
+ * Lookup394: frame_system::LastRuntimeUpgradeInfo
+ **/
+ FrameSystemLastRuntimeUpgradeInfo: {
+ specVersion: 'Compact<u32>',
+ specName: 'Text'
+ },
+ /**
+ * Lookup395: frame_system::limits::BlockWeights
+ **/
+ FrameSystemLimitsBlockWeights: {
+ baseBlock: 'SpWeightsWeightV2Weight',
+ maxBlock: 'SpWeightsWeightV2Weight',
+ perClass: 'FrameSupportDispatchPerDispatchClassWeightsPerClass'
+ },
+ /**
+ * Lookup396: frame_support::dispatch::PerDispatchClass<frame_system::limits::WeightsPerClass>
+ **/
+ FrameSupportDispatchPerDispatchClassWeightsPerClass: {
+ normal: 'FrameSystemLimitsWeightsPerClass',
+ operational: 'FrameSystemLimitsWeightsPerClass',
+ mandatory: 'FrameSystemLimitsWeightsPerClass'
+ },
+ /**
+ * Lookup397: frame_system::limits::WeightsPerClass
+ **/
+ FrameSystemLimitsWeightsPerClass: {
+ baseExtrinsic: 'SpWeightsWeightV2Weight',
+ maxExtrinsic: 'Option<SpWeightsWeightV2Weight>',
+ maxTotal: 'Option<SpWeightsWeightV2Weight>',
+ reserved: 'Option<SpWeightsWeightV2Weight>'
+ },
+ /**
+ * Lookup399: frame_system::limits::BlockLength
+ **/
+ FrameSystemLimitsBlockLength: {
+ max: 'FrameSupportDispatchPerDispatchClassU32'
+ },
+ /**
+ * Lookup400: frame_support::dispatch::PerDispatchClass<T>
+ **/
+ FrameSupportDispatchPerDispatchClassU32: {
+ normal: 'u32',
+ operational: 'u32',
+ mandatory: 'u32'
+ },
+ /**
+ * Lookup401: sp_weights::RuntimeDbWeight
+ **/
+ SpWeightsRuntimeDbWeight: {
+ read: 'u64',
+ write: 'u64'
+ },
+ /**
+ * Lookup402: sp_version::RuntimeVersion
+ **/
+ SpVersionRuntimeVersion: {
+ specName: 'Text',
+ implName: 'Text',
+ authoringVersion: 'u32',
+ specVersion: 'u32',
+ implVersion: 'u32',
+ apis: 'Vec<([u8;8],u32)>',
+ transactionVersion: 'u32',
+ stateVersion: 'u8'
+ },
+ /**
+ * Lookup406: frame_system::pallet::Error<T>
+ **/
+ FrameSystemError: {
+ _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
+ },
+ /**
+ * Lookup408: cumulus_pallet_parachain_system::unincluded_segment::Ancestor<primitive_types::H256>
+ **/
+ CumulusPalletParachainSystemUnincludedSegmentAncestor: {
+ usedBandwidth: 'CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth',
+ paraHeadHash: 'Option<H256>',
+ consumedGoAheadSignal: 'Option<PolkadotPrimitivesV5UpgradeGoAhead>'
+ },
+ /**
+ * Lookup409: cumulus_pallet_parachain_system::unincluded_segment::UsedBandwidth
+ **/
+ CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth: {
+ umpMsgCount: 'u32',
+ umpTotalBytes: 'u32',
+ hrmpOutgoing: 'BTreeMap<u32, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate>'
+ },
+ /**
+ * Lookup411: cumulus_pallet_parachain_system::unincluded_segment::HrmpChannelUpdate
+ **/
+ CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate: {
+ msgCount: 'u32',
+ totalBytes: 'u32'
+ },
+ /**
+ * Lookup415: polkadot_primitives::v5::UpgradeGoAhead
+ **/
+ PolkadotPrimitivesV5UpgradeGoAhead: {
+ _enum: ['Abort', 'GoAhead']
+ },
+ /**
+ * Lookup416: cumulus_pallet_parachain_system::unincluded_segment::SegmentTracker<primitive_types::H256>
+ **/
+ CumulusPalletParachainSystemUnincludedSegmentSegmentTracker: {
+ usedBandwidth: 'CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth',
+ hrmpWatermark: 'Option<u32>',
+ consumedGoAheadSignal: 'Option<PolkadotPrimitivesV5UpgradeGoAhead>'
+ },
+ /**
+ * Lookup418: polkadot_primitives::v5::UpgradeRestriction
+ **/
+ PolkadotPrimitivesV5UpgradeRestriction: {
+ _enum: ['Present']
+ },
+ /**
+ * Lookup419: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
+ **/
+ CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {
+ dmqMqcHead: 'H256',
+ relayDispatchQueueRemainingCapacity: 'CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity',
+ ingressChannels: 'Vec<(u32,PolkadotPrimitivesV5AbridgedHrmpChannel)>',
+ egressChannels: 'Vec<(u32,PolkadotPrimitivesV5AbridgedHrmpChannel)>'
+ },
+ /**
+ * Lookup420: cumulus_pallet_parachain_system::relay_state_snapshot::RelayDispatchQueueRemainingCapacity
+ **/
+ CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity: {
+ remainingCount: 'u32',
+ remainingSize: 'u32'
+ },
+ /**
+ * Lookup423: polkadot_primitives::v5::AbridgedHrmpChannel
+ **/
+ PolkadotPrimitivesV5AbridgedHrmpChannel: {
+ maxCapacity: 'u32',
+ maxTotalSize: 'u32',
+ maxMessageSize: 'u32',
+ msgCount: 'u32',
+ totalSize: 'u32',
+ mqcHead: 'Option<H256>'
+ },
+ /**
+ * Lookup424: polkadot_primitives::v5::AbridgedHostConfiguration
+ **/
+ PolkadotPrimitivesV5AbridgedHostConfiguration: {
+ maxCodeSize: 'u32',
+ maxHeadDataSize: 'u32',
+ maxUpwardQueueCount: 'u32',
+ maxUpwardQueueSize: 'u32',
+ maxUpwardMessageSize: 'u32',
+ maxUpwardMessageNumPerCandidate: 'u32',
+ hrmpMaxMessageNumPerCandidate: 'u32',
+ validationUpgradeCooldown: 'u32',
+ validationUpgradeDelay: 'u32',
+ asyncBackingParams: 'PolkadotPrimitivesVstagingAsyncBackingParams'
+ },
+ /**
+ * Lookup425: polkadot_primitives::vstaging::AsyncBackingParams
+ **/
+ PolkadotPrimitivesVstagingAsyncBackingParams: {
+ maxCandidateDepth: 'u32',
+ allowedAncestryLen: 'u32'
+ },
+ /**
+ * Lookup431: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain_primitives::primitives::Id>
+ **/
+ PolkadotCorePrimitivesOutboundHrmpMessage: {
+ recipient: 'u32',
+ data: 'Bytes'
+ },
+ /**
+ * Lookup432: cumulus_pallet_parachain_system::CodeUpgradeAuthorization<T>
+ **/
+ CumulusPalletParachainSystemCodeUpgradeAuthorization: {
+ codeHash: 'H256',
+ checkVersion: 'bool'
+ },
+ /**
+ * Lookup433: cumulus_pallet_parachain_system::pallet::Error<T>
+ **/
+ CumulusPalletParachainSystemError: {
+ _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']
+ },
+ /**
+ * Lookup435: pallet_collator_selection::pallet::Error<T>
+ **/
+ PalletCollatorSelectionError: {
+ _enum: ['TooManyCandidates', 'Unknown', 'Permission', 'AlreadyHoldingLicense', 'NoLicense', 'AlreadyCandidate', 'NotCandidate', 'TooManyInvulnerables', 'TooFewInvulnerables', 'AlreadyInvulnerable', 'NotInvulnerable', 'NoAssociatedValidatorId', 'ValidatorNotRegistered']
+ },
+ /**
+ * Lookup439: sp_core::crypto::KeyTypeId
+ **/
+ SpCoreCryptoKeyTypeId: '[u8;4]',
+ /**
+ * Lookup440: pallet_session::pallet::Error<T>
+ **/
+ PalletSessionError: {
+ _enum: ['InvalidProof', 'NoAssociatedValidatorId', 'DuplicatedKey', 'NoKeys', 'NoAccount']
+ },
+ /**
+ * Lookup446: pallet_balances::types::BalanceLock<Balance>
+ **/
+ PalletBalancesBalanceLock: {
+ id: '[u8;8]',
+ amount: 'u128',
+ reasons: 'PalletBalancesReasons'
+ },
+ /**
+ * Lookup447: pallet_balances::types::Reasons
+ **/
+ PalletBalancesReasons: {
+ _enum: ['Fee', 'Misc', 'All']
+ },
+ /**
+ * Lookup450: pallet_balances::types::ReserveData<ReserveIdentifier, Balance>
+ **/
+ PalletBalancesReserveData: {
+ id: '[u8;16]',
+ amount: 'u128'
+ },
+ /**
+ * Lookup454: opal_runtime::RuntimeHoldReason
+ **/
+ OpalRuntimeRuntimeHoldReason: {
+ _enum: {
+ __Unused0: 'Null',
+ __Unused1: 'Null',
+ __Unused2: 'Null',
+ __Unused3: 'Null',
+ __Unused4: 'Null',
+ __Unused5: 'Null',
+ __Unused6: 'Null',
+ __Unused7: 'Null',
+ __Unused8: 'Null',
+ __Unused9: 'Null',
+ __Unused10: 'Null',
+ __Unused11: 'Null',
+ __Unused12: 'Null',
+ __Unused13: 'Null',
+ __Unused14: 'Null',
+ __Unused15: 'Null',
+ __Unused16: 'Null',
+ __Unused17: 'Null',
+ __Unused18: 'Null',
+ __Unused19: 'Null',
+ __Unused20: 'Null',
+ __Unused21: 'Null',
+ __Unused22: 'Null',
+ CollatorSelection: 'PalletCollatorSelectionHoldReason'
+ }
+ },
+ /**
+ * Lookup455: pallet_collator_selection::pallet::HoldReason
+ **/
+ PalletCollatorSelectionHoldReason: {
+ _enum: ['LicenseBond']
+ },
+ /**
+ * Lookup458: pallet_balances::types::IdAmount<Id, Balance>
+ **/
+ PalletBalancesIdAmount: {
+ id: '[u8;16]',
+ amount: 'u128'
+ },
+ /**
+ * Lookup460: pallet_balances::pallet::Error<T, I>
+ **/
+ PalletBalancesError: {
+ _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'Expendability', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves', 'TooManyHolds', 'TooManyFreezes']
+ },
+ /**
+ * Lookup462: pallet_transaction_payment::Releases
+ **/
+ PalletTransactionPaymentReleases: {
+ _enum: ['V1Ancient', 'V2']
+ },
+ /**
+ * Lookup463: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
+ **/
+ PalletTreasuryProposal: {
+ proposer: 'AccountId32',
+ value: 'u128',
+ beneficiary: 'AccountId32',
+ bond: 'u128'
+ },
+ /**
+ * Lookup466: frame_support::PalletId
+ **/
+ FrameSupportPalletId: '[u8;8]',
+ /**
+ * Lookup467: pallet_treasury::pallet::Error<T, I>
+ **/
+ PalletTreasuryError: {
+ _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'InsufficientPermission', 'ProposalNotApproved']
+ },
+ /**
+ * Lookup468: pallet_sudo::pallet::Error<T>
+ **/
+ PalletSudoError: {
+ _enum: ['RequireSudo']
+ },
+ /**
+ * Lookup470: orml_vesting::module::Error<T>
+ **/
+ OrmlVestingModuleError: {
+ _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
+ },
+ /**
+ * Lookup471: orml_xtokens::module::Error<T>
+ **/
+ OrmlXtokensModuleError: {
+ _enum: ['AssetHasNoReserve', 'NotCrossChainTransfer', 'InvalidDest', 'NotCrossChainTransferableCurrency', 'UnweighableMessage', 'XcmExecutionFailed', 'CannotReanchor', 'InvalidAncestry', 'InvalidAsset', 'DestinationNotInvertible', 'BadVersion', 'DistinctReserveForAssetAndFee', 'ZeroFee', 'ZeroAmount', 'TooManyAssetsBeingSent', 'AssetIndexNonExistent', 'FeeNotEnough', 'NotSupportedMultiLocation', 'MinXcmFeeNotDefined']
+ },
+ /**
+ * Lookup474: orml_tokens::BalanceLock<Balance>
+ **/
+ OrmlTokensBalanceLock: {
+ id: '[u8;8]',
+ amount: 'u128'
+ },
+ /**
+ * Lookup476: orml_tokens::AccountData<Balance>
+ **/
+ OrmlTokensAccountData: {
+ free: 'u128',
+ reserved: 'u128',
+ frozen: 'u128'
+ },
+ /**
+ * Lookup478: orml_tokens::ReserveData<ReserveIdentifier, Balance>
+ **/
+ OrmlTokensReserveData: {
+ id: 'Null',
+ amount: 'u128'
+ },
+ /**
+ * Lookup480: orml_tokens::module::Error<T>
+ **/
+ OrmlTokensModuleError: {
+ _enum: ['BalanceTooLow', 'AmountIntoBalanceFailed', 'LiquidityRestrictions', 'MaxLocksExceeded', 'KeepAlive', 'ExistentialDeposit', 'DeadAccount', 'TooManyReserves']
+ },
+ /**
+ * Lookup485: pallet_identity::types::RegistrarInfo<Balance, sp_core::crypto::AccountId32>
+ **/
+ PalletIdentityRegistrarInfo: {
+ account: 'AccountId32',
+ fee: 'u128',
+ fields: 'PalletIdentityBitFlags'
+ },
+ /**
+ * Lookup487: pallet_identity::pallet::Error<T>
+ **/
+ PalletIdentityError: {
+ _enum: ['TooManySubAccounts', 'NotFound', 'NotNamed', 'EmptyIndex', 'FeeChanged', 'NoIdentity', 'StickyJudgement', 'JudgementGiven', 'InvalidJudgement', 'InvalidIndex', 'InvalidTarget', 'TooManyFields', 'TooManyRegistrars', 'AlreadyClaimed', 'NotSub', 'NotOwned', 'JudgementForDifferentIdentity', 'JudgementPaymentFailed']
+ },
+ /**
+ * Lookup488: pallet_preimage::RequestStatus<sp_core::crypto::AccountId32, Balance>
+ **/
+ PalletPreimageRequestStatus: {
+ _enum: {
+ Unrequested: {
+ deposit: '(AccountId32,u128)',
+ len: 'u32',
+ },
+ Requested: {
+ deposit: 'Option<(AccountId32,u128)>',
+ count: 'u32',
+ len: 'Option<u32>'
+ }
+ }
+ },
+ /**
+ * Lookup493: pallet_preimage::pallet::Error<T>
+ **/
+ PalletPreimageError: {
+ _enum: ['TooBig', 'AlreadyNoted', 'NotAuthorized', 'NotNoted', 'Requested', 'NotRequested']
+ },
+ /**
+ * Lookup499: pallet_democracy::types::ReferendumInfo<BlockNumber, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance>
+ **/
+ PalletDemocracyReferendumInfo: {
+ _enum: {
+ Ongoing: 'PalletDemocracyReferendumStatus',
+ Finished: {
+ approved: 'bool',
+ end: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup500: pallet_democracy::types::ReferendumStatus<BlockNumber, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance>
+ **/
+ PalletDemocracyReferendumStatus: {
+ end: 'u32',
+ proposal: 'FrameSupportPreimagesBounded',
+ threshold: 'PalletDemocracyVoteThreshold',
+ delay: 'u32',
+ tally: 'PalletDemocracyTally'
+ },
+ /**
+ * Lookup501: pallet_democracy::types::Tally<Balance>
+ **/
+ PalletDemocracyTally: {
+ ayes: 'u128',
+ nays: 'u128',
+ turnout: 'u128'
+ },
+ /**
+ * Lookup502: pallet_democracy::vote::Voting<Balance, sp_core::crypto::AccountId32, BlockNumber, MaxVotes>
+ **/
+ PalletDemocracyVoteVoting: {
+ _enum: {
+ Direct: {
+ votes: 'Vec<(u32,PalletDemocracyVoteAccountVote)>',
+ delegations: 'PalletDemocracyDelegations',
+ prior: 'PalletDemocracyVotePriorLock',
+ },
+ Delegating: {
+ balance: 'u128',
+ target: 'AccountId32',
+ conviction: 'PalletDemocracyConviction',
+ delegations: 'PalletDemocracyDelegations',
+ prior: 'PalletDemocracyVotePriorLock'
+ }
+ }
+ },
+ /**
+ * Lookup506: pallet_democracy::types::Delegations<Balance>
+ **/
+ PalletDemocracyDelegations: {
+ votes: 'u128',
+ capital: 'u128'
+ },
+ /**
+ * Lookup507: pallet_democracy::vote::PriorLock<BlockNumber, Balance>
+ **/
+ PalletDemocracyVotePriorLock: '(u32,u128)',
+ /**
+ * Lookup510: pallet_democracy::pallet::Error<T>
+ **/
+ PalletDemocracyError: {
+ _enum: ['ValueLow', 'ProposalMissing', 'AlreadyCanceled', 'DuplicateProposal', 'ProposalBlacklisted', 'NotSimpleMajority', 'InvalidHash', 'NoProposal', 'AlreadyVetoed', 'ReferendumInvalid', 'NoneWaiting', 'NotVoter', 'NoPermission', 'AlreadyDelegating', 'InsufficientFunds', 'NotDelegating', 'VotesExist', 'InstantNotAllowed', 'Nonsense', 'WrongUpperBound', 'MaxVotesReached', 'TooMany', 'VotingPeriodLow', 'PreimageNotExist']
+ },
+ /**
+ * Lookup512: pallet_collective::Votes<sp_core::crypto::AccountId32, BlockNumber>
+ **/
+ PalletCollectiveVotes: {
+ index: 'u32',
+ threshold: 'u32',
+ ayes: 'Vec<AccountId32>',
+ nays: 'Vec<AccountId32>',
+ end: 'u32'
+ },
+ /**
+ * Lookup513: pallet_collective::pallet::Error<T, I>
+ **/
+ PalletCollectiveError: {
+ _enum: ['NotMember', 'DuplicateProposal', 'ProposalMissing', 'WrongIndex', 'DuplicateVote', 'AlreadyInitialized', 'TooEarly', 'TooManyProposals', 'WrongProposalWeight', 'WrongProposalLength', 'PrimeAccountNotMember']
+ },
+ /**
+ * Lookup517: pallet_membership::pallet::Error<T, I>
+ **/
+ PalletMembershipError: {
+ _enum: ['AlreadyMember', 'NotMember', 'TooManyMembers']
+ },
+ /**
+ * Lookup520: pallet_ranked_collective::MemberRecord
+ **/
+ PalletRankedCollectiveMemberRecord: {
+ rank: 'u16'
+ },
+ /**
+ * Lookup525: pallet_ranked_collective::pallet::Error<T, I>
+ **/
+ PalletRankedCollectiveError: {
+ _enum: ['AlreadyMember', 'NotMember', 'NotPolling', 'Ongoing', 'NoneRemaining', 'Corruption', 'RankTooLow', 'InvalidWitness', 'NoPermission']
+ },
+ /**
+ * Lookup526: pallet_referenda::types::ReferendumInfo<TrackId, opal_runtime::OriginCaller, Moment, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance, pallet_ranked_collective::Tally<T, I, M>, sp_core::crypto::AccountId32, ScheduleAddress>
+ **/
+ PalletReferendaReferendumInfo: {
+ _enum: {
+ Ongoing: 'PalletReferendaReferendumStatus',
+ Approved: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
+ Rejected: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
+ Cancelled: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
+ TimedOut: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
+ Killed: 'u32'
+ }
+ },
+ /**
+ * Lookup527: pallet_referenda::types::ReferendumStatus<TrackId, opal_runtime::OriginCaller, Moment, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance, pallet_ranked_collective::Tally<T, I, M>, sp_core::crypto::AccountId32, ScheduleAddress>
+ **/
+ PalletReferendaReferendumStatus: {
+ track: 'u16',
+ origin: 'OpalRuntimeOriginCaller',
+ proposal: 'FrameSupportPreimagesBounded',
+ enactment: 'FrameSupportScheduleDispatchTime',
+ submitted: 'u32',
+ submissionDeposit: 'PalletReferendaDeposit',
+ decisionDeposit: 'Option<PalletReferendaDeposit>',
+ deciding: 'Option<PalletReferendaDecidingStatus>',
+ tally: 'PalletRankedCollectiveTally',
+ inQueue: 'bool',
+ alarm: 'Option<(u32,(u32,u32))>'
+ },
+ /**
+ * Lookup528: pallet_referenda::types::Deposit<sp_core::crypto::AccountId32, Balance>
+ **/
+ PalletReferendaDeposit: {
+ who: 'AccountId32',
+ amount: 'u128'
+ },
+ /**
+ * Lookup531: pallet_referenda::types::DecidingStatus<BlockNumber>
+ **/
+ PalletReferendaDecidingStatus: {
+ since: 'u32',
+ confirming: 'Option<u32>'
+ },
+ /**
+ * Lookup537: pallet_referenda::types::TrackInfo<Balance, Moment>
+ **/
+ PalletReferendaTrackInfo: {
+ name: 'Text',
+ maxDeciding: 'u32',
+ decisionDeposit: 'u128',
+ preparePeriod: 'u32',
+ decisionPeriod: 'u32',
+ confirmPeriod: 'u32',
+ minEnactmentPeriod: 'u32',
+ minApproval: 'PalletReferendaCurve',
+ minSupport: 'PalletReferendaCurve'
+ },
+ /**
+ * Lookup538: pallet_referenda::types::Curve
+ **/
+ PalletReferendaCurve: {
+ _enum: {
+ LinearDecreasing: {
+ length: 'Perbill',
+ floor: 'Perbill',
+ ceil: 'Perbill',
+ },
+ SteppedDecreasing: {
+ begin: 'Perbill',
+ end: 'Perbill',
+ step: 'Perbill',
+ period: 'Perbill',
+ },
+ Reciprocal: {
+ factor: 'i64',
+ xOffset: 'i64',
+ yOffset: 'i64'
+ }
+ }
+ },
+ /**
+ * Lookup541: pallet_referenda::pallet::Error<T, I>
+ **/
+ PalletReferendaError: {
+ _enum: ['NotOngoing', 'HasDeposit', 'BadTrack', 'Full', 'QueueEmpty', 'BadReferendum', 'NothingToDo', 'NoTrack', 'Unfinished', 'NoPermission', 'NoDeposit', 'BadStatus', 'PreimageNotExist']
+ },
+ /**
+ * Lookup544: pallet_scheduler::Scheduled<Name, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
+ **/
+ PalletSchedulerScheduled: {
+ maybeId: 'Option<[u8;32]>',
+ priority: 'u8',
+ call: 'FrameSupportPreimagesBounded',
+ maybePeriodic: 'Option<(u32,u32)>',
+ origin: 'OpalRuntimeOriginCaller'
+ },
+ /**
+ * Lookup546: pallet_scheduler::pallet::Error<T>
+ **/
+ PalletSchedulerError: {
+ _enum: ['FailedToSchedule', 'NotFound', 'TargetBlockNumberInPast', 'RescheduleNoChange', 'Named']
+ },
+ /**
+ * Lookup548: cumulus_pallet_xcmp_queue::InboundChannelDetails
+ **/
+ CumulusPalletXcmpQueueInboundChannelDetails: {
+ sender: 'u32',
+ state: 'CumulusPalletXcmpQueueInboundState',
+ messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat)>'
+ },
+ /**
+ * Lookup549: cumulus_pallet_xcmp_queue::InboundState
+ **/
+ CumulusPalletXcmpQueueInboundState: {
+ _enum: ['Ok', 'Suspended']
+ },
+ /**
+ * Lookup552: polkadot_parachain_primitives::primitives::XcmpMessageFormat
+ **/
+ PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat: {
+ _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
+ },
+ /**
+ * Lookup555: cumulus_pallet_xcmp_queue::OutboundChannelDetails
+ **/
+ CumulusPalletXcmpQueueOutboundChannelDetails: {
+ recipient: 'u32',
+ state: 'CumulusPalletXcmpQueueOutboundState',
+ signalsExist: 'bool',
+ firstIndex: 'u16',
+ lastIndex: 'u16'
+ },
+ /**
+ * Lookup556: cumulus_pallet_xcmp_queue::OutboundState
+ **/
+ CumulusPalletXcmpQueueOutboundState: {
+ _enum: ['Ok', 'Suspended']
+ },
+ /**
+ * Lookup558: cumulus_pallet_xcmp_queue::QueueConfigData
+ **/
+ CumulusPalletXcmpQueueQueueConfigData: {
+ suspendThreshold: 'u32',
+ dropThreshold: 'u32',
+ resumeThreshold: 'u32',
+ thresholdWeight: 'SpWeightsWeightV2Weight',
+ weightRestrictDecay: 'SpWeightsWeightV2Weight',
+ xcmpMaxIndividualWeight: 'SpWeightsWeightV2Weight'
+ },
+ /**
+ * Lookup560: cumulus_pallet_xcmp_queue::pallet::Error<T>
+ **/
+ CumulusPalletXcmpQueueError: {
+ _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
+ },
+ /**
+ * Lookup561: pallet_xcm::pallet::QueryStatus<BlockNumber>
+ **/
+ PalletXcmQueryStatus: {
+ _enum: {
+ Pending: {
+ responder: 'StagingXcmVersionedMultiLocation',
+ maybeMatchQuerier: 'Option<StagingXcmVersionedMultiLocation>',
+ maybeNotify: 'Option<(u8,u8)>',
+ timeout: 'u32',
+ },
+ VersionNotifier: {
+ origin: 'StagingXcmVersionedMultiLocation',
+ isActive: 'bool',
+ },
+ Ready: {
+ response: 'StagingXcmVersionedResponse',
+ at: 'u32'
+ }
+ }
+ },
+ /**
+ * Lookup565: staging_xcm::VersionedResponse
+ **/
+ StagingXcmVersionedResponse: {
+ _enum: {
+ __Unused0: 'Null',
+ __Unused1: 'Null',
+ V2: 'StagingXcmV2Response',
+ V3: 'StagingXcmV3Response'
+ }
+ },
+ /**
+ * Lookup571: pallet_xcm::pallet::VersionMigrationStage
+ **/
+ PalletXcmVersionMigrationStage: {
+ _enum: {
+ MigrateSupportedVersion: 'Null',
+ MigrateVersionNotifiers: 'Null',
+ NotifyCurrentTargets: 'Option<Bytes>',
+ MigrateAndNotifyOldTargets: 'Null'
+ }
+ },
+ /**
+ * Lookup574: staging_xcm::VersionedAssetId
+ **/
+ StagingXcmVersionedAssetId: {
+ _enum: {
+ __Unused0: 'Null',
+ __Unused1: 'Null',
+ __Unused2: 'Null',
+ V3: 'StagingXcmV3MultiassetAssetId'
+ }
+ },
+ /**
+ * Lookup575: pallet_xcm::pallet::RemoteLockedFungibleRecord<ConsumerIdentifier, MaxConsumers>
+ **/
+ PalletXcmRemoteLockedFungibleRecord: {
+ amount: 'u128',
+ owner: 'StagingXcmVersionedMultiLocation',
+ locker: 'StagingXcmVersionedMultiLocation',
+ consumers: 'Vec<(Null,u128)>'
+ },
+ /**
+ * Lookup582: pallet_xcm::pallet::Error<T>
+ **/
+ PalletXcmError: {
+ _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed', 'InvalidAsset', 'LowBalance', 'TooManyLocks', 'AccountNotSovereign', 'FeesNotMet', 'LockNotFound', 'InUse']
+ },
+ /**
+ * Lookup583: cumulus_pallet_xcm::pallet::Error<T>
+ **/
+ CumulusPalletXcmError: 'Null',
+ /**
+ * Lookup584: cumulus_pallet_dmp_queue::ConfigData
+ **/
+ CumulusPalletDmpQueueConfigData: {
+ maxIndividual: 'SpWeightsWeightV2Weight'
+ },
+ /**
+ * Lookup585: cumulus_pallet_dmp_queue::PageIndexData
+ **/
+ CumulusPalletDmpQueuePageIndexData: {
+ beginUsed: 'u32',
+ endUsed: 'u32',
+ overweightCount: 'u64'
+ },
+ /**
+ * Lookup588: cumulus_pallet_dmp_queue::pallet::Error<T>
+ **/
+ CumulusPalletDmpQueueError: {
+ _enum: ['Unknown', 'OverLimit']
+ },
+ /**
+ * Lookup592: pallet_unique::pallet::Error<T>
+ **/
+ PalletUniqueError: {
+ _enum: ['CollectionDecimalPointLimitExceeded', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']
+ },
+ /**
+ * Lookup593: pallet_configuration::pallet::Error<T>
+ **/
+ PalletConfigurationError: {
+ _enum: ['InconsistentConfiguration']
+ },
+ /**
+ * Lookup594: up_data_structs::Collection<sp_core::crypto::AccountId32>
+ **/
+ UpDataStructsCollection: {
+ owner: 'AccountId32',
+ mode: 'UpDataStructsCollectionMode',
+ name: 'Vec<u16>',
+ description: 'Vec<u16>',
+ tokenPrefix: 'Bytes',
+ sponsorship: 'UpDataStructsSponsorshipStateAccountId32',
+ limits: 'UpDataStructsCollectionLimits',
+ permissions: 'UpDataStructsCollectionPermissions',
+ flags: '[u8;1]'
+ },
+ /**
+ * Lookup595: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
+ **/
+ UpDataStructsSponsorshipStateAccountId32: {
+ _enum: {
+ Disabled: 'Null',
+ Unconfirmed: 'AccountId32',
+ Confirmed: 'AccountId32'
+ }
+ },
+ /**
+ * Lookup596: up_data_structs::Properties
+ **/
+ UpDataStructsProperties: {
+ map: 'UpDataStructsPropertiesMapBoundedVec',
+ consumedSpace: 'u32',
+ reserved: 'u32'
+ },
+ /**
+ * Lookup597: up_data_structs::PropertiesMap<bounded_collections::bounded_vec::BoundedVec<T, S>>
+ **/
+ UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
+ /**
+ * Lookup602: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
+ **/
+ UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
+ /**
+ * Lookup609: up_data_structs::CollectionStats
+ **/
+ UpDataStructsCollectionStats: {
+ created: 'u32',
+ destroyed: 'u32',
+ alive: 'u32'
+ },
+ /**
+ * Lookup610: up_data_structs::TokenChild
+ **/
+ UpDataStructsTokenChild: {
+ token: 'u32',
+ collection: 'u32'
+ },
+ /**
+ * Lookup611: PhantomType::up_data_structs<T>
+ **/
+ PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,UpPovEstimateRpcPovInfo);0]',
+ /**
+ * Lookup613: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsTokenData: {
+ properties: 'Vec<UpDataStructsProperty>',
+ owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>',
+ pieces: 'u128'
+ },
+ /**
+ * Lookup614: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+ **/
+ UpDataStructsRpcCollection: {
+ owner: 'AccountId32',
+ mode: 'UpDataStructsCollectionMode',
+ name: 'Vec<u16>',
+ description: 'Vec<u16>',
+ tokenPrefix: 'Bytes',
+ sponsorship: 'UpDataStructsSponsorshipStateAccountId32',
+ limits: 'UpDataStructsCollectionLimits',
+ permissions: 'UpDataStructsCollectionPermissions',
+ tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
+ properties: 'Vec<UpDataStructsProperty>',
+ readOnly: 'bool',
+ flags: 'UpDataStructsRpcCollectionFlags'
+ },
+ /**
+ * Lookup615: up_data_structs::RpcCollectionFlags
+ **/
+ UpDataStructsRpcCollectionFlags: {
+ foreign: 'bool',
+ erc721metadata: 'bool'
+ },
+ /**
+ * Lookup616: up_pov_estimate_rpc::PovInfo
+ **/
+ UpPovEstimateRpcPovInfo: {
+ proofSize: 'u64',
+ compactProofSize: 'u64',
+ compressedProofSize: 'u64',
+ results: 'Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>',
+ keyValues: 'Vec<UpPovEstimateRpcTrieKeyValue>'
+ },
+ /**
+ * Lookup619: sp_runtime::transaction_validity::TransactionValidityError
+ **/
+ SpRuntimeTransactionValidityTransactionValidityError: {
+ _enum: {
+ Invalid: 'SpRuntimeTransactionValidityInvalidTransaction',
+ Unknown: 'SpRuntimeTransactionValidityUnknownTransaction'
+ }
+ },
+ /**
+ * Lookup620: sp_runtime::transaction_validity::InvalidTransaction
+ **/
+ SpRuntimeTransactionValidityInvalidTransaction: {
+ _enum: {
+ Call: 'Null',
+ Payment: 'Null',
+ Future: 'Null',
+ Stale: 'Null',
+ BadProof: 'Null',
+ AncientBirthBlock: 'Null',
+ ExhaustsResources: 'Null',
+ Custom: 'u8',
+ BadMandatory: 'Null',
+ MandatoryValidation: 'Null',
+ BadSigner: 'Null'
+ }
+ },
+ /**
+ * Lookup621: sp_runtime::transaction_validity::UnknownTransaction
+ **/
+ SpRuntimeTransactionValidityUnknownTransaction: {
+ _enum: {
+ CannotLookup: 'Null',
+ NoUnsignedValidator: 'Null',
+ Custom: 'u8'
+ }
+ },
+ /**
+ * Lookup623: up_pov_estimate_rpc::TrieKeyValue
+ **/
+ UpPovEstimateRpcTrieKeyValue: {
+ key: 'Bytes',
+ value: 'Bytes'
+ },
+ /**
+ * Lookup625: pallet_common::pallet::Error<T>
+ **/
+ PalletCommonError: {
+ _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsNotEthMirror', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal', 'ConfirmSponsorshipFail', 'UserIsNotCollectionAdmin', 'FungibleItemsHaveNoId']
+ },
+ /**
+ * Lookup627: pallet_fungible::pallet::Error<T>
+ **/
+ PalletFungibleError: {
+ _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingAllowanceForAllNotAllowed', 'FungibleTokensAreAlwaysValid']
+ },
+ /**
+ * Lookup632: pallet_refungible::pallet::Error<T>
+ **/
+ PalletRefungibleError: {
+ _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
+ },
+ /**
+ * Lookup633: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ PalletNonfungibleItemData: {
+ owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
+ },
+ /**
+ * Lookup635: up_data_structs::PropertyScope
+ **/
+ UpDataStructsPropertyScope: {
+ _enum: ['None', 'Rmrk']
+ },
+ /**
+ * Lookup638: pallet_nonfungible::pallet::Error<T>
+ **/
+ PalletNonfungibleError: {
+ _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
+ },
+ /**
+ * Lookup639: pallet_structure::pallet::Error<T>
+ **/
+ PalletStructureError: {
+ _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound', 'CantNestTokenUnderCollection']
+ },
+ /**
+ * Lookup644: pallet_app_promotion::pallet::Error<T>
+ **/
+ PalletAppPromotionError: {
+ _enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'InsufficientStakedBalance', 'InconsistencyState']
+ },
+ /**
+ * Lookup645: pallet_foreign_assets::module::Error<T>
+ **/
+ PalletForeignAssetsModuleError: {
+ _enum: ['BadLocation', 'MultiLocationExisted', 'AssetIdNotExists', 'AssetIdExisted']
+ },
+ /**
+ * Lookup646: pallet_evm::CodeMetadata
+ **/
+ PalletEvmCodeMetadata: {
+ _alias: {
+ size_: 'size',
+ hash_: 'hash'
+ },
+ size_: 'u64',
+ hash_: 'H256'
+ },
+ /**
+ * Lookup648: pallet_evm::pallet::Error<T>
+ **/
+ PalletEvmError: {
+ _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce', 'GasLimitTooLow', 'GasLimitTooHigh', 'Undefined', 'Reentrancy', 'TransactionMustComeFromEOA']
+ },
+ /**
+ * Lookup651: fp_rpc::TransactionStatus
+ **/
+ FpRpcTransactionStatus: {
+ transactionHash: 'H256',
+ transactionIndex: 'u32',
+ from: 'H160',
+ to: 'Option<H160>',
+ contractAddress: 'Option<H160>',
+ logs: 'Vec<EthereumLog>',
+ logsBloom: 'EthbloomBloom'
+ },
+ /**
+ * Lookup653: ethbloom::Bloom
+ **/
+ EthbloomBloom: '[u8;256]',
+ /**
+ * Lookup655: ethereum::receipt::ReceiptV3
+ **/
+ EthereumReceiptReceiptV3: {
+ _enum: {
+ Legacy: 'EthereumReceiptEip658ReceiptData',
+ EIP2930: 'EthereumReceiptEip658ReceiptData',
+ EIP1559: 'EthereumReceiptEip658ReceiptData'
+ }
+ },
+ /**
+ * Lookup656: ethereum::receipt::EIP658ReceiptData
+ **/
+ EthereumReceiptEip658ReceiptData: {
+ statusCode: 'u8',
+ usedGas: 'U256',
+ logsBloom: 'EthbloomBloom',
+ logs: 'Vec<EthereumLog>'
+ },
+ /**
+ * Lookup657: ethereum::block::Block<ethereum::transaction::TransactionV2>
+ **/
+ EthereumBlock: {
+ header: 'EthereumHeader',
+ transactions: 'Vec<EthereumTransactionTransactionV2>',
+ ommers: 'Vec<EthereumHeader>'
+ },
+ /**
+ * Lookup658: ethereum::header::Header
+ **/
+ EthereumHeader: {
+ parentHash: 'H256',
+ ommersHash: 'H256',
+ beneficiary: 'H160',
+ stateRoot: 'H256',
+ transactionsRoot: 'H256',
+ receiptsRoot: 'H256',
+ logsBloom: 'EthbloomBloom',
+ difficulty: 'U256',
+ number: 'U256',
+ gasLimit: 'U256',
+ gasUsed: 'U256',
+ timestamp: 'u64',
+ extraData: 'Bytes',
+ mixHash: 'H256',
+ nonce: 'EthereumTypesHashH64'
+ },
+ /**
+ * Lookup659: ethereum_types::hash::H64
+ **/
+ EthereumTypesHashH64: '[u8;8]',
+ /**
+ * Lookup664: pallet_ethereum::pallet::Error<T>
+ **/
+ PalletEthereumError: {
+ _enum: ['InvalidSignature', 'PreLogExists']
+ },
+ /**
+ * Lookup665: pallet_evm_coder_substrate::pallet::Error<T>
+ **/
+ PalletEvmCoderSubstrateError: {
+ _enum: ['OutOfGas', 'OutOfFund']
+ },
+ /**
+ * Lookup666: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ **/
+ UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: {
+ _enum: {
+ Disabled: 'Null',
+ Unconfirmed: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ Confirmed: 'PalletEvmAccountBasicCrossAccountIdRepr'
+ }
+ },
+ /**
+ * Lookup667: pallet_evm_contract_helpers::SponsoringModeT
+ **/
+ PalletEvmContractHelpersSponsoringModeT: {
+ _enum: ['Disabled', 'Allowlisted', 'Generous']
+ },
+ /**
+ * Lookup673: pallet_evm_contract_helpers::pallet::Error<T>
+ **/
+ PalletEvmContractHelpersError: {
+ _enum: ['NoPermission', 'NoPendingSponsor', 'TooManyMethodsHaveSponsoredLimit']
+ },
+ /**
+ * Lookup674: pallet_evm_migration::pallet::Error<T>
+ **/
+ PalletEvmMigrationError: {
+ _enum: ['AccountNotEmpty', 'AccountIsNotMigrating', 'BadEvent']
+ },
+ /**
+ * Lookup675: pallet_maintenance::pallet::Error<T>
+ **/
+ PalletMaintenanceError: 'Null',
+ /**
+ * Lookup676: pallet_utility::pallet::Error<T>
+ **/
+ PalletUtilityError: {
+ _enum: ['TooManyCalls']
+ },
+ /**
+ * Lookup677: pallet_test_utils::pallet::Error<T>
+ **/
+ PalletTestUtilsError: {
+ _enum: ['TestPalletDisabled', 'TriggerRollback']
+ },
+ /**
+ * Lookup679: sp_runtime::MultiSignature
+ **/
+ SpRuntimeMultiSignature: {
+ _enum: {
+ Ed25519: 'SpCoreEd25519Signature',
+ Sr25519: 'SpCoreSr25519Signature',
+ Ecdsa: 'SpCoreEcdsaSignature'
+ }
+ },
+ /**
+ * Lookup680: sp_core::ed25519::Signature
+ **/
+ SpCoreEd25519Signature: '[u8;64]',
+ /**
+ * Lookup682: sp_core::sr25519::Signature
+ **/
+ SpCoreSr25519Signature: '[u8;64]',
+ /**
+ * Lookup683: sp_core::ecdsa::Signature
+ **/
+ SpCoreEcdsaSignature: '[u8;65]',
+ /**
+ * Lookup686: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+ **/
+ FrameSystemExtensionsCheckSpecVersion: 'Null',
+ /**
+ * Lookup687: frame_system::extensions::check_tx_version::CheckTxVersion<T>
+ **/
+ FrameSystemExtensionsCheckTxVersion: 'Null',
+ /**
+ * Lookup688: frame_system::extensions::check_genesis::CheckGenesis<T>
+ **/
+ FrameSystemExtensionsCheckGenesis: 'Null',
+ /**
+ * Lookup691: frame_system::extensions::check_nonce::CheckNonce<T>
+ **/
+ FrameSystemExtensionsCheckNonce: 'Compact<u32>',
+ /**
+ * Lookup692: frame_system::extensions::check_weight::CheckWeight<T>
+ **/
+ FrameSystemExtensionsCheckWeight: 'Null',
+ /**
+ * Lookup693: opal_runtime::runtime_common::maintenance::CheckMaintenance
+ **/
+ OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: 'Null',
+ /**
+ * Lookup694: opal_runtime::runtime_common::identity::DisableIdentityCalls
+ **/
+ OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls: 'Null',
+ /**
+ * Lookup695: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+ **/
+ PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
+ /**
+ * Lookup696: opal_runtime::Runtime
+ **/
+ OpalRuntimeRuntime: 'Null',
+ /**
+ * Lookup697: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+ **/
+ PalletEthereumFakeTransactionFinalizer: 'Null'
+};
js-packages/types/package.jsondiffbeforeafterboth--- a/js-packages/types/package.json
+++ b/js-packages/types/package.json
@@ -9,8 +9,7 @@
"type": "module",
"version": "1.0.0",
"main": "index.js",
- "dependencies": {
- "rxjs": "^7.8.1",
- "tslib": "^2.6.2"
+ "devDependencies": {
+ "@polkadot/typegen": "^10.10.1"
}
}
js-packages/types/povinfo/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/povinfo/definitions.ts
@@ -0,0 +1,40 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+type RpcParam = {
+ name: string;
+ type: string;
+ isOptional?: true;
+};
+
+const atParam = {name: 'at', type: 'Hash', isOptional: true};
+
+const fun = (description: string, params: RpcParam[], type: string) => ({
+ description,
+ params: [...params, atParam],
+ type,
+});
+
+export default {
+ types: {},
+ rpc: {
+ estimateExtrinsicPoV: fun(
+ 'Estimate PoV size of encoded signed extrinsics',
+ [{name: 'encodedXt', type: 'Vec<Bytes>'}],
+ 'UpPovEstimateRpcPovInfo',
+ ),
+ },
+};
js-packages/types/povinfo/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/povinfo/index.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './types.js';
js-packages/types/povinfo/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/povinfo/types.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export type PHANTOM_POVINFO = 'povinfo';
js-packages/types/src/.gitignorediffbeforeafterboth--- a/js-packages/types/src/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-metadata.json
js-packages/types/src/appPromotion/definitions.tsdiffbeforeafterboth--- a/js-packages/types/src/appPromotion/definitions.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-type RpcParam = {
- name: string;
- type: string;
- isOptional?: true;
-};
-
-const CROSS_ACCOUNT_ID_TYPE = 'PalletEvmAccountBasicCrossAccountIdRepr';
-
-const crossAccountParam = (name = 'account') => ({name, type: CROSS_ACCOUNT_ID_TYPE});
-const atParam = {name: 'at', type: 'Hash', isOptional: true};
-
-const fun = (description: string, params: RpcParam[], type: string) => ({
- description,
- params: [...params, atParam],
- type,
-});
-
-export default {
- types: {},
- rpc: {
- totalStaked: fun(
- 'Returns the total amount of staked tokens',
- [{name: 'staker', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
- 'u128',
- ),
- totalStakedPerBlock: fun(
- 'Returns the total amount of staked tokens per block when staked',
- [crossAccountParam('staker')],
- 'Vec<(u32, u128)>',
- ),
- pendingUnstake: fun(
- 'Returns the total amount of unstaked tokens',
- [{name: 'staker', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
- 'u128',
- ),
- pendingUnstakePerBlock: fun(
- 'Returns the total amount of unstaked tokens per block',
- [crossAccountParam('staker')],
- 'Vec<(u32, u128)>',
- ),
- },
-};
js-packages/types/src/appPromotion/index.tsdiffbeforeafterboth--- a/js-packages/types/src/appPromotion/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './types.js';
js-packages/types/src/appPromotion/types.tsdiffbeforeafterboth--- a/js-packages/types/src/appPromotion/types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export type PHANTOM_APPPROMOTION = 'appPromotion';
js-packages/types/src/augment-api-consts.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-consts.ts
+++ /dev/null
@@ -1,552 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/api-base/types/consts';
-
-import type { ApiTypes, AugmentedConst } from '@polkadot/api-base/types';
-import type { Option, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
-import type { Codec, ITuple } from '@polkadot/types-codec/types';
-import type { H160, Perbill, Permill } from '@polkadot/types/interfaces/runtime';
-import type { FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, PalletReferendaTrackInfo, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, StagingXcmV3MultiLocation, UpDataStructsCollectionLimits } from '@polkadot/types/lookup';
-
-export type __AugmentedConst<ApiType extends ApiTypes> = AugmentedConst<ApiType>;
-
-declare module '@polkadot/api-base/types/consts' {
- interface AugmentedConsts<ApiType extends ApiTypes> {
- appPromotion: {
- /**
- * Freeze identifier used by the pallet
- **/
- freezeIdentifier: U8aFixed & AugmentedConst<ApiType>;
- /**
- * Rate of return for interval in blocks defined in `RecalculationInterval`.
- **/
- intervalIncome: Perbill & AugmentedConst<ApiType>;
- /**
- * Decimals for the `Currency`.
- **/
- nominal: u128 & AugmentedConst<ApiType>;
- /**
- * The app's pallet id, used for deriving its sovereign account address.
- **/
- palletId: FrameSupportPalletId & AugmentedConst<ApiType>;
- /**
- * In parachain blocks.
- **/
- pendingInterval: u32 & AugmentedConst<ApiType>;
- /**
- * In relay blocks.
- **/
- recalculationInterval: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- balances: {
- /**
- * The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO!
- *
- * If you *really* need it to be zero, you can enable the feature `insecure_zero_ed` for
- * this pallet. However, you do so at your own risk: this will open up a major DoS vector.
- * In case you have multiple sources of provider references, you may also get unexpected
- * behaviour if you set this to zero.
- *
- * Bottom line: Do yourself a favour and make it at least one!
- **/
- existentialDeposit: u128 & AugmentedConst<ApiType>;
- /**
- * The maximum number of individual freeze locks that can exist on an account at any time.
- **/
- maxFreezes: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of holds that can exist on an account at any time.
- **/
- maxHolds: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of locks that should exist on an account.
- * Not strictly enforced, but used for weight estimation.
- **/
- maxLocks: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of named reserves that can exist on an account.
- **/
- maxReserves: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- common: {
- /**
- * Maximum admins per collection.
- **/
- collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
- /**
- * Set price to create a collection.
- **/
- collectionCreationPrice: u128 & AugmentedConst<ApiType>;
- /**
- * Address under which the CollectionHelper contract would be available.
- **/
- contractAddress: H160 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- configuration: {
- appPromotionDailyRate: Perbill & AugmentedConst<ApiType>;
- dayRelayBlocks: u32 & AugmentedConst<ApiType>;
- defaultCollatorSelectionKickThreshold: u32 & AugmentedConst<ApiType>;
- defaultCollatorSelectionLicenseBond: u128 & AugmentedConst<ApiType>;
- defaultCollatorSelectionMaxCollators: u32 & AugmentedConst<ApiType>;
- defaultMinGasPrice: u64 & AugmentedConst<ApiType>;
- defaultWeightToFeeCoefficient: u64 & AugmentedConst<ApiType>;
- maxXcmAllowedLocations: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- council: {
- /**
- * The maximum weight of a dispatch call that can be proposed and executed.
- **/
- maxProposalWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- democracy: {
- /**
- * Period in blocks where an external proposal may not be re-submitted after being vetoed.
- **/
- cooloffPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * The period between a proposal being approved and enacted.
- *
- * It should generally be a little more than the unstake period to ensure that
- * voting stakers have an opportunity to remove themselves from the system in the case
- * where they are on the losing side of a vote.
- **/
- enactmentPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * Minimum voting period allowed for a fast-track referendum.
- **/
- fastTrackVotingPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * Indicator for whether an emergency origin is even allowed to happen. Some chains may
- * want to set this permanently to `false`, others may want to condition it on things such
- * as an upgrade having happened recently.
- **/
- instantAllowed: bool & AugmentedConst<ApiType>;
- /**
- * How often (in blocks) new public referenda are launched.
- **/
- launchPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of items which can be blacklisted.
- **/
- maxBlacklisted: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of deposits a public proposal may have at any time.
- **/
- maxDeposits: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of public proposals that can exist at any time.
- **/
- maxProposals: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of votes for an account.
- *
- * Also used to compute weight, an overly big value can
- * lead to extrinsic with very big weight: see `delegate` for instance.
- **/
- maxVotes: u32 & AugmentedConst<ApiType>;
- /**
- * The minimum amount to be used as a deposit for a public referendum proposal.
- **/
- minimumDeposit: u128 & AugmentedConst<ApiType>;
- /**
- * The minimum period of vote locking.
- *
- * It should be no shorter than enactment period to ensure that in the case of an approval,
- * those successful voters are locked into the consequences that their votes entail.
- **/
- voteLockingPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * How often (in blocks) to check for new votes.
- **/
- votingPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- evmContractHelpers: {
- /**
- * Address, under which magic contract will be available
- **/
- contractAddress: H160 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- fellowshipReferenda: {
- /**
- * Quantization level for the referendum wakeup scheduler. A higher number will result in
- * fewer storage reads/writes needed for smaller voters, but also result in delays to the
- * automatic referendum status changes. Explicit servicing instructions are unaffected.
- **/
- alarmInterval: u32 & AugmentedConst<ApiType>;
- /**
- * Maximum size of the referendum queue for a single track.
- **/
- maxQueued: u32 & AugmentedConst<ApiType>;
- /**
- * The minimum amount to be used as a deposit for a public referendum proposal.
- **/
- submissionDeposit: u128 & AugmentedConst<ApiType>;
- /**
- * Information concerning the different referendum tracks.
- **/
- tracks: Vec<ITuple<[u16, PalletReferendaTrackInfo]>> & AugmentedConst<ApiType>;
- /**
- * The number of blocks after submission that a referendum must begin being decided by.
- * Once this passes, then anyone may cancel the referendum.
- **/
- undecidingTimeout: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- identity: {
- /**
- * The amount held on deposit for a registered identity
- **/
- basicDeposit: u128 & AugmentedConst<ApiType>;
- /**
- * The amount held on deposit per additional field for a registered identity.
- **/
- fieldDeposit: u128 & AugmentedConst<ApiType>;
- /**
- * Maximum number of additional fields that may be stored in an ID. Needed to bound the I/O
- * required to access an identity, but can be pretty high.
- **/
- maxAdditionalFields: u32 & AugmentedConst<ApiType>;
- /**
- * Maxmimum number of registrars allowed in the system. Needed to bound the complexity
- * of, e.g., updating judgements.
- **/
- maxRegistrars: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of sub-accounts allowed per identified account.
- **/
- maxSubAccounts: u32 & AugmentedConst<ApiType>;
- /**
- * The amount held on deposit for a registered subaccount. This should account for the fact
- * that one storage item's value will increase by the size of an account ID, and there will
- * be another trie item whose value is the size of an account ID plus 32 bytes.
- **/
- subAccountDeposit: u128 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- inflation: {
- /**
- * Number of blocks that pass between treasury balance updates due to inflation
- **/
- inflationBlockInterval: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- scheduler: {
- /**
- * The maximum weight that may be scheduled per block for any dispatchables.
- **/
- maximumWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
- /**
- * The maximum number of scheduled calls in the queue for a single block.
- *
- * NOTE:
- * + Dependent pallets' benchmarks might require a higher limit for the setting. Set a
- * higher limit under `runtime-benchmarks` feature.
- **/
- maxScheduledPerBlock: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- stateTrieMigration: {
- /**
- * Maximal number of bytes that a key can have.
- *
- * FRAME itself does not limit the key length.
- * The concrete value must therefore depend on your storage usage.
- * A [`frame_support::storage::StorageNMap`] for example can have an arbitrary number of
- * keys which are then hashed and concatenated, resulting in arbitrarily long keys.
- *
- * Use the *state migration RPC* to retrieve the length of the longest key in your
- * storage: <https://github.com/paritytech/substrate/issues/11642>
- *
- * The migration will halt with a `Halted` event if this value is too small.
- * Since there is no real penalty from over-estimating, it is advised to use a large
- * value. The default is 512 byte.
- *
- * Some key lengths for reference:
- * - [`frame_support::storage::StorageValue`]: 32 byte
- * - [`frame_support::storage::StorageMap`]: 64 byte
- * - [`frame_support::storage::StorageDoubleMap`]: 96 byte
- *
- * For more info see
- * <https://www.shawntabrizi.com/substrate/querying-substrate-storage-via-rpc/>
- **/
- maxKeyLen: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- system: {
- /**
- * Maximum number of block number to block hash mappings to keep (oldest pruned first).
- **/
- blockHashCount: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum length of a block (in bytes).
- **/
- blockLength: FrameSystemLimitsBlockLength & AugmentedConst<ApiType>;
- /**
- * Block & extrinsics weights: base values and limits.
- **/
- blockWeights: FrameSystemLimitsBlockWeights & AugmentedConst<ApiType>;
- /**
- * The weight of runtime database operations the runtime can invoke.
- **/
- dbWeight: SpWeightsRuntimeDbWeight & AugmentedConst<ApiType>;
- /**
- * The designated SS58 prefix of this chain.
- *
- * This replaces the "ss58Format" property declared in the chain spec. Reason is
- * that the runtime should know about the prefix in order to make use of it as
- * an identifier of the chain.
- **/
- ss58Prefix: u16 & AugmentedConst<ApiType>;
- /**
- * Get the chain's current version.
- **/
- version: SpVersionRuntimeVersion & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- technicalCommittee: {
- /**
- * The maximum weight of a dispatch call that can be proposed and executed.
- **/
- maxProposalWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- timestamp: {
- /**
- * The minimum period between blocks. Beware that this is different to the *expected*
- * period that the block production apparatus provides. Your chosen consensus system will
- * generally work with this to determine a sensible block time. e.g. For Aura, it will be
- * double this period on default settings.
- **/
- minimumPeriod: u64 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- tokens: {
- maxLocks: u32 & AugmentedConst<ApiType>;
- /**
- * The maximum number of named reserves that can exist on an account.
- **/
- maxReserves: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- transactionPayment: {
- /**
- * A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their
- * `priority`
- *
- * This value is multipled by the `final_fee` to obtain a "virtual tip" that is later
- * added to a tip component in regular `priority` calculations.
- * It means that a `Normal` transaction can front-run a similarly-sized `Operational`
- * extrinsic (with no tip), by including a tip value greater than the virtual tip.
- *
- * ```rust,ignore
- * // For `Normal`
- * let priority = priority_calc(tip);
- *
- * // For `Operational`
- * let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;
- * let priority = priority_calc(tip + virtual_tip);
- * ```
- *
- * Note that since we use `final_fee` the multiplier applies also to the regular `tip`
- * sent with the transaction. So, not only does the transaction get a priority bump based
- * on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`
- * transactions.
- **/
- operationalFeeMultiplier: u8 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- treasury: {
- /**
- * Percentage of spare funds (if any) that are burnt per spend period.
- **/
- burn: Permill & AugmentedConst<ApiType>;
- /**
- * The maximum number of approvals that can wait in the spending queue.
- *
- * NOTE: This parameter is also used within the Bounties Pallet extension if enabled.
- **/
- maxApprovals: u32 & AugmentedConst<ApiType>;
- /**
- * The treasury's pallet id, used for deriving its sovereign account ID.
- **/
- palletId: FrameSupportPalletId & AugmentedConst<ApiType>;
- /**
- * Fraction of a proposal's value that should be bonded in order to place the proposal.
- * An accepted proposal gets these back. A rejected proposal does not.
- **/
- proposalBond: Permill & AugmentedConst<ApiType>;
- /**
- * Maximum amount of funds that should be placed in a deposit for making a proposal.
- **/
- proposalBondMaximum: Option<u128> & AugmentedConst<ApiType>;
- /**
- * Minimum amount of funds that should be placed in a deposit for making a proposal.
- **/
- proposalBondMinimum: u128 & AugmentedConst<ApiType>;
- /**
- * Period between successive spends.
- **/
- spendPeriod: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- unique: {
- /**
- * Maximum admins per collection.
- **/
- collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
- /**
- * Default FT collection limit.
- **/
- ftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
- /**
- * Maximal length of a collection description.
- **/
- maxCollectionDescriptionLength: u32 & AugmentedConst<ApiType>;
- /**
- * Maximal length of a collection name.
- **/
- maxCollectionNameLength: u32 & AugmentedConst<ApiType>;
- /**
- * Maximum size for all collection properties.
- **/
- maxCollectionPropertiesSize: u32 & AugmentedConst<ApiType>;
- /**
- * A maximum number of token properties.
- **/
- maxPropertiesPerItem: u32 & AugmentedConst<ApiType>;
- /**
- * Maximal length of a property key.
- **/
- maxPropertyKeyLength: u32 & AugmentedConst<ApiType>;
- /**
- * Maximal length of a property value.
- **/
- maxPropertyValueLength: u32 & AugmentedConst<ApiType>;
- /**
- * Maximal length of a token prefix.
- **/
- maxTokenPrefixLength: u32 & AugmentedConst<ApiType>;
- /**
- * Maximum size of all token properties.
- **/
- maxTokenPropertiesSize: u32 & AugmentedConst<ApiType>;
- /**
- * A maximum number of levels of depth in the token nesting tree.
- **/
- nestingBudget: u32 & AugmentedConst<ApiType>;
- /**
- * Default NFT collection limit.
- **/
- nftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
- /**
- * Default RFT collection limit.
- **/
- rftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- utility: {
- /**
- * The limit on the number of batched calls.
- **/
- batchedCallsLimit: u32 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- vesting: {
- /**
- * The minimum amount transferred to call `vested_transfer`.
- **/
- minVestedTransfer: u128 & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- xTokens: {
- /**
- * Base XCM weight.
- *
- * The actually weight for an XCM message is `T::BaseXcmWeight +
- * T::Weigher::weight(&msg)`.
- **/
- baseXcmWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
- /**
- * Self chain location.
- **/
- selfLocation: StagingXcmV3MultiLocation & AugmentedConst<ApiType>;
- /**
- * Generic const
- **/
- [key: string]: Codec;
- };
- } // AugmentedConsts
-} // declare module
js-packages/types/src/augment-api-errors.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-errors.ts
+++ /dev/null
@@ -1,1521 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/api-base/types/errors';
-
-import type { ApiTypes, AugmentedError } from '@polkadot/api-base/types';
-
-export type __AugmentedError<ApiType extends ApiTypes> = AugmentedError<ApiType>;
-
-declare module '@polkadot/api-base/types/errors' {
- interface AugmentedErrors<ApiType extends ApiTypes> {
- appPromotion: {
- /**
- * Error due to action requiring admin to be set.
- **/
- AdminNotSet: AugmentedError<ApiType>;
- /**
- * Errors caused by incorrect state of a staker in context of the pallet.
- **/
- InconsistencyState: AugmentedError<ApiType>;
- /**
- * Errors caused by insufficient staked balance.
- **/
- InsufficientStakedBalance: AugmentedError<ApiType>;
- /**
- * No permission to perform an action.
- **/
- NoPermission: AugmentedError<ApiType>;
- /**
- * Insufficient funds to perform an action.
- **/
- NotSufficientFunds: AugmentedError<ApiType>;
- /**
- * Occurs when a pending unstake cannot be added in this block. PENDING_LIMIT_PER_BLOCK` limits exceeded.
- **/
- PendingForBlockOverflow: AugmentedError<ApiType>;
- /**
- * The error is due to the fact that the collection/contract must already be sponsored in order to perform the action.
- **/
- SponsorNotSet: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- balances: {
- /**
- * Beneficiary account must pre-exist.
- **/
- DeadAccount: AugmentedError<ApiType>;
- /**
- * Value too low to create account due to existential deposit.
- **/
- ExistentialDeposit: AugmentedError<ApiType>;
- /**
- * A vesting schedule already exists for this account.
- **/
- ExistingVestingSchedule: AugmentedError<ApiType>;
- /**
- * Transfer/payment would kill account.
- **/
- Expendability: AugmentedError<ApiType>;
- /**
- * Balance too low to send value.
- **/
- InsufficientBalance: AugmentedError<ApiType>;
- /**
- * Account liquidity restrictions prevent withdrawal.
- **/
- LiquidityRestrictions: AugmentedError<ApiType>;
- /**
- * Number of freezes exceed `MaxFreezes`.
- **/
- TooManyFreezes: AugmentedError<ApiType>;
- /**
- * Number of holds exceed `MaxHolds`.
- **/
- TooManyHolds: AugmentedError<ApiType>;
- /**
- * Number of named reserves exceed `MaxReserves`.
- **/
- TooManyReserves: AugmentedError<ApiType>;
- /**
- * Vesting balance too high to send value.
- **/
- VestingBalance: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- collatorSelection: {
- /**
- * User is already a candidate
- **/
- AlreadyCandidate: AugmentedError<ApiType>;
- /**
- * User already holds license to collate
- **/
- AlreadyHoldingLicense: AugmentedError<ApiType>;
- /**
- * User is already an Invulnerable
- **/
- AlreadyInvulnerable: AugmentedError<ApiType>;
- /**
- * Account has no associated validator ID
- **/
- NoAssociatedValidatorId: AugmentedError<ApiType>;
- /**
- * User does not hold a license to collate
- **/
- NoLicense: AugmentedError<ApiType>;
- /**
- * User is not a candidate
- **/
- NotCandidate: AugmentedError<ApiType>;
- /**
- * User is not an Invulnerable
- **/
- NotInvulnerable: AugmentedError<ApiType>;
- /**
- * Permission issue
- **/
- Permission: AugmentedError<ApiType>;
- /**
- * Too few invulnerables
- **/
- TooFewInvulnerables: AugmentedError<ApiType>;
- /**
- * Too many candidates
- **/
- TooManyCandidates: AugmentedError<ApiType>;
- /**
- * Too many invulnerables
- **/
- TooManyInvulnerables: AugmentedError<ApiType>;
- /**
- * Unknown error
- **/
- Unknown: AugmentedError<ApiType>;
- /**
- * Validator ID is not yet registered
- **/
- ValidatorNotRegistered: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- common: {
- /**
- * Account token limit exceeded per collection
- **/
- AccountTokenLimitExceeded: AugmentedError<ApiType>;
- /**
- * Only spending from eth mirror could be approved
- **/
- AddressIsNotEthMirror: AugmentedError<ApiType>;
- /**
- * Can't transfer tokens to ethereum zero address
- **/
- AddressIsZero: AugmentedError<ApiType>;
- /**
- * Address is not in allow list.
- **/
- AddressNotInAllowlist: AugmentedError<ApiType>;
- /**
- * Requested value is more than the approved
- **/
- ApprovedValueTooLow: AugmentedError<ApiType>;
- /**
- * Tried to approve more than owned
- **/
- CantApproveMoreThanOwned: AugmentedError<ApiType>;
- /**
- * Destroying only empty collections is allowed
- **/
- CantDestroyNotEmptyCollection: AugmentedError<ApiType>;
- /**
- * Exceeded max admin count
- **/
- CollectionAdminCountExceeded: AugmentedError<ApiType>;
- /**
- * Collection description can not be longer than 255 char.
- **/
- CollectionDescriptionLimitExceeded: AugmentedError<ApiType>;
- /**
- * Tried to store more data than allowed in collection field
- **/
- CollectionFieldSizeExceeded: AugmentedError<ApiType>;
- /**
- * Tried to access an external collection with an internal API
- **/
- CollectionIsExternal: AugmentedError<ApiType>;
- /**
- * Tried to access an internal collection with an external API
- **/
- CollectionIsInternal: AugmentedError<ApiType>;
- /**
- * Collection limit bounds per collection exceeded
- **/
- CollectionLimitBoundsExceeded: AugmentedError<ApiType>;
- /**
- * Collection name can not be longer than 63 char.
- **/
- CollectionNameLimitExceeded: AugmentedError<ApiType>;
- /**
- * This collection does not exist.
- **/
- CollectionNotFound: AugmentedError<ApiType>;
- /**
- * Collection token limit exceeded
- **/
- CollectionTokenLimitExceeded: AugmentedError<ApiType>;
- /**
- * Token prefix can not be longer than 15 char.
- **/
- CollectionTokenPrefixLimitExceeded: AugmentedError<ApiType>;
- /**
- * This address is not set as sponsor, use setCollectionSponsor first.
- **/
- ConfirmSponsorshipFail: AugmentedError<ApiType>;
- /**
- * Empty property keys are forbidden
- **/
- EmptyPropertyKey: AugmentedError<ApiType>;
- /**
- * Fungible tokens hold no ID, and the default value of TokenId for a fungible collection is 0.
- **/
- FungibleItemsHaveNoId: AugmentedError<ApiType>;
- /**
- * Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed
- **/
- InvalidCharacterInPropertyKey: AugmentedError<ApiType>;
- /**
- * Metadata flag frozen
- **/
- MetadataFlagFrozen: AugmentedError<ApiType>;
- /**
- * Sender parameter and item owner must be equal.
- **/
- MustBeTokenOwner: AugmentedError<ApiType>;
- /**
- * No permission to perform action
- **/
- NoPermission: AugmentedError<ApiType>;
- /**
- * Tried to store more property data than allowed
- **/
- NoSpaceForProperty: AugmentedError<ApiType>;
- /**
- * Insufficient funds to perform an action
- **/
- NotSufficientFounds: AugmentedError<ApiType>;
- /**
- * Tried to enable permissions which are only permitted to be disabled
- **/
- OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;
- /**
- * Property key is too long
- **/
- PropertyKeyIsTooLong: AugmentedError<ApiType>;
- /**
- * Tried to store more property keys than allowed
- **/
- PropertyLimitReached: AugmentedError<ApiType>;
- /**
- * Collection is not in mint mode.
- **/
- PublicMintingNotAllowed: AugmentedError<ApiType>;
- /**
- * Only tokens from specific collections may nest tokens under this one
- **/
- SourceCollectionIsNotAllowedToNest: AugmentedError<ApiType>;
- /**
- * Item does not exist
- **/
- TokenNotFound: AugmentedError<ApiType>;
- /**
- * Item is balance not enough
- **/
- TokenValueTooLow: AugmentedError<ApiType>;
- /**
- * Total collections bound exceeded.
- **/
- TotalCollectionsLimitExceeded: AugmentedError<ApiType>;
- /**
- * Collection settings not allowing items transferring
- **/
- TransferNotAllowed: AugmentedError<ApiType>;
- /**
- * The operation is not supported
- **/
- UnsupportedOperation: AugmentedError<ApiType>;
- /**
- * User does not satisfy the nesting rule
- **/
- UserIsNotAllowedToNest: AugmentedError<ApiType>;
- /**
- * The user is not an administrator.
- **/
- UserIsNotCollectionAdmin: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- configuration: {
- InconsistentConfiguration: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- council: {
- /**
- * Members are already initialized!
- **/
- AlreadyInitialized: AugmentedError<ApiType>;
- /**
- * Duplicate proposals not allowed
- **/
- DuplicateProposal: AugmentedError<ApiType>;
- /**
- * Duplicate vote ignored
- **/
- DuplicateVote: AugmentedError<ApiType>;
- /**
- * Account is not a member
- **/
- NotMember: AugmentedError<ApiType>;
- /**
- * Prime account is not a member
- **/
- PrimeAccountNotMember: AugmentedError<ApiType>;
- /**
- * Proposal must exist
- **/
- ProposalMissing: AugmentedError<ApiType>;
- /**
- * The close call was made too early, before the end of the voting.
- **/
- TooEarly: AugmentedError<ApiType>;
- /**
- * There can only be a maximum of `MaxProposals` active proposals.
- **/
- TooManyProposals: AugmentedError<ApiType>;
- /**
- * Mismatched index
- **/
- WrongIndex: AugmentedError<ApiType>;
- /**
- * The given length bound for the proposal was too low.
- **/
- WrongProposalLength: AugmentedError<ApiType>;
- /**
- * The given weight bound for the proposal was too low.
- **/
- WrongProposalWeight: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- councilMembership: {
- /**
- * Already a member.
- **/
- AlreadyMember: AugmentedError<ApiType>;
- /**
- * Not a member.
- **/
- NotMember: AugmentedError<ApiType>;
- /**
- * Too many members.
- **/
- TooManyMembers: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- cumulusXcm: {
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- democracy: {
- /**
- * Cannot cancel the same proposal twice
- **/
- AlreadyCanceled: AugmentedError<ApiType>;
- /**
- * The account is already delegating.
- **/
- AlreadyDelegating: AugmentedError<ApiType>;
- /**
- * Identity may not veto a proposal twice
- **/
- AlreadyVetoed: AugmentedError<ApiType>;
- /**
- * Proposal already made
- **/
- DuplicateProposal: AugmentedError<ApiType>;
- /**
- * The instant referendum origin is currently disallowed.
- **/
- InstantNotAllowed: AugmentedError<ApiType>;
- /**
- * Too high a balance was provided that the account cannot afford.
- **/
- InsufficientFunds: AugmentedError<ApiType>;
- /**
- * Invalid hash
- **/
- InvalidHash: AugmentedError<ApiType>;
- /**
- * Maximum number of votes reached.
- **/
- MaxVotesReached: AugmentedError<ApiType>;
- /**
- * No proposals waiting
- **/
- NoneWaiting: AugmentedError<ApiType>;
- /**
- * Delegation to oneself makes no sense.
- **/
- Nonsense: AugmentedError<ApiType>;
- /**
- * The actor has no permission to conduct the action.
- **/
- NoPermission: AugmentedError<ApiType>;
- /**
- * No external proposal
- **/
- NoProposal: AugmentedError<ApiType>;
- /**
- * The account is not currently delegating.
- **/
- NotDelegating: AugmentedError<ApiType>;
- /**
- * Next external proposal not simple majority
- **/
- NotSimpleMajority: AugmentedError<ApiType>;
- /**
- * The given account did not vote on the referendum.
- **/
- NotVoter: AugmentedError<ApiType>;
- /**
- * The preimage does not exist.
- **/
- PreimageNotExist: AugmentedError<ApiType>;
- /**
- * Proposal still blacklisted
- **/
- ProposalBlacklisted: AugmentedError<ApiType>;
- /**
- * Proposal does not exist
- **/
- ProposalMissing: AugmentedError<ApiType>;
- /**
- * Vote given for invalid referendum
- **/
- ReferendumInvalid: AugmentedError<ApiType>;
- /**
- * Maximum number of items reached.
- **/
- TooMany: AugmentedError<ApiType>;
- /**
- * Value too low
- **/
- ValueLow: AugmentedError<ApiType>;
- /**
- * The account currently has votes attached to it and the operation cannot succeed until
- * these are removed, either through `unvote` or `reap_vote`.
- **/
- VotesExist: AugmentedError<ApiType>;
- /**
- * Voting period too low
- **/
- VotingPeriodLow: AugmentedError<ApiType>;
- /**
- * Invalid upper bound.
- **/
- WrongUpperBound: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- dmpQueue: {
- /**
- * The amount of weight given is possibly not enough for executing the message.
- **/
- OverLimit: AugmentedError<ApiType>;
- /**
- * The message index given is unknown.
- **/
- Unknown: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- ethereum: {
- /**
- * Signature is invalid.
- **/
- InvalidSignature: AugmentedError<ApiType>;
- /**
- * Pre-log is present, therefore transact is not allowed.
- **/
- PreLogExists: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- evm: {
- /**
- * Not enough balance to perform action
- **/
- BalanceLow: AugmentedError<ApiType>;
- /**
- * Calculating total fee overflowed
- **/
- FeeOverflow: AugmentedError<ApiType>;
- /**
- * Gas limit is too high.
- **/
- GasLimitTooHigh: AugmentedError<ApiType>;
- /**
- * Gas limit is too low.
- **/
- GasLimitTooLow: AugmentedError<ApiType>;
- /**
- * Gas price is too low.
- **/
- GasPriceTooLow: AugmentedError<ApiType>;
- /**
- * Nonce is invalid
- **/
- InvalidNonce: AugmentedError<ApiType>;
- /**
- * Calculating total payment overflowed
- **/
- PaymentOverflow: AugmentedError<ApiType>;
- /**
- * EVM reentrancy
- **/
- Reentrancy: AugmentedError<ApiType>;
- /**
- * EIP-3607,
- **/
- TransactionMustComeFromEOA: AugmentedError<ApiType>;
- /**
- * Undefined error.
- **/
- Undefined: AugmentedError<ApiType>;
- /**
- * Withdraw fee failed
- **/
- WithdrawFailed: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- evmCoderSubstrate: {
- OutOfFund: AugmentedError<ApiType>;
- OutOfGas: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- evmContractHelpers: {
- /**
- * No pending sponsor for contract.
- **/
- NoPendingSponsor: AugmentedError<ApiType>;
- /**
- * This method is only executable by contract owner
- **/
- NoPermission: AugmentedError<ApiType>;
- /**
- * Number of methods that sponsored limit is defined for exceeds maximum.
- **/
- TooManyMethodsHaveSponsoredLimit: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- evmMigration: {
- /**
- * Migration of this account is not yet started, or already finished.
- **/
- AccountIsNotMigrating: AugmentedError<ApiType>;
- /**
- * Can only migrate to empty address.
- **/
- AccountNotEmpty: AugmentedError<ApiType>;
- /**
- * Failed to decode event bytes
- **/
- BadEvent: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- fellowshipCollective: {
- /**
- * Account is already a member.
- **/
- AlreadyMember: AugmentedError<ApiType>;
- /**
- * Unexpected error in state.
- **/
- Corruption: AugmentedError<ApiType>;
- /**
- * The information provided is incorrect.
- **/
- InvalidWitness: AugmentedError<ApiType>;
- /**
- * There are no further records to be removed.
- **/
- NoneRemaining: AugmentedError<ApiType>;
- /**
- * The origin is not sufficiently privileged to do the operation.
- **/
- NoPermission: AugmentedError<ApiType>;
- /**
- * Account is not a member.
- **/
- NotMember: AugmentedError<ApiType>;
- /**
- * The given poll index is unknown or has closed.
- **/
- NotPolling: AugmentedError<ApiType>;
- /**
- * The given poll is still ongoing.
- **/
- Ongoing: AugmentedError<ApiType>;
- /**
- * The member's rank is too low to vote.
- **/
- RankTooLow: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- fellowshipReferenda: {
- /**
- * The referendum index provided is invalid in this context.
- **/
- BadReferendum: AugmentedError<ApiType>;
- /**
- * The referendum status is invalid for this operation.
- **/
- BadStatus: AugmentedError<ApiType>;
- /**
- * The track identifier given was invalid.
- **/
- BadTrack: AugmentedError<ApiType>;
- /**
- * There are already a full complement of referenda in progress for this track.
- **/
- Full: AugmentedError<ApiType>;
- /**
- * Referendum's decision deposit is already paid.
- **/
- HasDeposit: AugmentedError<ApiType>;
- /**
- * The deposit cannot be refunded since none was made.
- **/
- NoDeposit: AugmentedError<ApiType>;
- /**
- * The deposit refunder is not the depositor.
- **/
- NoPermission: AugmentedError<ApiType>;
- /**
- * There was nothing to do in the advancement.
- **/
- NothingToDo: AugmentedError<ApiType>;
- /**
- * Referendum is not ongoing.
- **/
- NotOngoing: AugmentedError<ApiType>;
- /**
- * No track exists for the proposal origin.
- **/
- NoTrack: AugmentedError<ApiType>;
- /**
- * The preimage does not exist.
- **/
- PreimageNotExist: AugmentedError<ApiType>;
- /**
- * The queue of the track is empty.
- **/
- QueueEmpty: AugmentedError<ApiType>;
- /**
- * Any deposit cannot be refunded until after the decision is over.
- **/
- Unfinished: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- foreignAssets: {
- /**
- * AssetId exists
- **/
- AssetIdExisted: AugmentedError<ApiType>;
- /**
- * AssetId not exists
- **/
- AssetIdNotExists: AugmentedError<ApiType>;
- /**
- * The given location could not be used (e.g. because it cannot be expressed in the
- * desired version of XCM).
- **/
- BadLocation: AugmentedError<ApiType>;
- /**
- * MultiLocation existed
- **/
- MultiLocationExisted: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- fungible: {
- /**
- * Fungible token does not support nesting.
- **/
- FungibleDisallowsNesting: AugmentedError<ApiType>;
- /**
- * Tried to set data for fungible item.
- **/
- FungibleItemsDontHaveData: AugmentedError<ApiType>;
- /**
- * Only a fungible collection could be possibly broken; any fungible token is valid.
- **/
- FungibleTokensAreAlwaysValid: AugmentedError<ApiType>;
- /**
- * Not Fungible item data used to mint in Fungible collection.
- **/
- NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
- /**
- * Setting allowance for all is not allowed.
- **/
- SettingAllowanceForAllNotAllowed: AugmentedError<ApiType>;
- /**
- * Setting item properties is not allowed.
- **/
- SettingPropertiesNotAllowed: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- identity: {
- /**
- * Account ID is already named.
- **/
- AlreadyClaimed: AugmentedError<ApiType>;
- /**
- * Empty index.
- **/
- EmptyIndex: AugmentedError<ApiType>;
- /**
- * Fee is changed.
- **/
- FeeChanged: AugmentedError<ApiType>;
- /**
- * The index is invalid.
- **/
- InvalidIndex: AugmentedError<ApiType>;
- /**
- * Invalid judgement.
- **/
- InvalidJudgement: AugmentedError<ApiType>;
- /**
- * The target is invalid.
- **/
- InvalidTarget: AugmentedError<ApiType>;
- /**
- * The provided judgement was for a different identity.
- **/
- JudgementForDifferentIdentity: AugmentedError<ApiType>;
- /**
- * Judgement given.
- **/
- JudgementGiven: AugmentedError<ApiType>;
- /**
- * Error that occurs when there is an issue paying for judgement.
- **/
- JudgementPaymentFailed: AugmentedError<ApiType>;
- /**
- * No identity found.
- **/
- NoIdentity: AugmentedError<ApiType>;
- /**
- * Account isn't found.
- **/
- NotFound: AugmentedError<ApiType>;
- /**
- * Account isn't named.
- **/
- NotNamed: AugmentedError<ApiType>;
- /**
- * Sub-account isn't owned by sender.
- **/
- NotOwned: AugmentedError<ApiType>;
- /**
- * Sender is not a sub-account.
- **/
- NotSub: AugmentedError<ApiType>;
- /**
- * Sticky judgement.
- **/
- StickyJudgement: AugmentedError<ApiType>;
- /**
- * Too many additional fields.
- **/
- TooManyFields: AugmentedError<ApiType>;
- /**
- * Maximum amount of registrars reached. Cannot add any more.
- **/
- TooManyRegistrars: AugmentedError<ApiType>;
- /**
- * Too many subs-accounts.
- **/
- TooManySubAccounts: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- maintenance: {
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- nonfungible: {
- /**
- * Unable to burn NFT with children
- **/
- CantBurnNftWithChildren: AugmentedError<ApiType>;
- /**
- * Used amount > 1 with NFT
- **/
- NonfungibleItemsHaveNoAmount: AugmentedError<ApiType>;
- /**
- * Not Nonfungible item data used to mint in Nonfungible collection.
- **/
- NotNonfungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- parachainSystem: {
- /**
- * The inherent which supplies the host configuration did not run this block.
- **/
- HostConfigurationNotAvailable: AugmentedError<ApiType>;
- /**
- * No code upgrade has been authorized.
- **/
- NothingAuthorized: AugmentedError<ApiType>;
- /**
- * No validation function upgrade is currently scheduled.
- **/
- NotScheduled: AugmentedError<ApiType>;
- /**
- * Attempt to upgrade validation function while existing upgrade pending.
- **/
- OverlappingUpgrades: AugmentedError<ApiType>;
- /**
- * Polkadot currently prohibits this parachain from upgrading its validation function.
- **/
- ProhibitedByPolkadot: AugmentedError<ApiType>;
- /**
- * The supplied validation function has compiled into a blob larger than Polkadot is
- * willing to run.
- **/
- TooBig: AugmentedError<ApiType>;
- /**
- * The given code upgrade has not been authorized.
- **/
- Unauthorized: AugmentedError<ApiType>;
- /**
- * The inherent which supplies the validation data did not run this block.
- **/
- ValidationDataNotAvailable: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- polkadotXcm: {
- /**
- * The given account is not an identifiable sovereign account for any location.
- **/
- AccountNotSovereign: AugmentedError<ApiType>;
- /**
- * The location is invalid since it already has a subscription from us.
- **/
- AlreadySubscribed: AugmentedError<ApiType>;
- /**
- * The given location could not be used (e.g. because it cannot be expressed in the
- * desired version of XCM).
- **/
- BadLocation: AugmentedError<ApiType>;
- /**
- * The version of the `Versioned` value used is not able to be interpreted.
- **/
- BadVersion: AugmentedError<ApiType>;
- /**
- * Could not re-anchor the assets to declare the fees for the destination chain.
- **/
- CannotReanchor: AugmentedError<ApiType>;
- /**
- * The destination `MultiLocation` provided cannot be inverted.
- **/
- DestinationNotInvertible: AugmentedError<ApiType>;
- /**
- * The assets to be sent are empty.
- **/
- Empty: AugmentedError<ApiType>;
- /**
- * The operation required fees to be paid which the initiator could not meet.
- **/
- FeesNotMet: AugmentedError<ApiType>;
- /**
- * The message execution fails the filter.
- **/
- Filtered: AugmentedError<ApiType>;
- /**
- * The unlock operation cannot succeed because there are still consumers of the lock.
- **/
- InUse: AugmentedError<ApiType>;
- /**
- * Invalid asset for the operation.
- **/
- InvalidAsset: AugmentedError<ApiType>;
- /**
- * Origin is invalid for sending.
- **/
- InvalidOrigin: AugmentedError<ApiType>;
- /**
- * A remote lock with the corresponding data could not be found.
- **/
- LockNotFound: AugmentedError<ApiType>;
- /**
- * The owner does not own (all) of the asset that they wish to do the operation on.
- **/
- LowBalance: AugmentedError<ApiType>;
- /**
- * The referenced subscription could not be found.
- **/
- NoSubscription: AugmentedError<ApiType>;
- /**
- * There was some other issue (i.e. not to do with routing) in sending the message.
- * Perhaps a lack of space for buffering the message.
- **/
- SendFailure: AugmentedError<ApiType>;
- /**
- * Too many assets have been attempted for transfer.
- **/
- TooManyAssets: AugmentedError<ApiType>;
- /**
- * The asset owner has too many locks on the asset.
- **/
- TooManyLocks: AugmentedError<ApiType>;
- /**
- * The desired destination was unreachable, generally because there is a no way of routing
- * to it.
- **/
- Unreachable: AugmentedError<ApiType>;
- /**
- * The message's weight could not be determined.
- **/
- UnweighableMessage: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- preimage: {
- /**
- * Preimage has already been noted on-chain.
- **/
- AlreadyNoted: AugmentedError<ApiType>;
- /**
- * The user is not authorized to perform this action.
- **/
- NotAuthorized: AugmentedError<ApiType>;
- /**
- * The preimage cannot be removed since it has not yet been noted.
- **/
- NotNoted: AugmentedError<ApiType>;
- /**
- * The preimage request cannot be removed since no outstanding requests exist.
- **/
- NotRequested: AugmentedError<ApiType>;
- /**
- * A preimage may not be removed when there are outstanding requests.
- **/
- Requested: AugmentedError<ApiType>;
- /**
- * Preimage is too large to store on-chain.
- **/
- TooBig: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- refungible: {
- /**
- * Not Refungible item data used to mint in Refungible collection.
- **/
- NotRefungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
- /**
- * Refungible token can't nest other tokens.
- **/
- RefungibleDisallowsNesting: AugmentedError<ApiType>;
- /**
- * Refungible token can't be repartitioned by user who isn't owns all pieces.
- **/
- RepartitionWhileNotOwningAllPieces: AugmentedError<ApiType>;
- /**
- * Setting item properties is not allowed.
- **/
- SettingPropertiesNotAllowed: AugmentedError<ApiType>;
- /**
- * Maximum refungibility exceeded.
- **/
- WrongRefungiblePieces: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- scheduler: {
- /**
- * Failed to schedule a call
- **/
- FailedToSchedule: AugmentedError<ApiType>;
- /**
- * Attempt to use a non-named function on a named task.
- **/
- Named: AugmentedError<ApiType>;
- /**
- * Cannot find the scheduled call.
- **/
- NotFound: AugmentedError<ApiType>;
- /**
- * Reschedule failed because it does not change scheduled time.
- **/
- RescheduleNoChange: AugmentedError<ApiType>;
- /**
- * Given target block number is in the past.
- **/
- TargetBlockNumberInPast: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- session: {
- /**
- * Registered duplicate key.
- **/
- DuplicatedKey: AugmentedError<ApiType>;
- /**
- * Invalid ownership proof.
- **/
- InvalidProof: AugmentedError<ApiType>;
- /**
- * Key setting account is not live, so it's impossible to associate keys.
- **/
- NoAccount: AugmentedError<ApiType>;
- /**
- * No associated validator ID for account.
- **/
- NoAssociatedValidatorId: AugmentedError<ApiType>;
- /**
- * No keys are associated with this account.
- **/
- NoKeys: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- stateTrieMigration: {
- /**
- * Bad child root provided.
- **/
- BadChildRoot: AugmentedError<ApiType>;
- /**
- * Bad witness data provided.
- **/
- BadWitness: AugmentedError<ApiType>;
- /**
- * A key was longer than the configured maximum.
- *
- * This means that the migration halted at the current [`Progress`] and
- * can be resumed with a larger [`crate::Config::MaxKeyLen`] value.
- * Retrying with the same [`crate::Config::MaxKeyLen`] value will not work.
- * The value should only be increased to avoid a storage migration for the currently
- * stored [`crate::Progress::LastKey`].
- **/
- KeyTooLong: AugmentedError<ApiType>;
- /**
- * Max signed limits not respected.
- **/
- MaxSignedLimits: AugmentedError<ApiType>;
- /**
- * submitter does not have enough funds.
- **/
- NotEnoughFunds: AugmentedError<ApiType>;
- /**
- * Signed migration is not allowed because the maximum limit is not set yet.
- **/
- SignedMigrationNotAllowed: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- structure: {
- /**
- * While nesting, reached the breadth limit of nesting, exceeding the provided budget.
- **/
- BreadthLimit: AugmentedError<ApiType>;
- /**
- * Tried to nest token under collection contract address, instead of token address
- **/
- CantNestTokenUnderCollection: AugmentedError<ApiType>;
- /**
- * While nesting, reached the depth limit of nesting, exceeding the provided budget.
- **/
- DepthLimit: AugmentedError<ApiType>;
- /**
- * While nesting, encountered an already checked account, detecting a loop.
- **/
- OuroborosDetected: AugmentedError<ApiType>;
- /**
- * Couldn't find the token owner that is itself a token.
- **/
- TokenNotFound: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- sudo: {
- /**
- * Sender must be the Sudo account
- **/
- RequireSudo: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- system: {
- /**
- * The origin filter prevent the call to be dispatched.
- **/
- CallFiltered: AugmentedError<ApiType>;
- /**
- * Failed to extract the runtime version from the new runtime.
- *
- * Either calling `Core_version` or decoding `RuntimeVersion` failed.
- **/
- FailedToExtractRuntimeVersion: AugmentedError<ApiType>;
- /**
- * The name of specification does not match between the current runtime
- * and the new runtime.
- **/
- InvalidSpecName: AugmentedError<ApiType>;
- /**
- * Suicide called when the account has non-default composite data.
- **/
- NonDefaultComposite: AugmentedError<ApiType>;
- /**
- * There is a non-zero reference count preventing the account from being purged.
- **/
- NonZeroRefCount: AugmentedError<ApiType>;
- /**
- * The specification version is not allowed to decrease between the current runtime
- * and the new runtime.
- **/
- SpecVersionNeedsToIncrease: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- technicalCommittee: {
- /**
- * Members are already initialized!
- **/
- AlreadyInitialized: AugmentedError<ApiType>;
- /**
- * Duplicate proposals not allowed
- **/
- DuplicateProposal: AugmentedError<ApiType>;
- /**
- * Duplicate vote ignored
- **/
- DuplicateVote: AugmentedError<ApiType>;
- /**
- * Account is not a member
- **/
- NotMember: AugmentedError<ApiType>;
- /**
- * Prime account is not a member
- **/
- PrimeAccountNotMember: AugmentedError<ApiType>;
- /**
- * Proposal must exist
- **/
- ProposalMissing: AugmentedError<ApiType>;
- /**
- * The close call was made too early, before the end of the voting.
- **/
- TooEarly: AugmentedError<ApiType>;
- /**
- * There can only be a maximum of `MaxProposals` active proposals.
- **/
- TooManyProposals: AugmentedError<ApiType>;
- /**
- * Mismatched index
- **/
- WrongIndex: AugmentedError<ApiType>;
- /**
- * The given length bound for the proposal was too low.
- **/
- WrongProposalLength: AugmentedError<ApiType>;
- /**
- * The given weight bound for the proposal was too low.
- **/
- WrongProposalWeight: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- technicalCommitteeMembership: {
- /**
- * Already a member.
- **/
- AlreadyMember: AugmentedError<ApiType>;
- /**
- * Not a member.
- **/
- NotMember: AugmentedError<ApiType>;
- /**
- * Too many members.
- **/
- TooManyMembers: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- testUtils: {
- TestPalletDisabled: AugmentedError<ApiType>;
- TriggerRollback: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- tokens: {
- /**
- * Cannot convert Amount into Balance type
- **/
- AmountIntoBalanceFailed: AugmentedError<ApiType>;
- /**
- * The balance is too low
- **/
- BalanceTooLow: AugmentedError<ApiType>;
- /**
- * Beneficiary account must pre-exist
- **/
- DeadAccount: AugmentedError<ApiType>;
- /**
- * Value too low to create account due to existential deposit
- **/
- ExistentialDeposit: AugmentedError<ApiType>;
- /**
- * Transfer/payment would kill account
- **/
- KeepAlive: AugmentedError<ApiType>;
- /**
- * Failed because liquidity restrictions due to locking
- **/
- LiquidityRestrictions: AugmentedError<ApiType>;
- /**
- * Failed because the maximum locks was exceeded
- **/
- MaxLocksExceeded: AugmentedError<ApiType>;
- TooManyReserves: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- treasury: {
- /**
- * The spend origin is valid but the amount it is allowed to spend is lower than the
- * amount to be spent.
- **/
- InsufficientPermission: AugmentedError<ApiType>;
- /**
- * Proposer's balance is too low.
- **/
- InsufficientProposersBalance: AugmentedError<ApiType>;
- /**
- * No proposal or bounty at that index.
- **/
- InvalidIndex: AugmentedError<ApiType>;
- /**
- * Proposal has not been approved.
- **/
- ProposalNotApproved: AugmentedError<ApiType>;
- /**
- * Too many approvals in the queue.
- **/
- TooManyApprovals: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- unique: {
- /**
- * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].
- **/
- CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;
- /**
- * Length of items properties must be greater than 0.
- **/
- EmptyArgument: AugmentedError<ApiType>;
- /**
- * Repertition is only supported by refungible collection.
- **/
- RepartitionCalledOnNonRefungibleCollection: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- utility: {
- /**
- * Too many calls batched.
- **/
- TooManyCalls: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- vesting: {
- /**
- * The vested transfer amount is too low
- **/
- AmountLow: AugmentedError<ApiType>;
- /**
- * Insufficient amount of balance to lock
- **/
- InsufficientBalanceToLock: AugmentedError<ApiType>;
- /**
- * Failed because the maximum vesting schedules was exceeded
- **/
- MaxVestingSchedulesExceeded: AugmentedError<ApiType>;
- /**
- * This account have too many vesting schedules
- **/
- TooManyVestingSchedules: AugmentedError<ApiType>;
- /**
- * Vesting period is zero
- **/
- ZeroVestingPeriod: AugmentedError<ApiType>;
- /**
- * Number of vests is zero
- **/
- ZeroVestingPeriodCount: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- xcmpQueue: {
- /**
- * Bad overweight index.
- **/
- BadOverweightIndex: AugmentedError<ApiType>;
- /**
- * Bad XCM data.
- **/
- BadXcm: AugmentedError<ApiType>;
- /**
- * Bad XCM origin.
- **/
- BadXcmOrigin: AugmentedError<ApiType>;
- /**
- * Failed to send XCM message.
- **/
- FailedToSend: AugmentedError<ApiType>;
- /**
- * Provided weight is possibly not enough to execute the message.
- **/
- WeightOverLimit: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- xTokens: {
- /**
- * Asset has no reserve location.
- **/
- AssetHasNoReserve: AugmentedError<ApiType>;
- /**
- * The specified index does not exist in a MultiAssets struct.
- **/
- AssetIndexNonExistent: AugmentedError<ApiType>;
- /**
- * The version of the `Versioned` value used is not able to be
- * interpreted.
- **/
- BadVersion: AugmentedError<ApiType>;
- /**
- * Could not re-anchor the assets to declare the fees for the
- * destination chain.
- **/
- CannotReanchor: AugmentedError<ApiType>;
- /**
- * The destination `MultiLocation` provided cannot be inverted.
- **/
- DestinationNotInvertible: AugmentedError<ApiType>;
- /**
- * We tried sending distinct asset and fee but they have different
- * reserve chains.
- **/
- DistinctReserveForAssetAndFee: AugmentedError<ApiType>;
- /**
- * Fee is not enough.
- **/
- FeeNotEnough: AugmentedError<ApiType>;
- /**
- * Could not get ancestry of asset reserve location.
- **/
- InvalidAncestry: AugmentedError<ApiType>;
- /**
- * The MultiAsset is invalid.
- **/
- InvalidAsset: AugmentedError<ApiType>;
- /**
- * Invalid transfer destination.
- **/
- InvalidDest: AugmentedError<ApiType>;
- /**
- * MinXcmFee not registered for certain reserve location
- **/
- MinXcmFeeNotDefined: AugmentedError<ApiType>;
- /**
- * Not cross-chain transfer.
- **/
- NotCrossChainTransfer: AugmentedError<ApiType>;
- /**
- * Currency is not cross-chain transferable.
- **/
- NotCrossChainTransferableCurrency: AugmentedError<ApiType>;
- /**
- * Not supported MultiLocation
- **/
- NotSupportedMultiLocation: AugmentedError<ApiType>;
- /**
- * The number of assets to be sent is over the maximum.
- **/
- TooManyAssetsBeingSent: AugmentedError<ApiType>;
- /**
- * The message's weight could not be determined.
- **/
- UnweighableMessage: AugmentedError<ApiType>;
- /**
- * XCM execution failed.
- **/
- XcmExecutionFailed: AugmentedError<ApiType>;
- /**
- * The transfering asset amount is zero.
- **/
- ZeroAmount: AugmentedError<ApiType>;
- /**
- * The fee is zero.
- **/
- ZeroFee: AugmentedError<ApiType>;
- /**
- * Generic error
- **/
- [key: string]: AugmentedError<ApiType>;
- };
- } // AugmentedErrors
-} // declare module
js-packages/types/src/augment-api-events.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-events.ts
+++ /dev/null
@@ -1,1294 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/api-base/types/events';
-
-import type { ApiTypes, AugmentedEvent } from '@polkadot/api-base/types';
-import type { Bytes, Null, Option, Result, U8aFixed, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
-import type { ITuple } from '@polkadot/types-codec/types';
-import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';
-import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportDispatchDispatchInfo, FrameSupportPreimagesBounded, FrameSupportTokensMiscBalanceStatus, OrmlVestingVestingSchedule, PalletDemocracyMetadataOwner, PalletDemocracyVoteAccountVote, PalletDemocracyVoteThreshold, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletRankedCollectiveTally, PalletRankedCollectiveVoteRecord, PalletStateTrieMigrationError, PalletStateTrieMigrationMigrationCompute, SpRuntimeDispatchError, SpWeightsWeightV2Weight, StagingXcmV3MultiAsset, StagingXcmV3MultiLocation, StagingXcmV3MultiassetMultiAssets, StagingXcmV3Response, StagingXcmV3TraitsError, StagingXcmV3TraitsOutcome, StagingXcmV3Xcm, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation } from '@polkadot/types/lookup';
-
-export type __AugmentedEvent<ApiType extends ApiTypes> = AugmentedEvent<ApiType>;
-
-declare module '@polkadot/api-base/types/events' {
- interface AugmentedEvents<ApiType extends ApiTypes> {
- appPromotion: {
- /**
- * The admin was set
- *
- * # Arguments
- * * AccountId: account address of the admin
- **/
- SetAdmin: AugmentedEvent<ApiType, [AccountId32]>;
- /**
- * Staking was performed
- *
- * # Arguments
- * * AccountId: account of the staker
- * * Balance : staking amount
- **/
- Stake: AugmentedEvent<ApiType, [AccountId32, u128]>;
- /**
- * Staking recalculation was performed
- *
- * # Arguments
- * * AccountId: account of the staker.
- * * Balance : recalculation base
- * * Balance : total income
- **/
- StakingRecalculation: AugmentedEvent<ApiType, [AccountId32, u128, u128]>;
- /**
- * Unstaking was performed
- *
- * # Arguments
- * * AccountId: account of the staker
- * * Balance : unstaking amount
- **/
- Unstake: AugmentedEvent<ApiType, [AccountId32, u128]>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- balances: {
- /**
- * A balance was set by root.
- **/
- BalanceSet: AugmentedEvent<ApiType, [who: AccountId32, free: u128], { who: AccountId32, free: u128 }>;
- /**
- * Some amount was burned from an account.
- **/
- Burned: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some amount was deposited (e.g. for transaction fees).
- **/
- Deposit: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * An account was removed whose balance was non-zero but below ExistentialDeposit,
- * resulting in an outright loss.
- **/
- DustLost: AugmentedEvent<ApiType, [account: AccountId32, amount: u128], { account: AccountId32, amount: u128 }>;
- /**
- * An account was created with some free balance.
- **/
- Endowed: AugmentedEvent<ApiType, [account: AccountId32, freeBalance: u128], { account: AccountId32, freeBalance: u128 }>;
- /**
- * Some balance was frozen.
- **/
- Frozen: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Total issuance was increased by `amount`, creating a credit to be balanced.
- **/
- Issued: AugmentedEvent<ApiType, [amount: u128], { amount: u128 }>;
- /**
- * Some balance was locked.
- **/
- Locked: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some amount was minted into an account.
- **/
- Minted: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Total issuance was decreased by `amount`, creating a debt to be balanced.
- **/
- Rescinded: AugmentedEvent<ApiType, [amount: u128], { amount: u128 }>;
- /**
- * Some balance was reserved (moved from free to reserved).
- **/
- Reserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some balance was moved from the reserve of the first account to the second account.
- * Final argument indicates the destination balance type.
- **/
- ReserveRepatriated: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus], { from: AccountId32, to: AccountId32, amount: u128, destinationStatus: FrameSupportTokensMiscBalanceStatus }>;
- /**
- * Some amount was restored into an account.
- **/
- Restored: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some amount was removed from the account (e.g. for misbehavior).
- **/
- Slashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some amount was suspended from an account (it can be restored later).
- **/
- Suspended: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some balance was thawed.
- **/
- Thawed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Transfer succeeded.
- **/
- Transfer: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, amount: u128], { from: AccountId32, to: AccountId32, amount: u128 }>;
- /**
- * Some balance was unlocked.
- **/
- Unlocked: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Some balance was unreserved (moved from reserved to free).
- **/
- Unreserved: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * An account was upgraded.
- **/
- Upgraded: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
- /**
- * Some amount was withdrawn from the account (e.g. for transaction fees).
- **/
- Withdraw: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- collatorSelection: {
- CandidateAdded: AugmentedEvent<ApiType, [accountId: AccountId32], { accountId: AccountId32 }>;
- CandidateRemoved: AugmentedEvent<ApiType, [accountId: AccountId32], { accountId: AccountId32 }>;
- InvulnerableAdded: AugmentedEvent<ApiType, [invulnerable: AccountId32], { invulnerable: AccountId32 }>;
- InvulnerableRemoved: AugmentedEvent<ApiType, [invulnerable: AccountId32], { invulnerable: AccountId32 }>;
- LicenseObtained: AugmentedEvent<ApiType, [accountId: AccountId32, deposit: u128], { accountId: AccountId32, deposit: u128 }>;
- LicenseReleased: AugmentedEvent<ApiType, [accountId: AccountId32, depositReturned: u128], { accountId: AccountId32, depositReturned: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- common: {
- /**
- * Address was added to the allow list.
- **/
- AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Address was removed from the allow list.
- **/
- AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Amount pieces of token owned by `sender` was approved for `spender`.
- **/
- Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- /**
- * A `sender` approves operations on all owned tokens for `spender`.
- **/
- ApprovedForAll: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
- /**
- * Collection admin was added.
- **/
- CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Collection admin was removed.
- **/
- CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * New collection was created
- **/
- CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;
- /**
- * New collection was destroyed
- **/
- CollectionDestroyed: AugmentedEvent<ApiType, [u32]>;
- /**
- * Collection limits were set.
- **/
- CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;
- /**
- * Collection owned was changed.
- **/
- CollectionOwnerChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;
- /**
- * Collection permissions were set.
- **/
- CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;
- /**
- * The property has been deleted.
- **/
- CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;
- /**
- * The colletion property has been added or edited.
- **/
- CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;
- /**
- * Collection sponsor was removed.
- **/
- CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;
- /**
- * Collection sponsor was set.
- **/
- CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;
- /**
- * New item was created.
- **/
- ItemCreated: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- /**
- * Collection item was burned.
- **/
- ItemDestroyed: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- /**
- * The token property permission of a collection has been set.
- **/
- PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;
- /**
- * New sponsor was confirm.
- **/
- SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;
- /**
- * The token property has been deleted.
- **/
- TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
- /**
- * The token property has been added or edited.
- **/
- TokenPropertySet: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
- /**
- * Item was transferred
- **/
- Transfer: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- configuration: {
- NewCollatorKickThreshold: AugmentedEvent<ApiType, [lengthInBlocks: Option<u32>], { lengthInBlocks: Option<u32> }>;
- NewCollatorLicenseBond: AugmentedEvent<ApiType, [bondCost: Option<u128>], { bondCost: Option<u128> }>;
- NewDesiredCollators: AugmentedEvent<ApiType, [desiredCollators: Option<u32>], { desiredCollators: Option<u32> }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- council: {
- /**
- * A motion was approved by the required threshold.
- **/
- Approved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
- /**
- * A proposal was closed because its threshold was reached or after its duration was up.
- **/
- Closed: AugmentedEvent<ApiType, [proposalHash: H256, yes: u32, no: u32], { proposalHash: H256, yes: u32, no: u32 }>;
- /**
- * A motion was not approved by the required threshold.
- **/
- Disapproved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
- /**
- * A motion was executed; result will be `Ok` if it returned without error.
- **/
- Executed: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * A single member did some action; result will be `Ok` if it returned without error.
- **/
- MemberExecuted: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * A motion (given hash) has been proposed (by given account) with a threshold (given
- * `MemberCount`).
- **/
- Proposed: AugmentedEvent<ApiType, [account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32], { account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32 }>;
- /**
- * A motion (given hash) has been voted on by given account, leaving
- * a tally (yes votes and no votes given respectively as `MemberCount`).
- **/
- Voted: AugmentedEvent<ApiType, [account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32], { account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- councilMembership: {
- /**
- * Phantom member, never used.
- **/
- Dummy: AugmentedEvent<ApiType, []>;
- /**
- * One of the members' keys changed.
- **/
- KeyChanged: AugmentedEvent<ApiType, []>;
- /**
- * The given member was added; see the transaction for who.
- **/
- MemberAdded: AugmentedEvent<ApiType, []>;
- /**
- * The given member was removed; see the transaction for who.
- **/
- MemberRemoved: AugmentedEvent<ApiType, []>;
- /**
- * The membership was reset; see the transaction for who the new set is.
- **/
- MembersReset: AugmentedEvent<ApiType, []>;
- /**
- * Two members were swapped; see the transaction for who.
- **/
- MembersSwapped: AugmentedEvent<ApiType, []>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- cumulusXcm: {
- /**
- * Downward message executed with the given outcome.
- * \[ id, outcome \]
- **/
- ExecutedDownward: AugmentedEvent<ApiType, [U8aFixed, StagingXcmV3TraitsOutcome]>;
- /**
- * Downward message is invalid XCM.
- * \[ id \]
- **/
- InvalidFormat: AugmentedEvent<ApiType, [U8aFixed]>;
- /**
- * Downward message is unsupported version of XCM.
- * \[ id \]
- **/
- UnsupportedVersion: AugmentedEvent<ApiType, [U8aFixed]>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- democracy: {
- /**
- * A proposal_hash has been blacklisted permanently.
- **/
- Blacklisted: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
- /**
- * A referendum has been cancelled.
- **/
- Cancelled: AugmentedEvent<ApiType, [refIndex: u32], { refIndex: u32 }>;
- /**
- * An account has delegated their vote to another account.
- **/
- Delegated: AugmentedEvent<ApiType, [who: AccountId32, target: AccountId32], { who: AccountId32, target: AccountId32 }>;
- /**
- * An external proposal has been tabled.
- **/
- ExternalTabled: AugmentedEvent<ApiType, []>;
- /**
- * Metadata for a proposal or a referendum has been cleared.
- **/
- MetadataCleared: AugmentedEvent<ApiType, [owner: PalletDemocracyMetadataOwner, hash_: H256], { owner: PalletDemocracyMetadataOwner, hash_: H256 }>;
- /**
- * Metadata for a proposal or a referendum has been set.
- **/
- MetadataSet: AugmentedEvent<ApiType, [owner: PalletDemocracyMetadataOwner, hash_: H256], { owner: PalletDemocracyMetadataOwner, hash_: H256 }>;
- /**
- * Metadata has been transferred to new owner.
- **/
- MetadataTransferred: AugmentedEvent<ApiType, [prevOwner: PalletDemocracyMetadataOwner, owner: PalletDemocracyMetadataOwner, hash_: H256], { prevOwner: PalletDemocracyMetadataOwner, owner: PalletDemocracyMetadataOwner, hash_: H256 }>;
- /**
- * A proposal has been rejected by referendum.
- **/
- NotPassed: AugmentedEvent<ApiType, [refIndex: u32], { refIndex: u32 }>;
- /**
- * A proposal has been approved by referendum.
- **/
- Passed: AugmentedEvent<ApiType, [refIndex: u32], { refIndex: u32 }>;
- /**
- * A proposal got canceled.
- **/
- ProposalCanceled: AugmentedEvent<ApiType, [propIndex: u32], { propIndex: u32 }>;
- /**
- * A motion has been proposed by a public account.
- **/
- Proposed: AugmentedEvent<ApiType, [proposalIndex: u32, deposit: u128], { proposalIndex: u32, deposit: u128 }>;
- /**
- * An account has secconded a proposal
- **/
- Seconded: AugmentedEvent<ApiType, [seconder: AccountId32, propIndex: u32], { seconder: AccountId32, propIndex: u32 }>;
- /**
- * A referendum has begun.
- **/
- Started: AugmentedEvent<ApiType, [refIndex: u32, threshold: PalletDemocracyVoteThreshold], { refIndex: u32, threshold: PalletDemocracyVoteThreshold }>;
- /**
- * A public proposal has been tabled for referendum vote.
- **/
- Tabled: AugmentedEvent<ApiType, [proposalIndex: u32, deposit: u128], { proposalIndex: u32, deposit: u128 }>;
- /**
- * An account has cancelled a previous delegation operation.
- **/
- Undelegated: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;
- /**
- * An external proposal has been vetoed.
- **/
- Vetoed: AugmentedEvent<ApiType, [who: AccountId32, proposalHash: H256, until: u32], { who: AccountId32, proposalHash: H256, until: u32 }>;
- /**
- * An account has voted in a referendum
- **/
- Voted: AugmentedEvent<ApiType, [voter: AccountId32, refIndex: u32, vote: PalletDemocracyVoteAccountVote], { voter: AccountId32, refIndex: u32, vote: PalletDemocracyVoteAccountVote }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- dmpQueue: {
- /**
- * Downward message executed with the given outcome.
- **/
- ExecutedDownward: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, outcome: StagingXcmV3TraitsOutcome], { messageHash: U8aFixed, messageId: U8aFixed, outcome: StagingXcmV3TraitsOutcome }>;
- /**
- * Downward message is invalid XCM.
- **/
- InvalidFormat: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
- /**
- * The maximum number of downward messages was reached.
- **/
- MaxMessagesExhausted: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
- /**
- * Downward message is overweight and was placed in the overweight queue.
- **/
- OverweightEnqueued: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, overweightIndex: u64, requiredWeight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, overweightIndex: u64, requiredWeight: SpWeightsWeightV2Weight }>;
- /**
- * Downward message from the overweight queue was executed.
- **/
- OverweightServiced: AugmentedEvent<ApiType, [overweightIndex: u64, weightUsed: SpWeightsWeightV2Weight], { overweightIndex: u64, weightUsed: SpWeightsWeightV2Weight }>;
- /**
- * Downward message is unsupported version of XCM.
- **/
- UnsupportedVersion: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
- /**
- * The weight limit for handling downward messages was reached.
- **/
- WeightExhausted: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, remainingWeight: SpWeightsWeightV2Weight, requiredWeight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, remainingWeight: SpWeightsWeightV2Weight, requiredWeight: SpWeightsWeightV2Weight }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- ethereum: {
- /**
- * An ethereum transaction was successfully executed.
- **/
- Executed: AugmentedEvent<ApiType, [from: H160, to: H160, transactionHash: H256, exitReason: EvmCoreErrorExitReason, extraData: Bytes], { from: H160, to: H160, transactionHash: H256, exitReason: EvmCoreErrorExitReason, extraData: Bytes }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- evm: {
- /**
- * A contract has been created at given address.
- **/
- Created: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
- /**
- * A contract was attempted to be created, but the execution failed.
- **/
- CreatedFailed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
- /**
- * A contract has been executed successfully with states applied.
- **/
- Executed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
- /**
- * A contract has been executed with errors. States are reverted with only gas fees applied.
- **/
- ExecutedFailed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
- /**
- * Ethereum events from contracts.
- **/
- Log: AugmentedEvent<ApiType, [log: EthereumLog], { log: EthereumLog }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- evmContractHelpers: {
- /**
- * Collection sponsor was removed.
- **/
- ContractSponsorRemoved: AugmentedEvent<ApiType, [H160]>;
- /**
- * Contract sponsor was set.
- **/
- ContractSponsorSet: AugmentedEvent<ApiType, [H160, AccountId32]>;
- /**
- * New sponsor was confirm.
- **/
- ContractSponsorshipConfirmed: AugmentedEvent<ApiType, [H160, AccountId32]>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- evmMigration: {
- /**
- * This event is used in benchmarking and can be used for tests
- **/
- TestEvent: AugmentedEvent<ApiType, []>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- fellowshipCollective: {
- /**
- * A member `who` has been added.
- **/
- MemberAdded: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
- /**
- * The member `who` of given `rank` has been removed from the collective.
- **/
- MemberRemoved: AugmentedEvent<ApiType, [who: AccountId32, rank: u16], { who: AccountId32, rank: u16 }>;
- /**
- * The member `who`se rank has been changed to the given `rank`.
- **/
- RankChanged: AugmentedEvent<ApiType, [who: AccountId32, rank: u16], { who: AccountId32, rank: u16 }>;
- /**
- * The member `who` has voted for the `poll` with the given `vote` leading to an updated
- * `tally`.
- **/
- Voted: AugmentedEvent<ApiType, [who: AccountId32, poll: u32, vote: PalletRankedCollectiveVoteRecord, tally: PalletRankedCollectiveTally], { who: AccountId32, poll: u32, vote: PalletRankedCollectiveVoteRecord, tally: PalletRankedCollectiveTally }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- fellowshipReferenda: {
- /**
- * A referendum has been approved and its proposal has been scheduled.
- **/
- Approved: AugmentedEvent<ApiType, [index: u32], { index: u32 }>;
- /**
- * A referendum has been cancelled.
- **/
- Cancelled: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
- ConfirmAborted: AugmentedEvent<ApiType, [index: u32], { index: u32 }>;
- /**
- * A referendum has ended its confirmation phase and is ready for approval.
- **/
- Confirmed: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
- ConfirmStarted: AugmentedEvent<ApiType, [index: u32], { index: u32 }>;
- /**
- * The decision deposit has been placed.
- **/
- DecisionDepositPlaced: AugmentedEvent<ApiType, [index: u32, who: AccountId32, amount: u128], { index: u32, who: AccountId32, amount: u128 }>;
- /**
- * The decision deposit has been refunded.
- **/
- DecisionDepositRefunded: AugmentedEvent<ApiType, [index: u32, who: AccountId32, amount: u128], { index: u32, who: AccountId32, amount: u128 }>;
- /**
- * A referendum has moved into the deciding phase.
- **/
- DecisionStarted: AugmentedEvent<ApiType, [index: u32, track: u16, proposal: FrameSupportPreimagesBounded, tally: PalletRankedCollectiveTally], { index: u32, track: u16, proposal: FrameSupportPreimagesBounded, tally: PalletRankedCollectiveTally }>;
- /**
- * A deposit has been slashaed.
- **/
- DepositSlashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * A referendum has been killed.
- **/
- Killed: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
- /**
- * Metadata for a referendum has been cleared.
- **/
- MetadataCleared: AugmentedEvent<ApiType, [index: u32, hash_: H256], { index: u32, hash_: H256 }>;
- /**
- * Metadata for a referendum has been set.
- **/
- MetadataSet: AugmentedEvent<ApiType, [index: u32, hash_: H256], { index: u32, hash_: H256 }>;
- /**
- * A proposal has been rejected by referendum.
- **/
- Rejected: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
- /**
- * The submission deposit has been refunded.
- **/
- SubmissionDepositRefunded: AugmentedEvent<ApiType, [index: u32, who: AccountId32, amount: u128], { index: u32, who: AccountId32, amount: u128 }>;
- /**
- * A referendum has been submitted.
- **/
- Submitted: AugmentedEvent<ApiType, [index: u32, track: u16, proposal: FrameSupportPreimagesBounded], { index: u32, track: u16, proposal: FrameSupportPreimagesBounded }>;
- /**
- * A referendum has been timed out without being decided.
- **/
- TimedOut: AugmentedEvent<ApiType, [index: u32, tally: PalletRankedCollectiveTally], { index: u32, tally: PalletRankedCollectiveTally }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- foreignAssets: {
- /**
- * The asset registered.
- **/
- AssetRegistered: AugmentedEvent<ApiType, [assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata }>;
- /**
- * The asset updated.
- **/
- AssetUpdated: AugmentedEvent<ApiType, [assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: PalletForeignAssetsAssetId, metadata: PalletForeignAssetsModuleAssetMetadata }>;
- /**
- * The foreign asset registered.
- **/
- ForeignAssetRegistered: AugmentedEvent<ApiType, [assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata }>;
- /**
- * The foreign asset updated.
- **/
- ForeignAssetUpdated: AugmentedEvent<ApiType, [assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata], { assetId: u32, assetAddress: StagingXcmV3MultiLocation, metadata: PalletForeignAssetsModuleAssetMetadata }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- identity: {
- /**
- * A number of identities and associated info were forcibly inserted.
- **/
- IdentitiesInserted: AugmentedEvent<ApiType, [amount: u32], { amount: u32 }>;
- /**
- * A number of identities and all associated info were forcibly removed.
- **/
- IdentitiesRemoved: AugmentedEvent<ApiType, [amount: u32], { amount: u32 }>;
- /**
- * A name was cleared, and the given balance returned.
- **/
- IdentityCleared: AugmentedEvent<ApiType, [who: AccountId32, deposit: u128], { who: AccountId32, deposit: u128 }>;
- /**
- * A name was removed and the given balance slashed.
- **/
- IdentityKilled: AugmentedEvent<ApiType, [who: AccountId32, deposit: u128], { who: AccountId32, deposit: u128 }>;
- /**
- * A name was set or reset (which will remove all judgements).
- **/
- IdentitySet: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
- /**
- * A judgement was given by a registrar.
- **/
- JudgementGiven: AugmentedEvent<ApiType, [target: AccountId32, registrarIndex: u32], { target: AccountId32, registrarIndex: u32 }>;
- /**
- * A judgement was asked from a registrar.
- **/
- JudgementRequested: AugmentedEvent<ApiType, [who: AccountId32, registrarIndex: u32], { who: AccountId32, registrarIndex: u32 }>;
- /**
- * A judgement request was retracted.
- **/
- JudgementUnrequested: AugmentedEvent<ApiType, [who: AccountId32, registrarIndex: u32], { who: AccountId32, registrarIndex: u32 }>;
- /**
- * A registrar was added.
- **/
- RegistrarAdded: AugmentedEvent<ApiType, [registrarIndex: u32], { registrarIndex: u32 }>;
- /**
- * A number of identities were forcibly updated with new sub-identities.
- **/
- SubIdentitiesInserted: AugmentedEvent<ApiType, [amount: u32], { amount: u32 }>;
- /**
- * A sub-identity was added to an identity and the deposit paid.
- **/
- SubIdentityAdded: AugmentedEvent<ApiType, [sub: AccountId32, main: AccountId32, deposit: u128], { sub: AccountId32, main: AccountId32, deposit: u128 }>;
- /**
- * A sub-identity was removed from an identity and the deposit freed.
- **/
- SubIdentityRemoved: AugmentedEvent<ApiType, [sub: AccountId32, main: AccountId32, deposit: u128], { sub: AccountId32, main: AccountId32, deposit: u128 }>;
- /**
- * A sub-identity was cleared, and the given deposit repatriated from the
- * main identity account to the sub-identity account.
- **/
- SubIdentityRevoked: AugmentedEvent<ApiType, [sub: AccountId32, main: AccountId32, deposit: u128], { sub: AccountId32, main: AccountId32, deposit: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- maintenance: {
- MaintenanceDisabled: AugmentedEvent<ApiType, []>;
- MaintenanceEnabled: AugmentedEvent<ApiType, []>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- parachainSystem: {
- /**
- * Downward messages were processed using the given weight.
- **/
- DownwardMessagesProcessed: AugmentedEvent<ApiType, [weightUsed: SpWeightsWeightV2Weight, dmqHead: H256], { weightUsed: SpWeightsWeightV2Weight, dmqHead: H256 }>;
- /**
- * Some downward messages have been received and will be processed.
- **/
- DownwardMessagesReceived: AugmentedEvent<ApiType, [count: u32], { count: u32 }>;
- /**
- * An upgrade has been authorized.
- **/
- UpgradeAuthorized: AugmentedEvent<ApiType, [codeHash: H256], { codeHash: H256 }>;
- /**
- * An upward message was sent to the relay chain.
- **/
- UpwardMessageSent: AugmentedEvent<ApiType, [messageHash: Option<U8aFixed>], { messageHash: Option<U8aFixed> }>;
- /**
- * The validation function was applied as of the contained relay chain block number.
- **/
- ValidationFunctionApplied: AugmentedEvent<ApiType, [relayChainBlockNum: u32], { relayChainBlockNum: u32 }>;
- /**
- * The relay-chain aborted the upgrade process.
- **/
- ValidationFunctionDiscarded: AugmentedEvent<ApiType, []>;
- /**
- * The validation function has been scheduled to apply.
- **/
- ValidationFunctionStored: AugmentedEvent<ApiType, []>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- polkadotXcm: {
- /**
- * Some assets have been claimed from an asset trap
- **/
- AssetsClaimed: AugmentedEvent<ApiType, [hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets], { hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets }>;
- /**
- * Some assets have been placed in an asset trap.
- **/
- AssetsTrapped: AugmentedEvent<ApiType, [hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets], { hash_: H256, origin: StagingXcmV3MultiLocation, assets: StagingXcmVersionedMultiAssets }>;
- /**
- * Execution of an XCM message was attempted.
- **/
- Attempted: AugmentedEvent<ApiType, [outcome: StagingXcmV3TraitsOutcome], { outcome: StagingXcmV3TraitsOutcome }>;
- /**
- * Fees were paid from a location for an operation (often for using `SendXcm`).
- **/
- FeesPaid: AugmentedEvent<ApiType, [paying: StagingXcmV3MultiLocation, fees: StagingXcmV3MultiassetMultiAssets], { paying: StagingXcmV3MultiLocation, fees: StagingXcmV3MultiassetMultiAssets }>;
- /**
- * Expected query response has been received but the querier location of the response does
- * not match the expected. The query remains registered for a later, valid, response to
- * be received and acted upon.
- **/
- InvalidQuerier: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64, expectedQuerier: StagingXcmV3MultiLocation, maybeActualQuerier: Option<StagingXcmV3MultiLocation>], { origin: StagingXcmV3MultiLocation, queryId: u64, expectedQuerier: StagingXcmV3MultiLocation, maybeActualQuerier: Option<StagingXcmV3MultiLocation> }>;
- /**
- * Expected query response has been received but the expected querier location placed in
- * storage by this runtime previously cannot be decoded. The query remains registered.
- *
- * This is unexpected (since a location placed in storage in a previously executing
- * runtime should be readable prior to query timeout) and dangerous since the possibly
- * valid response will be dropped. Manual governance intervention is probably going to be
- * needed.
- **/
- InvalidQuerierVersion: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64], { origin: StagingXcmV3MultiLocation, queryId: u64 }>;
- /**
- * Expected query response has been received but the origin location of the response does
- * not match that expected. The query remains registered for a later, valid, response to
- * be received and acted upon.
- **/
- InvalidResponder: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64, expectedLocation: Option<StagingXcmV3MultiLocation>], { origin: StagingXcmV3MultiLocation, queryId: u64, expectedLocation: Option<StagingXcmV3MultiLocation> }>;
- /**
- * Expected query response has been received but the expected origin location placed in
- * storage by this runtime previously cannot be decoded. The query remains registered.
- *
- * This is unexpected (since a location placed in storage in a previously executing
- * runtime should be readable prior to query timeout) and dangerous since the possibly
- * valid response will be dropped. Manual governance intervention is probably going to be
- * needed.
- **/
- InvalidResponderVersion: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64], { origin: StagingXcmV3MultiLocation, queryId: u64 }>;
- /**
- * Query response has been received and query is removed. The registered notification has
- * been dispatched and executed successfully.
- **/
- Notified: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8], { queryId: u64, palletIndex: u8, callIndex: u8 }>;
- /**
- * Query response has been received and query is removed. The dispatch was unable to be
- * decoded into a `Call`; this might be due to dispatch function having a signature which
- * is not `(origin, QueryId, Response)`.
- **/
- NotifyDecodeFailed: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8], { queryId: u64, palletIndex: u8, callIndex: u8 }>;
- /**
- * Query response has been received and query is removed. There was a general error with
- * dispatching the notification call.
- **/
- NotifyDispatchError: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8], { queryId: u64, palletIndex: u8, callIndex: u8 }>;
- /**
- * Query response has been received and query is removed. The registered notification
- * could not be dispatched because the dispatch weight is greater than the maximum weight
- * originally budgeted by this runtime for the query result.
- **/
- NotifyOverweight: AugmentedEvent<ApiType, [queryId: u64, palletIndex: u8, callIndex: u8, actualWeight: SpWeightsWeightV2Weight, maxBudgetedWeight: SpWeightsWeightV2Weight], { queryId: u64, palletIndex: u8, callIndex: u8, actualWeight: SpWeightsWeightV2Weight, maxBudgetedWeight: SpWeightsWeightV2Weight }>;
- /**
- * A given location which had a version change subscription was dropped owing to an error
- * migrating the location to our new XCM format.
- **/
- NotifyTargetMigrationFail: AugmentedEvent<ApiType, [location: StagingXcmVersionedMultiLocation, queryId: u64], { location: StagingXcmVersionedMultiLocation, queryId: u64 }>;
- /**
- * A given location which had a version change subscription was dropped owing to an error
- * sending the notification to it.
- **/
- NotifyTargetSendFail: AugmentedEvent<ApiType, [location: StagingXcmV3MultiLocation, queryId: u64, error: StagingXcmV3TraitsError], { location: StagingXcmV3MultiLocation, queryId: u64, error: StagingXcmV3TraitsError }>;
- /**
- * Query response has been received and is ready for taking with `take_response`. There is
- * no registered notification call.
- **/
- ResponseReady: AugmentedEvent<ApiType, [queryId: u64, response: StagingXcmV3Response], { queryId: u64, response: StagingXcmV3Response }>;
- /**
- * Received query response has been read and removed.
- **/
- ResponseTaken: AugmentedEvent<ApiType, [queryId: u64], { queryId: u64 }>;
- /**
- * A XCM message was sent.
- **/
- Sent: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, destination: StagingXcmV3MultiLocation, message: StagingXcmV3Xcm, messageId: U8aFixed], { origin: StagingXcmV3MultiLocation, destination: StagingXcmV3MultiLocation, message: StagingXcmV3Xcm, messageId: U8aFixed }>;
- /**
- * The supported version of a location has been changed. This might be through an
- * automatic notification or a manual intervention.
- **/
- SupportedVersionChanged: AugmentedEvent<ApiType, [location: StagingXcmV3MultiLocation, version: u32], { location: StagingXcmV3MultiLocation, version: u32 }>;
- /**
- * Query response received which does not match a registered query. This may be because a
- * matching query was never registered, it may be because it is a duplicate response, or
- * because the query timed out.
- **/
- UnexpectedResponse: AugmentedEvent<ApiType, [origin: StagingXcmV3MultiLocation, queryId: u64], { origin: StagingXcmV3MultiLocation, queryId: u64 }>;
- /**
- * An XCM version change notification message has been attempted to be sent.
- *
- * The cost of sending it (borne by the chain) is included.
- **/
- VersionChangeNotified: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, result: u32, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, result: u32, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
- /**
- * We have requested that a remote chain send us XCM version change notifications.
- **/
- VersionNotifyRequested: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
- /**
- * A remote has requested XCM version change notification from us and we have honored it.
- * A version information message is sent to them and its cost is included.
- **/
- VersionNotifyStarted: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
- /**
- * We have requested that a remote chain stops sending us XCM version change
- * notifications.
- **/
- VersionNotifyUnrequested: AugmentedEvent<ApiType, [destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed], { destination: StagingXcmV3MultiLocation, cost: StagingXcmV3MultiassetMultiAssets, messageId: U8aFixed }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- preimage: {
- /**
- * A preimage has ben cleared.
- **/
- Cleared: AugmentedEvent<ApiType, [hash_: H256], { hash_: H256 }>;
- /**
- * A preimage has been noted.
- **/
- Noted: AugmentedEvent<ApiType, [hash_: H256], { hash_: H256 }>;
- /**
- * A preimage has been requested.
- **/
- Requested: AugmentedEvent<ApiType, [hash_: H256], { hash_: H256 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- scheduler: {
- /**
- * The call for the provided hash was not found so the task has been aborted.
- **/
- CallUnavailable: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
- /**
- * Canceled some task.
- **/
- Canceled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;
- /**
- * Dispatched some task.
- **/
- Dispatched: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * The given task was unable to be renewed since the agenda is full at that block.
- **/
- PeriodicFailed: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
- /**
- * The given task can never be executed since it is overweight.
- **/
- PermanentlyOverweight: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
- /**
- * Scheduled some task.
- **/
- Scheduled: AugmentedEvent<ApiType, [when: u32, index: u32], { when: u32, index: u32 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- session: {
- /**
- * New session has happened. Note that the argument is the session index, not the
- * block number as the type might suggest.
- **/
- NewSession: AugmentedEvent<ApiType, [sessionIndex: u32], { sessionIndex: u32 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- stateTrieMigration: {
- /**
- * The auto migration task finished.
- **/
- AutoMigrationFinished: AugmentedEvent<ApiType, []>;
- /**
- * Migration got halted due to an error or miss-configuration.
- **/
- Halted: AugmentedEvent<ApiType, [error: PalletStateTrieMigrationError], { error: PalletStateTrieMigrationError }>;
- /**
- * Given number of `(top, child)` keys were migrated respectively, with the given
- * `compute`.
- **/
- Migrated: AugmentedEvent<ApiType, [top: u32, child: u32, compute: PalletStateTrieMigrationMigrationCompute], { top: u32, child: u32, compute: PalletStateTrieMigrationMigrationCompute }>;
- /**
- * Some account got slashed by the given amount.
- **/
- Slashed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- structure: {
- /**
- * Executed call on behalf of the token.
- **/
- Executed: AugmentedEvent<ApiType, [Result<Null, SpRuntimeDispatchError>]>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- sudo: {
- /**
- * The \[sudoer\] just switched identity; the old key is supplied if one existed.
- **/
- KeyChanged: AugmentedEvent<ApiType, [oldSudoer: Option<AccountId32>], { oldSudoer: Option<AccountId32> }>;
- /**
- * A sudo just took place. \[result\]
- **/
- Sudid: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * A sudo just took place. \[result\]
- **/
- SudoAsDone: AugmentedEvent<ApiType, [sudoResult: Result<Null, SpRuntimeDispatchError>], { sudoResult: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- system: {
- /**
- * `:code` was updated.
- **/
- CodeUpdated: AugmentedEvent<ApiType, []>;
- /**
- * An extrinsic failed.
- **/
- ExtrinsicFailed: AugmentedEvent<ApiType, [dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportDispatchDispatchInfo], { dispatchError: SpRuntimeDispatchError, dispatchInfo: FrameSupportDispatchDispatchInfo }>;
- /**
- * An extrinsic completed successfully.
- **/
- ExtrinsicSuccess: AugmentedEvent<ApiType, [dispatchInfo: FrameSupportDispatchDispatchInfo], { dispatchInfo: FrameSupportDispatchDispatchInfo }>;
- /**
- * An account was reaped.
- **/
- KilledAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;
- /**
- * A new account was created.
- **/
- NewAccount: AugmentedEvent<ApiType, [account: AccountId32], { account: AccountId32 }>;
- /**
- * On on-chain remark happened.
- **/
- Remarked: AugmentedEvent<ApiType, [sender: AccountId32, hash_: H256], { sender: AccountId32, hash_: H256 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- technicalCommittee: {
- /**
- * A motion was approved by the required threshold.
- **/
- Approved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
- /**
- * A proposal was closed because its threshold was reached or after its duration was up.
- **/
- Closed: AugmentedEvent<ApiType, [proposalHash: H256, yes: u32, no: u32], { proposalHash: H256, yes: u32, no: u32 }>;
- /**
- * A motion was not approved by the required threshold.
- **/
- Disapproved: AugmentedEvent<ApiType, [proposalHash: H256], { proposalHash: H256 }>;
- /**
- * A motion was executed; result will be `Ok` if it returned without error.
- **/
- Executed: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * A single member did some action; result will be `Ok` if it returned without error.
- **/
- MemberExecuted: AugmentedEvent<ApiType, [proposalHash: H256, result: Result<Null, SpRuntimeDispatchError>], { proposalHash: H256, result: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * A motion (given hash) has been proposed (by given account) with a threshold (given
- * `MemberCount`).
- **/
- Proposed: AugmentedEvent<ApiType, [account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32], { account: AccountId32, proposalIndex: u32, proposalHash: H256, threshold: u32 }>;
- /**
- * A motion (given hash) has been voted on by given account, leaving
- * a tally (yes votes and no votes given respectively as `MemberCount`).
- **/
- Voted: AugmentedEvent<ApiType, [account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32], { account: AccountId32, proposalHash: H256, voted: bool, yes: u32, no: u32 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- technicalCommitteeMembership: {
- /**
- * Phantom member, never used.
- **/
- Dummy: AugmentedEvent<ApiType, []>;
- /**
- * One of the members' keys changed.
- **/
- KeyChanged: AugmentedEvent<ApiType, []>;
- /**
- * The given member was added; see the transaction for who.
- **/
- MemberAdded: AugmentedEvent<ApiType, []>;
- /**
- * The given member was removed; see the transaction for who.
- **/
- MemberRemoved: AugmentedEvent<ApiType, []>;
- /**
- * The membership was reset; see the transaction for who the new set is.
- **/
- MembersReset: AugmentedEvent<ApiType, []>;
- /**
- * Two members were swapped; see the transaction for who.
- **/
- MembersSwapped: AugmentedEvent<ApiType, []>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- testUtils: {
- BatchCompleted: AugmentedEvent<ApiType, []>;
- ShouldRollback: AugmentedEvent<ApiType, []>;
- ValueIsSet: AugmentedEvent<ApiType, []>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- tokens: {
- /**
- * A balance was set by root.
- **/
- BalanceSet: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, free: u128, reserved: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, free: u128, reserved: u128 }>;
- /**
- * Deposited some balance into an account
- **/
- Deposited: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * An account was removed whose balance was non-zero but below
- * ExistentialDeposit, resulting in an outright loss.
- **/
- DustLost: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * An account was created with some free balance.
- **/
- Endowed: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- Issued: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, amount: u128], { currencyId: PalletForeignAssetsAssetId, amount: u128 }>;
- /**
- * Some free balance was locked.
- **/
- Locked: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * Some locked funds were unlocked
- **/
- LockRemoved: AugmentedEvent<ApiType, [lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32], { lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32 }>;
- /**
- * Some funds are locked
- **/
- LockSet: AugmentedEvent<ApiType, [lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { lockId: U8aFixed, currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- Rescinded: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, amount: u128], { currencyId: PalletForeignAssetsAssetId, amount: u128 }>;
- /**
- * Some balance was reserved (moved from free to reserved).
- **/
- Reserved: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * Some reserved balance was repatriated (moved from reserved to
- * another account).
- **/
- ReserveRepatriated: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128, status: FrameSupportTokensMiscBalanceStatus], { currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128, status: FrameSupportTokensMiscBalanceStatus }>;
- /**
- * Some balances were slashed (e.g. due to mis-behavior)
- **/
- Slashed: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, freeAmount: u128, reservedAmount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, freeAmount: u128, reservedAmount: u128 }>;
- /**
- * The total issuance of an currency has been set
- **/
- TotalIssuanceSet: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, amount: u128], { currencyId: PalletForeignAssetsAssetId, amount: u128 }>;
- /**
- * Transfer succeeded.
- **/
- Transfer: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, from: AccountId32, to: AccountId32, amount: u128 }>;
- /**
- * Some locked balance was freed.
- **/
- Unlocked: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * Some balance was unreserved (moved from reserved to free).
- **/
- Unreserved: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * Some balances were withdrawn (e.g. pay for transaction fee)
- **/
- Withdrawn: AugmentedEvent<ApiType, [currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128], { currencyId: PalletForeignAssetsAssetId, who: AccountId32, amount: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- transactionPayment: {
- /**
- * A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,
- * has been paid by `who`.
- **/
- TransactionFeePaid: AugmentedEvent<ApiType, [who: AccountId32, actualFee: u128, tip: u128], { who: AccountId32, actualFee: u128, tip: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- treasury: {
- /**
- * Some funds have been allocated.
- **/
- Awarded: AugmentedEvent<ApiType, [proposalIndex: u32, award: u128, account: AccountId32], { proposalIndex: u32, award: u128, account: AccountId32 }>;
- /**
- * Some of our funds have been burnt.
- **/
- Burnt: AugmentedEvent<ApiType, [burntFunds: u128], { burntFunds: u128 }>;
- /**
- * Some funds have been deposited.
- **/
- Deposit: AugmentedEvent<ApiType, [value: u128], { value: u128 }>;
- /**
- * New proposal.
- **/
- Proposed: AugmentedEvent<ApiType, [proposalIndex: u32], { proposalIndex: u32 }>;
- /**
- * A proposal was rejected; funds were slashed.
- **/
- Rejected: AugmentedEvent<ApiType, [proposalIndex: u32, slashed: u128], { proposalIndex: u32, slashed: u128 }>;
- /**
- * Spending has finished; this is the amount that rolls over until next spend.
- **/
- Rollover: AugmentedEvent<ApiType, [rolloverBalance: u128], { rolloverBalance: u128 }>;
- /**
- * A new spend proposal has been approved.
- **/
- SpendApproved: AugmentedEvent<ApiType, [proposalIndex: u32, amount: u128, beneficiary: AccountId32], { proposalIndex: u32, amount: u128, beneficiary: AccountId32 }>;
- /**
- * We have ended a spend period and will now allocate funds.
- **/
- Spending: AugmentedEvent<ApiType, [budgetRemaining: u128], { budgetRemaining: u128 }>;
- /**
- * The inactive funds of the pallet have been updated.
- **/
- UpdatedInactive: AugmentedEvent<ApiType, [reactivated: u128, deactivated: u128], { reactivated: u128, deactivated: u128 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- utility: {
- /**
- * Batch of dispatches completed fully with no error.
- **/
- BatchCompleted: AugmentedEvent<ApiType, []>;
- /**
- * Batch of dispatches completed but has errors.
- **/
- BatchCompletedWithErrors: AugmentedEvent<ApiType, []>;
- /**
- * Batch of dispatches did not complete fully. Index of first failing dispatch given, as
- * well as the error.
- **/
- BatchInterrupted: AugmentedEvent<ApiType, [index: u32, error: SpRuntimeDispatchError], { index: u32, error: SpRuntimeDispatchError }>;
- /**
- * A call was dispatched.
- **/
- DispatchedAs: AugmentedEvent<ApiType, [result: Result<Null, SpRuntimeDispatchError>], { result: Result<Null, SpRuntimeDispatchError> }>;
- /**
- * A single item within a Batch of dispatches has completed with no error.
- **/
- ItemCompleted: AugmentedEvent<ApiType, []>;
- /**
- * A single item within a Batch of dispatches has completed with error.
- **/
- ItemFailed: AugmentedEvent<ApiType, [error: SpRuntimeDispatchError], { error: SpRuntimeDispatchError }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- vesting: {
- /**
- * Claimed vesting.
- **/
- Claimed: AugmentedEvent<ApiType, [who: AccountId32, amount: u128], { who: AccountId32, amount: u128 }>;
- /**
- * Added new vesting schedule.
- **/
- VestingScheduleAdded: AugmentedEvent<ApiType, [from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule], { from: AccountId32, to: AccountId32, vestingSchedule: OrmlVestingVestingSchedule }>;
- /**
- * Updated vesting schedules.
- **/
- VestingSchedulesUpdated: AugmentedEvent<ApiType, [who: AccountId32], { who: AccountId32 }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- xcmpQueue: {
- /**
- * Bad XCM format used.
- **/
- BadFormat: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
- /**
- * Bad XCM version used.
- **/
- BadVersion: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
- /**
- * Some XCM failed.
- **/
- Fail: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, error: StagingXcmV3TraitsError, weight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, error: StagingXcmV3TraitsError, weight: SpWeightsWeightV2Weight }>;
- /**
- * An XCM exceeded the individual message weight budget.
- **/
- OverweightEnqueued: AugmentedEvent<ApiType, [sender: u32, sentAt: u32, index: u64, required: SpWeightsWeightV2Weight], { sender: u32, sentAt: u32, index: u64, required: SpWeightsWeightV2Weight }>;
- /**
- * An XCM from the overweight queue was executed with the given actual weight used.
- **/
- OverweightServiced: AugmentedEvent<ApiType, [index: u64, used: SpWeightsWeightV2Weight], { index: u64, used: SpWeightsWeightV2Weight }>;
- /**
- * Some XCM was executed ok.
- **/
- Success: AugmentedEvent<ApiType, [messageHash: U8aFixed, messageId: U8aFixed, weight: SpWeightsWeightV2Weight], { messageHash: U8aFixed, messageId: U8aFixed, weight: SpWeightsWeightV2Weight }>;
- /**
- * An HRMP message was sent to a sibling parachain.
- **/
- XcmpMessageSent: AugmentedEvent<ApiType, [messageHash: U8aFixed], { messageHash: U8aFixed }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- xTokens: {
- /**
- * Transferred `MultiAsset` with fee.
- **/
- TransferredMultiAssets: AugmentedEvent<ApiType, [sender: AccountId32, assets: StagingXcmV3MultiassetMultiAssets, fee: StagingXcmV3MultiAsset, dest: StagingXcmV3MultiLocation], { sender: AccountId32, assets: StagingXcmV3MultiassetMultiAssets, fee: StagingXcmV3MultiAsset, dest: StagingXcmV3MultiLocation }>;
- /**
- * Generic event
- **/
- [key: string]: AugmentedEvent<ApiType>;
- };
- } // AugmentedEvents
-} // declare module
js-packages/types/src/augment-api-query.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-query.ts
+++ /dev/null
@@ -1,1442 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/api-base/types/storage';
-
-import type { ApiTypes, AugmentedQuery, QueryableStorageEntry } from '@polkadot/api-base/types';
-import type { Data } from '@polkadot/types';
-import type { BTreeMap, Bytes, Option, Struct, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
-import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
-import type { AccountId32, Call, H160, H256 } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCodeUpgradeAuthorization, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletParachainSystemUnincludedSegmentAncestor, CumulusPalletParachainSystemUnincludedSegmentSegmentTracker, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportDispatchPerDispatchClassWeight, FrameSupportPreimagesBounded, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OpalRuntimeRuntimeCommonSessionKeys, OpalRuntimeRuntimeHoldReason, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensReserveData, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesIdAmount, PalletBalancesReserveData, PalletCollectiveVotes, PalletConfigurationAppPromotionConfiguration, PalletDemocracyMetadataOwner, PalletDemocracyReferendumInfo, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCodeMetadata, PalletEvmContractHelpersSponsoringModeT, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletNonfungibleItemData, PalletPreimageRequestStatus, PalletRankedCollectiveMemberRecord, PalletRankedCollectiveVoteRecord, PalletReferendaReferendumInfo, PalletSchedulerScheduled, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletTransactionPaymentReleases, PalletTreasuryProposal, PalletXcmQueryStatus, PalletXcmRemoteLockedFungibleRecord, PalletXcmVersionMigrationStage, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV5AbridgedHostConfiguration, PolkadotPrimitivesV5PersistedValidationData, PolkadotPrimitivesV5UpgradeGoAhead, PolkadotPrimitivesV5UpgradeRestriction, SpConsensusAuraSr25519AppSr25519Public, SpCoreCryptoKeyTypeId, SpRuntimeDigest, SpTrieStorageProof, SpWeightsWeightV2Weight, StagingXcmV3MultiLocation, StagingXcmVersionedAssetId, StagingXcmVersionedMultiLocation, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild } from '@polkadot/types/lookup';
-import type { Observable } from '@polkadot/types/types';
-
-export type __AugmentedQuery<ApiType extends ApiTypes> = AugmentedQuery<ApiType, () => unknown>;
-export type __QueryableStorageEntry<ApiType extends ApiTypes> = QueryableStorageEntry<ApiType>;
-
-declare module '@polkadot/api-base/types/storage' {
- interface AugmentedQueries<ApiType extends ApiTypes> {
- appPromotion: {
- /**
- * Stores the `admin` account. Some extrinsics can only be executed if they were signed by `admin`.
- **/
- admin: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Pending unstake records for an `Account`.
- *
- * * **Key** - Staker account.
- * * **Value** - Amount of stakes.
- **/
- pendingUnstake: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[AccountId32, u128]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Stores a key for record for which the revenue recalculation was performed.
- * If `None`, then recalculation has not yet been performed or calculations have been completed for all stakers.
- **/
- previousCalculatedRecord: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[AccountId32, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Stores the amount of tokens staked by account in the blocknumber.
- *
- * * **Key1** - Staker account.
- * * **Key2** - Relay block number when the stake was made.
- * * **(Balance, BlockNumber)** - Balance of the stake.
- * The number of the relay block in which we must perform the interest recalculation
- **/
- staked: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<ITuple<[u128, u32]>>, [AccountId32, u32]> & QueryableStorageEntry<ApiType, [AccountId32, u32]>;
- /**
- * Stores number of stake records for an `Account`.
- *
- * * **Key** - Staker account.
- * * **Value** - Amount of stakes.
- **/
- stakesPerAccount: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u8>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Stores the total staked amount.
- **/
- totalStaked: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- aura: {
- /**
- * The current authority set.
- **/
- authorities: AugmentedQuery<ApiType, () => Observable<Vec<SpConsensusAuraSr25519AppSr25519Public>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current slot of this block.
- *
- * This will be set in `on_initialize`.
- **/
- currentSlot: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- auraExt: {
- /**
- * Serves as cache for the authorities.
- *
- * The authorities in AuRa are overwritten in `on_initialize` when we switch to a new session,
- * but we require the old authorities to verify the seal when validating a PoV. This will
- * always be updated to the latest AuRa authorities in `on_finalize`.
- **/
- authorities: AugmentedQuery<ApiType, () => Observable<Vec<SpConsensusAuraSr25519AppSr25519Public>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Current slot paired with a number of authored blocks.
- *
- * Updated on each block initialization.
- **/
- slotInfo: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[u64, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- authorship: {
- /**
- * Author of current block.
- **/
- author: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- balances: {
- /**
- * The Balances pallet example of storing the balance of an account.
- *
- * # Example
- *
- * ```nocompile
- * impl pallet_balances::Config for Runtime {
- * type AccountStore = StorageMapShim<Self::Account<Runtime>, frame_system::Provider<Runtime>, AccountId, Self::AccountData<Balance>>
- * }
- * ```
- *
- * You can also store the balance of an account in the `System` pallet.
- *
- * # Example
- *
- * ```nocompile
- * impl pallet_balances::Config for Runtime {
- * type AccountStore = System
- * }
- * ```
- *
- * But this comes with tradeoffs, storing account balances in the system pallet stores
- * `frame_system` data alongside the account data contrary to storing account balances in the
- * `Balances` pallet, which uses a `StorageMap` to store balances data only.
- * NOTE: This is only used in the case that this pallet is used to store balances.
- **/
- account: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<PalletBalancesAccountData>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Freeze locks on account balances.
- **/
- freezes: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<PalletBalancesIdAmount>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Holds on account balances.
- **/
- holds: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<{
- readonly id: OpalRuntimeRuntimeHoldReason;
- readonly amount: u128;
- } & Struct>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * The total units of outstanding deactivated balance in the system.
- **/
- inactiveIssuance: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Any liquidity locks on some account balances.
- * NOTE: Should only be accessed when setting, changing and freeing a lock.
- **/
- locks: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<PalletBalancesBalanceLock>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Named reserves on some account balances.
- **/
- reserves: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<PalletBalancesReserveData>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * The total units issued in the system.
- **/
- totalIssuance: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- collatorSelection: {
- /**
- * The (community, limited) collation candidates.
- **/
- candidates: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The invulnerable, fixed collators.
- **/
- invulnerables: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Last block authored by collator.
- **/
- lastAuthoredBlock: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u32>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * The (community) collation license holders.
- **/
- licenseDepositOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u128>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- common: {
- /**
- * Storage of the amount of collection admins.
- **/
- adminAmount: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Allowlisted collection users.
- **/
- allowlist: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Storage of collection info.
- **/
- collectionById: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsCollection>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Storage of collection properties.
- **/
- collectionProperties: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Storage of token property permissions of a collection.
- **/
- collectionPropertyPermissions: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsPropertiesMapPropertyPermission>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Storage of the count of created collections. Essentially contains the last collection ID.
- **/
- createdCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Storage of the count of deleted collections.
- **/
- destroyedCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Not used by code, exists only to provide some types to metadata.
- **/
- dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, UpDataStructsTokenChild, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * List of collection admins.
- **/
- isAdmin: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- configuration: {
- appPromomotionConfigurationOverride: AugmentedQuery<ApiType, () => Observable<PalletConfigurationAppPromotionConfiguration>, []> & QueryableStorageEntry<ApiType, []>;
- collatorSelectionDesiredCollatorsOverride: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- collatorSelectionKickThresholdOverride: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- collatorSelectionLicenseBondOverride: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- minGasPriceOverride: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- weightToFeeCoefficientOverride: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- council: {
- /**
- * The current members of the collective. This is stored sorted (just by value).
- **/
- members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The prime member that helps determine the default vote behavior in case of absentations.
- **/
- prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Proposals so far.
- **/
- proposalCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Actual proposal for a given hash, if it's current.
- **/
- proposalOf: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<Call>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * The hashes of the active proposals.
- **/
- proposals: AugmentedQuery<ApiType, () => Observable<Vec<H256>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Votes on a given proposal, if it is ongoing.
- **/
- voting: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<PalletCollectiveVotes>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- councilMembership: {
- /**
- * The current membership, stored as an ordered Vec.
- **/
- members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current prime member, if one exists.
- **/
- prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- democracy: {
- /**
- * A record of who vetoed what. Maps proposal hash to a possible existent block number
- * (until when it may not be resubmitted) and who vetoed it.
- **/
- blacklist: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<ITuple<[u32, Vec<AccountId32>]>>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * Record of all proposals that have been subject to emergency cancellation.
- **/
- cancellations: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<bool>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * Those who have locked a deposit.
- *
- * TWOX-NOTE: Safe, as increasing integer keys are safe.
- **/
- depositOf: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<ITuple<[Vec<AccountId32>, u128]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * True if the last referendum tabled was submitted externally. False if it was a public
- * proposal.
- **/
- lastTabledWasExternal: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The lowest referendum index representing an unbaked referendum. Equal to
- * `ReferendumCount` if there isn't a unbaked referendum.
- **/
- lowestUnbaked: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * General information concerning any proposal or referendum.
- * The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON
- * dump or IPFS hash of a JSON file.
- *
- * Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove)
- * large preimages.
- **/
- metadataOf: AugmentedQuery<ApiType, (arg: PalletDemocracyMetadataOwner | { External: any } | { Proposal: any } | { Referendum: any } | string | Uint8Array) => Observable<Option<H256>>, [PalletDemocracyMetadataOwner]> & QueryableStorageEntry<ApiType, [PalletDemocracyMetadataOwner]>;
- /**
- * The referendum to be tabled whenever it would be valid to table an external proposal.
- * This happens when a referendum needs to be tabled and one of two conditions are met:
- * - `LastTabledWasExternal` is `false`; or
- * - `PublicProps` is empty.
- **/
- nextExternal: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[FrameSupportPreimagesBounded, PalletDemocracyVoteThreshold]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The number of (public) proposals that have been made so far.
- **/
- publicPropCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The public proposals. Unsorted. The second item is the proposal.
- **/
- publicProps: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[u32, FrameSupportPreimagesBounded, AccountId32]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The next free referendum index, aka the number of referenda started so far.
- **/
- referendumCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Information concerning any given referendum.
- *
- * TWOX-NOTE: SAFE as indexes are not under an attacker’s control.
- **/
- referendumInfoOf: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletDemocracyReferendumInfo>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * All votes for a particular voter. We store the balance for the number of votes that we
- * have recorded. The second item is the total amount of delegations, that will be added.
- *
- * TWOX-NOTE: SAFE as `AccountId`s are crypto hashes anyway.
- **/
- votingOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<PalletDemocracyVoteVoting>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- dmpQueue: {
- /**
- * The configuration.
- **/
- configuration: AugmentedQuery<ApiType, () => Observable<CumulusPalletDmpQueueConfigData>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Counter for the related counted storage map
- **/
- counterForOverweight: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The overweight messages.
- **/
- overweight: AugmentedQuery<ApiType, (arg: u64 | AnyNumber | Uint8Array) => Observable<Option<ITuple<[u32, Bytes]>>>, [u64]> & QueryableStorageEntry<ApiType, [u64]>;
- /**
- * The page index.
- **/
- pageIndex: AugmentedQuery<ApiType, () => Observable<CumulusPalletDmpQueuePageIndexData>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The queue pages.
- **/
- pages: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[u32, Bytes]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- ethereum: {
- blockHash: AugmentedQuery<ApiType, (arg: U256 | AnyNumber | Uint8Array) => Observable<H256>, [U256]> & QueryableStorageEntry<ApiType, [U256]>;
- /**
- * The current Ethereum block.
- **/
- currentBlock: AugmentedQuery<ApiType, () => Observable<Option<EthereumBlock>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current Ethereum receipts.
- **/
- currentReceipts: AugmentedQuery<ApiType, () => Observable<Option<Vec<EthereumReceiptReceiptV3>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current transaction statuses.
- **/
- currentTransactionStatuses: AugmentedQuery<ApiType, () => Observable<Option<Vec<FpRpcTransactionStatus>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Injected transactions should have unique nonce, here we store current
- **/
- injectedNonce: AugmentedQuery<ApiType, () => Observable<U256>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Current building block's transactions and receipts.
- **/
- pending: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[EthereumTransactionTransactionV2, FpRpcTransactionStatus, EthereumReceiptReceiptV3]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- evm: {
- accountCodes: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Bytes>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- accountCodesMetadata: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Option<PalletEvmCodeMetadata>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- accountStorages: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H256 | string | Uint8Array) => Observable<H256>, [H160, H256]> & QueryableStorageEntry<ApiType, [H160, H256]>;
- /**
- * Written on log, reset after transaction
- * Should be empty between transactions
- **/
- currentLogs: AugmentedQuery<ApiType, () => Observable<Vec<EthereumLog>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- evmContractHelpers: {
- /**
- * Storage for users that allowed for sponsorship.
- *
- * ### Usage
- * Prefer to delete record from storage if user no more allowed for sponsorship.
- *
- * * **Key1** - contract address.
- * * **Key2** - user that allowed for sponsorship.
- * * **Value** - allowance for sponsorship.
- **/
- allowlist: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H160 | string | Uint8Array) => Observable<bool>, [H160, H160]> & QueryableStorageEntry<ApiType, [H160, H160]>;
- /**
- * Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.
- *
- * ### Usage
- * Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.
- *
- * * **Key** - contract address.
- * * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.
- **/
- allowlistEnabled: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Store owner for contract.
- *
- * * **Key** - contract address.
- * * **Value** - owner for contract.
- **/
- owner: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<H160>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Deprecated: this storage is deprecated
- **/
- selfSponsoring: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- sponsorBasket: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H160 | string | Uint8Array) => Observable<Option<u32>>, [H160, H160]> & QueryableStorageEntry<ApiType, [H160, H160]>;
- /**
- * Store for contract sponsorship state.
- *
- * * **Key** - contract address.
- * * **Value** - sponsorship state.
- **/
- sponsoring: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<UpDataStructsSponsorshipStateBasicCrossAccountIdRepr>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Storage for last sponsored block.
- *
- * * **Key1** - contract address.
- * * **Key2** - sponsored user address.
- * * **Value** - last sponsored block number.
- **/
- sponsoringFeeLimit: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<BTreeMap<u32, U256>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Store for sponsoring mode.
- *
- * ### Usage
- * Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).
- *
- * * **Key** - contract address.
- * * **Value** - [`sponsoring mode`](SponsoringModeT).
- **/
- sponsoringMode: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Option<PalletEvmContractHelpersSponsoringModeT>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Storage for sponsoring rate limit in blocks.
- *
- * * **Key** - contract address.
- * * **Value** - amount of sponsored blocks.
- **/
- sponsoringRateLimit: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<u32>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- evmMigration: {
- migrationPending: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- fellowshipCollective: {
- /**
- * The index of each ranks's member into the group of members who have at least that rank.
- **/
- idToIndex: AugmentedQuery<ApiType, (arg1: u16 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u16, AccountId32]> & QueryableStorageEntry<ApiType, [u16, AccountId32]>;
- /**
- * The members in the collective by index. All indices in the range `0..MemberCount` will
- * return `Some`, however a member's index is not guaranteed to remain unchanged over time.
- **/
- indexToId: AugmentedQuery<ApiType, (arg1: u16 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<AccountId32>>, [u16, u32]> & QueryableStorageEntry<ApiType, [u16, u32]>;
- /**
- * The number of members in the collective who have at least the rank according to the index
- * of the vec.
- **/
- memberCount: AugmentedQuery<ApiType, (arg: u16 | AnyNumber | Uint8Array) => Observable<u32>, [u16]> & QueryableStorageEntry<ApiType, [u16]>;
- /**
- * The current members of the collective.
- **/
- members: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<PalletRankedCollectiveMemberRecord>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Votes on a given proposal, if it is ongoing.
- **/
- voting: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<PalletRankedCollectiveVoteRecord>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
- votingCleanup: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<Bytes>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- fellowshipReferenda: {
- /**
- * The number of referenda being decided currently.
- **/
- decidingCount: AugmentedQuery<ApiType, (arg: u16 | AnyNumber | Uint8Array) => Observable<u32>, [u16]> & QueryableStorageEntry<ApiType, [u16]>;
- /**
- * The metadata is a general information concerning the referendum.
- * The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON
- * dump or IPFS hash of a JSON file.
- *
- * Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove)
- * large preimages.
- **/
- metadataOf: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<H256>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * The next free referendum index, aka the number of referenda started so far.
- **/
- referendumCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Information concerning any given referendum.
- **/
- referendumInfoFor: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletReferendaReferendumInfo>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * The sorted list of referenda ready to be decided but not yet being decided, ordered by
- * conviction-weighted approvals.
- *
- * This should be empty if `DecidingCount` is less than `TrackInfo::max_deciding`.
- **/
- trackQueue: AugmentedQuery<ApiType, (arg: u16 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[u32, u32]>>>, [u16]> & QueryableStorageEntry<ApiType, [u16]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- foreignAssets: {
- /**
- * The storages for assets to fungible collection binding
- *
- **/
- assetBinding: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * The storages for AssetMetadatas.
- *
- * AssetMetadatas: map AssetIds => Option<AssetMetadata>
- **/
- assetMetadatas: AugmentedQuery<ApiType, (arg: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<Option<PalletForeignAssetsModuleAssetMetadata>>, [PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [PalletForeignAssetsAssetId]>;
- /**
- * The storages for MultiLocations.
- *
- * ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>
- **/
- foreignAssetLocations: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<StagingXcmV3MultiLocation>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * The storages for CurrencyIds.
- *
- * LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>
- **/
- locationToCurrencyIds: AugmentedQuery<ApiType, (arg: StagingXcmV3MultiLocation | { parents?: any; interior?: any } | string | Uint8Array) => Observable<Option<u32>>, [StagingXcmV3MultiLocation]> & QueryableStorageEntry<ApiType, [StagingXcmV3MultiLocation]>;
- /**
- * Next available Foreign AssetId ID.
- *
- * NextForeignAssetId: ForeignAssetId
- **/
- nextForeignAssetId: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- fungible: {
- /**
- * Storage for assets delegated to a limited extent to other users.
- **/
- allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Amount of tokens owned by an account inside a collection.
- **/
- balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Total amount of fungible tokens inside a collection.
- **/
- totalSupply: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- identity: {
- /**
- * Information that is pertinent to identify the entity behind an account.
- *
- * TWOX-NOTE: OK ― `AccountId` is a secure hash.
- **/
- identityOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<PalletIdentityRegistration>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * The set of registrars. Not expected to get very big as can only be added through a
- * special origin (likely a council motion).
- *
- * The index into this can be cast to `RegistrarIndex` to get a valid value.
- **/
- registrars: AugmentedQuery<ApiType, () => Observable<Vec<Option<PalletIdentityRegistrarInfo>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Alternative "sub" identities of this account.
- *
- * The first item is the deposit, the second is a vector of the accounts.
- *
- * TWOX-NOTE: OK ― `AccountId` is a secure hash.
- **/
- subsOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<ITuple<[u128, Vec<AccountId32>]>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * The super-identity of an alternative "sub" identity together with its name, within that
- * context. If the account is not some other account's sub-identity, then just `None`.
- **/
- superOf: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<ITuple<[AccountId32, Data]>>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- inflation: {
- /**
- * Current inflation for `InflationBlockInterval` number of blocks
- **/
- blockInflation: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Next target (relay) block when inflation will be applied
- **/
- nextInflationBlock: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Next target (relay) block when inflation is recalculated
- **/
- nextRecalculationBlock: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Relay block when inflation has started
- **/
- startBlock: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * starting year total issuance
- **/
- startingYearTotalIssuance: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- maintenance: {
- enabled: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- nonfungible: {
- /**
- * Amount of tokens owned by an account in a collection.
- **/
- accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Allowance set by a token owner for another user to perform one of certain transactions on a token.
- **/
- allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
- **/
- collectionAllowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Used to enumerate tokens owned by account.
- **/
- owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
- /**
- * Custom data of a token that is serialized to bytes,
- * primarily reserved for on-chain operations,
- * normally obscured from the external users.
- *
- * Auxiliary properties are slightly different from
- * usual [`TokenProperties`] due to an unlimited number
- * and separately stored and written-to key-value pairs.
- *
- * Currently unused.
- **/
- tokenAuxProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: UpDataStructsPropertyScope | 'None' | 'Rmrk' | number | Uint8Array, arg4: Bytes | string | Uint8Array) => Observable<Option<Bytes>>, [u32, u32, UpDataStructsPropertyScope, Bytes]> & QueryableStorageEntry<ApiType, [u32, u32, UpDataStructsPropertyScope, Bytes]>;
- /**
- * Used to enumerate token's children.
- **/
- tokenChildren: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array]) => Observable<bool>, [u32, u32, ITuple<[u32, u32]>]> & QueryableStorageEntry<ApiType, [u32, u32, ITuple<[u32, u32]>]>;
- /**
- * Token data, used to partially describe a token.
- **/
- tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletNonfungibleItemData>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Map of key-value pairs, describing the metadata of a token.
- **/
- tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsProperties>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Amount of burnt tokens in a collection.
- **/
- tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Total amount of minted tokens in a collection.
- **/
- tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- parachainInfo: {
- parachainId: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- parachainSystem: {
- /**
- * Storage field that keeps track of bandwidth used by the unincluded segment along with the
- * latest the latest HRMP watermark. Used for limiting the acceptance of new blocks with
- * respect to relay chain constraints.
- **/
- aggregatedUnincludedSegment: AugmentedQuery<ApiType, () => Observable<Option<CumulusPalletParachainSystemUnincludedSegmentSegmentTracker>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The number of HRMP messages we observed in `on_initialize` and thus used that number for
- * announcing the weight of `on_initialize` and `on_finalize`.
- **/
- announcedHrmpMessagesPerCandidate: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The next authorized upgrade, if there is one.
- **/
- authorizedUpgrade: AugmentedQuery<ApiType, () => Observable<Option<CumulusPalletParachainSystemCodeUpgradeAuthorization>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * A custom head data that should be returned as result of `validate_block`.
- *
- * See `Pallet::set_custom_validation_head_data` for more information.
- **/
- customValidationHeadData: AugmentedQuery<ApiType, () => Observable<Option<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Were the validation data set to notify the relay chain?
- **/
- didSetValidationCode: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The parachain host configuration that was obtained from the relay parent.
- *
- * This field is meant to be updated each block with the validation data inherent. Therefore,
- * before processing of the inherent, e.g. in `on_initialize` this data may be stale.
- *
- * This data is also absent from the genesis.
- **/
- hostConfiguration: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5AbridgedHostConfiguration>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * HRMP messages that were sent in a block.
- *
- * This will be cleared in `on_initialize` of each new block.
- **/
- hrmpOutboundMessages: AugmentedQuery<ApiType, () => Observable<Vec<PolkadotCorePrimitivesOutboundHrmpMessage>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * HRMP watermark that was set in a block.
- *
- * This will be cleared in `on_initialize` of each new block.
- **/
- hrmpWatermark: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The last downward message queue chain head we have observed.
- *
- * This value is loaded before and saved after processing inbound downward messages carried
- * by the system inherent.
- **/
- lastDmqMqcHead: AugmentedQuery<ApiType, () => Observable<H256>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The message queue chain heads we have observed per each channel incoming channel.
- *
- * This value is loaded before and saved after processing inbound downward messages carried
- * by the system inherent.
- **/
- lastHrmpMqcHeads: AugmentedQuery<ApiType, () => Observable<BTreeMap<u32, H256>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The relay chain block number associated with the last parachain block.
- **/
- lastRelayChainBlockNumber: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Validation code that is set by the parachain and is to be communicated to collator and
- * consequently the relay-chain.
- *
- * This will be cleared in `on_initialize` of each new block if no other pallet already set
- * the value.
- **/
- newValidationCode: AugmentedQuery<ApiType, () => Observable<Option<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Upward messages that are still pending and not yet send to the relay chain.
- **/
- pendingUpwardMessages: AugmentedQuery<ApiType, () => Observable<Vec<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * In case of a scheduled upgrade, this storage field contains the validation code to be
- * applied.
- *
- * As soon as the relay chain gives us the go-ahead signal, we will overwrite the
- * [`:code`][sp_core::storage::well_known_keys::CODE] which will result the next block process
- * with the new validation code. This concludes the upgrade process.
- **/
- pendingValidationCode: AugmentedQuery<ApiType, () => Observable<Bytes>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Number of downward messages processed in a block.
- *
- * This will be cleared in `on_initialize` of each new block.
- **/
- processedDownwardMessages: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The state proof for the last relay parent block.
- *
- * This field is meant to be updated each block with the validation data inherent. Therefore,
- * before processing of the inherent, e.g. in `on_initialize` this data may be stale.
- *
- * This data is also absent from the genesis.
- **/
- relayStateProof: AugmentedQuery<ApiType, () => Observable<Option<SpTrieStorageProof>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The snapshot of some state related to messaging relevant to the current parachain as per
- * the relay parent.
- *
- * This field is meant to be updated each block with the validation data inherent. Therefore,
- * before processing of the inherent, e.g. in `on_initialize` this data may be stale.
- *
- * This data is also absent from the genesis.
- **/
- relevantMessagingState: AugmentedQuery<ApiType, () => Observable<Option<CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The weight we reserve at the beginning of the block for processing DMP messages. This
- * overrides the amount set in the Config trait.
- **/
- reservedDmpWeightOverride: AugmentedQuery<ApiType, () => Observable<Option<SpWeightsWeightV2Weight>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The weight we reserve at the beginning of the block for processing XCMP messages. This
- * overrides the amount set in the Config trait.
- **/
- reservedXcmpWeightOverride: AugmentedQuery<ApiType, () => Observable<Option<SpWeightsWeightV2Weight>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Latest included block descendants the runtime accepted. In other words, these are
- * ancestors of the currently executing block which have not been included in the observed
- * relay-chain state.
- *
- * The segment length is limited by the capacity returned from the [`ConsensusHook`] configured
- * in the pallet.
- **/
- unincludedSegment: AugmentedQuery<ApiType, () => Observable<Vec<CumulusPalletParachainSystemUnincludedSegmentAncestor>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Optional upgrade go-ahead signal from the relay-chain.
- *
- * This storage item is a mirror of the corresponding value for the current parachain from the
- * relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is
- * set after the inherent.
- **/
- upgradeGoAhead: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5UpgradeGoAhead>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * An option which indicates if the relay-chain restricts signalling a validation code upgrade.
- * In other words, if this is `Some` and [`NewValidationCode`] is `Some` then the produced
- * candidate will be invalid.
- *
- * This storage item is a mirror of the corresponding value for the current parachain from the
- * relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is
- * set after the inherent.
- **/
- upgradeRestrictionSignal: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5UpgradeRestriction>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Upward messages that were sent in a block.
- *
- * This will be cleared in `on_initialize` of each new block.
- **/
- upwardMessages: AugmentedQuery<ApiType, () => Observable<Vec<Bytes>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The [`PersistedValidationData`] set for this block.
- * This value is expected to be set only once per block and it's never stored
- * in the trie.
- **/
- validationData: AugmentedQuery<ApiType, () => Observable<Option<PolkadotPrimitivesV5PersistedValidationData>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- polkadotXcm: {
- /**
- * The existing asset traps.
- *
- * Key is the blake2 256 hash of (origin, versioned `MultiAssets`) pair. Value is the number of
- * times this pair has been trapped (usually just 1 if it exists at all).
- **/
- assetTraps: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<u32>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * The current migration's stage, if any.
- **/
- currentMigration: AugmentedQuery<ApiType, () => Observable<Option<PalletXcmVersionMigrationStage>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Fungible assets which we know are locked on this chain.
- **/
- lockedFungibles: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<Vec<ITuple<[u128, StagingXcmVersionedMultiLocation]>>>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * The ongoing queries.
- **/
- queries: AugmentedQuery<ApiType, (arg: u64 | AnyNumber | Uint8Array) => Observable<Option<PalletXcmQueryStatus>>, [u64]> & QueryableStorageEntry<ApiType, [u64]>;
- /**
- * The latest available query index.
- **/
- queryCounter: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Fungible assets which we know are locked on a remote chain.
- **/
- remoteLockedFungibles: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array, arg3: StagingXcmVersionedAssetId | { V3: any } | string | Uint8Array) => Observable<Option<PalletXcmRemoteLockedFungibleRecord>>, [u32, AccountId32, StagingXcmVersionedAssetId]> & QueryableStorageEntry<ApiType, [u32, AccountId32, StagingXcmVersionedAssetId]>;
- /**
- * Default version to encode XCM when latest version of destination is unknown. If `None`,
- * then the destinations whose XCM version is unknown are considered unreachable.
- **/
- safeXcmVersion: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The Latest versions that we know various locations support.
- **/
- supportedVersion: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => Observable<Option<u32>>, [u32, StagingXcmVersionedMultiLocation]> & QueryableStorageEntry<ApiType, [u32, StagingXcmVersionedMultiLocation]>;
- /**
- * Destinations whose latest XCM version we would like to know. Duplicates not allowed, and
- * the `u32` counter is the number of times that a send to the destination has been attempted,
- * which is used as a prioritization.
- **/
- versionDiscoveryQueue: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[StagingXcmVersionedMultiLocation, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * All locations that we have requested version notifications from.
- **/
- versionNotifiers: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => Observable<Option<u64>>, [u32, StagingXcmVersionedMultiLocation]> & QueryableStorageEntry<ApiType, [u32, StagingXcmVersionedMultiLocation]>;
- /**
- * The target locations that are subscribed to our version changes, as well as the most recent
- * of our versions we informed them of.
- **/
- versionNotifyTargets: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => Observable<Option<ITuple<[u64, SpWeightsWeightV2Weight, u32]>>>, [u32, StagingXcmVersionedMultiLocation]> & QueryableStorageEntry<ApiType, [u32, StagingXcmVersionedMultiLocation]>;
- /**
- * Global suspension state of the XCM executor.
- **/
- xcmExecutionSuspended: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- preimage: {
- preimageFor: AugmentedQuery<ApiType, (arg: ITuple<[H256, u32]> | [H256 | string | Uint8Array, u32 | AnyNumber | Uint8Array]) => Observable<Option<Bytes>>, [ITuple<[H256, u32]>]> & QueryableStorageEntry<ApiType, [ITuple<[H256, u32]>]>;
- /**
- * The request status of a given hash.
- **/
- statusFor: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<PalletPreimageRequestStatus>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- refungible: {
- /**
- * Amount of tokens (not pieces) partially owned by an account within a collection.
- **/
- accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.
- **/
- allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg4: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Amount of token pieces owned by account.
- **/
- balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Spender set by a wallet owner that could perform certain transactions on all tokens in the wallet.
- **/
- collectionAllowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * Used to enumerate tokens owned by account.
- **/
- owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
- /**
- * Amount of pieces a refungible token is split into.
- **/
- tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsProperties>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Amount of tokens burnt in a collection.
- **/
- tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Total amount of minted tokens in a collection.
- **/
- tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Total amount of pieces for token
- **/
- totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- scheduler: {
- /**
- * Items to be executed, indexed by the block number that they should be executed on.
- **/
- agenda: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<Option<PalletSchedulerScheduled>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- incompleteSince: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Lookup from a name to the block number and index of the task.
- *
- * For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4
- * identities.
- **/
- lookup: AugmentedQuery<ApiType, (arg: U8aFixed | string | Uint8Array) => Observable<Option<ITuple<[u32, u32]>>>, [U8aFixed]> & QueryableStorageEntry<ApiType, [U8aFixed]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- session: {
- /**
- * Current index of the session.
- **/
- currentIndex: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Indices of disabled validators.
- *
- * The vec is always kept sorted so that we can find whether a given validator is
- * disabled using binary search. It gets cleared when `on_session_ending` returns
- * a new set of identities.
- **/
- disabledValidators: AugmentedQuery<ApiType, () => Observable<Vec<u32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The owner of a key. The key is the `KeyTypeId` + the encoded key.
- **/
- keyOwner: AugmentedQuery<ApiType, (arg: ITuple<[SpCoreCryptoKeyTypeId, Bytes]> | [SpCoreCryptoKeyTypeId | string | Uint8Array, Bytes | string | Uint8Array]) => Observable<Option<AccountId32>>, [ITuple<[SpCoreCryptoKeyTypeId, Bytes]>]> & QueryableStorageEntry<ApiType, [ITuple<[SpCoreCryptoKeyTypeId, Bytes]>]>;
- /**
- * The next session keys for a validator.
- **/
- nextKeys: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Option<OpalRuntimeRuntimeCommonSessionKeys>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * True if the underlying economic identities or weighting behind the validators
- * has changed in the queued validator set.
- **/
- queuedChanged: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The queued keys for the next session. When the next session begins, these keys
- * will be used to determine the validator's session keys.
- **/
- queuedKeys: AugmentedQuery<ApiType, () => Observable<Vec<ITuple<[AccountId32, OpalRuntimeRuntimeCommonSessionKeys]>>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current set of validators.
- **/
- validators: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- stateTrieMigration: {
- /**
- * The limits that are imposed on automatic migrations.
- *
- * If set to None, then no automatic migration happens.
- **/
- autoLimits: AugmentedQuery<ApiType, () => Observable<Option<PalletStateTrieMigrationMigrationLimits>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Migration progress.
- *
- * This stores the snapshot of the last migrated keys. It can be set into motion and move
- * forward by any of the means provided by this pallet.
- **/
- migrationProcess: AugmentedQuery<ApiType, () => Observable<PalletStateTrieMigrationMigrationTask>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The maximum limits that the signed migration could use.
- *
- * If not set, no signed submission is allowed.
- **/
- signedMigrationMaxLimits: AugmentedQuery<ApiType, () => Observable<Option<PalletStateTrieMigrationMigrationLimits>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- sudo: {
- /**
- * The `AccountId` of the sudo key.
- **/
- key: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- system: {
- /**
- * The full account information for a particular account ID.
- **/
- account: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<FrameSystemAccountInfo>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Total length (in bytes) for all extrinsics put together, for the current block.
- **/
- allExtrinsicsLen: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Map of block numbers to block hashes.
- **/
- blockHash: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<H256>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * The current weight for the block.
- **/
- blockWeight: AugmentedQuery<ApiType, () => Observable<FrameSupportDispatchPerDispatchClassWeight>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Digest of the current block, also part of the block header.
- **/
- digest: AugmentedQuery<ApiType, () => Observable<SpRuntimeDigest>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The number of events in the `Events<T>` list.
- **/
- eventCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Events deposited for the current block.
- *
- * NOTE: The item is unbound and should therefore never be read on chain.
- * It could otherwise inflate the PoV size of a block.
- *
- * Events have a large in-memory size. Box the events to not go out-of-memory
- * just in case someone still reads them from within the runtime.
- **/
- events: AugmentedQuery<ApiType, () => Observable<Vec<FrameSystemEventRecord>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Mapping between a topic (represented by T::Hash) and a vector of indexes
- * of events in the `<Events<T>>` list.
- *
- * All topic vectors have deterministic storage locations depending on the topic. This
- * allows light-clients to leverage the changes trie storage tracking mechanism and
- * in case of changes fetch the list of events of interest.
- *
- * The value has the type `(BlockNumberFor<T>, EventIndex)` because if we used only just
- * the `EventIndex` then in case if the topic has the same contents on the next block
- * no notification will be triggered thus the event might be lost.
- **/
- eventTopics: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Vec<ITuple<[u32, u32]>>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * The execution phase of the block.
- **/
- executionPhase: AugmentedQuery<ApiType, () => Observable<Option<FrameSystemPhase>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Total extrinsics count for the current block.
- **/
- extrinsicCount: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Extrinsics data for the current block (maps an extrinsic's index to its data).
- **/
- extrinsicData: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened.
- **/
- lastRuntimeUpgrade: AugmentedQuery<ApiType, () => Observable<Option<FrameSystemLastRuntimeUpgradeInfo>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current block number being processed. Set by `execute_block`.
- **/
- number: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Hash of the previous block.
- **/
- parentHash: AugmentedQuery<ApiType, () => Observable<H256>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * True if we have upgraded so that AccountInfo contains three types of `RefCount`. False
- * (default) if not.
- **/
- upgradedToTripleRefCount: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * True if we have upgraded so that `type RefCount` is `u32`. False (default) if not.
- **/
- upgradedToU32RefCount: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- technicalCommittee: {
- /**
- * The current members of the collective. This is stored sorted (just by value).
- **/
- members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The prime member that helps determine the default vote behavior in case of absentations.
- **/
- prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Proposals so far.
- **/
- proposalCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Actual proposal for a given hash, if it's current.
- **/
- proposalOf: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<Call>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * The hashes of the active proposals.
- **/
- proposals: AugmentedQuery<ApiType, () => Observable<Vec<H256>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Votes on a given proposal, if it is ongoing.
- **/
- voting: AugmentedQuery<ApiType, (arg: H256 | string | Uint8Array) => Observable<Option<PalletCollectiveVotes>>, [H256]> & QueryableStorageEntry<ApiType, [H256]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- technicalCommitteeMembership: {
- /**
- * The current membership, stored as an ordered Vec.
- **/
- members: AugmentedQuery<ApiType, () => Observable<Vec<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The current prime member, if one exists.
- **/
- prime: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- testUtils: {
- enabled: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- testValue: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- timestamp: {
- /**
- * Did the timestamp get updated in this block?
- **/
- didUpdate: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Current time for the current block.
- **/
- now: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- tokens: {
- /**
- * The balance of a token type under an account.
- *
- * NOTE: If the total is ever zero, decrease account ref account.
- *
- * NOTE: This is only used in the case that this module is used to store
- * balances.
- **/
- accounts: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<OrmlTokensAccountData>, [AccountId32, PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [AccountId32, PalletForeignAssetsAssetId]>;
- /**
- * Any liquidity locks of a token type under an account.
- * NOTE: Should only be accessed when setting, changing and freeing a lock.
- **/
- locks: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<Vec<OrmlTokensBalanceLock>>, [AccountId32, PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [AccountId32, PalletForeignAssetsAssetId]>;
- /**
- * Named reserves on some account balances.
- **/
- reserves: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<Vec<OrmlTokensReserveData>>, [AccountId32, PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [AccountId32, PalletForeignAssetsAssetId]>;
- /**
- * The total issuance of a token type.
- **/
- totalIssuance: AugmentedQuery<ApiType, (arg: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array) => Observable<u128>, [PalletForeignAssetsAssetId]> & QueryableStorageEntry<ApiType, [PalletForeignAssetsAssetId]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- transactionPayment: {
- nextFeeMultiplier: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- storageVersion: AugmentedQuery<ApiType, () => Observable<PalletTransactionPaymentReleases>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- treasury: {
- /**
- * Proposal indices that have been approved but not yet awarded.
- **/
- approvals: AugmentedQuery<ApiType, () => Observable<Vec<u32>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The amount which has been reported as inactive to Currency.
- **/
- deactivated: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Number of proposals that have been made.
- **/
- proposalCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Proposals that have been made.
- **/
- proposals: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletTreasuryProposal>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- unique: {
- /**
- * Used for migrations
- **/
- chainVersion: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * (Collection id (controlled?2), who created (real))
- * TODO: Off chain worker should remove from this map when collection gets removed
- **/
- createItemBasket: AugmentedQuery<ApiType, (arg: ITuple<[u32, AccountId32]> | [u32 | AnyNumber | Uint8Array, AccountId32 | string | Uint8Array]) => Observable<Option<u32>>, [ITuple<[u32, AccountId32]>]> & QueryableStorageEntry<ApiType, [ITuple<[u32, AccountId32]>]>;
- /**
- * Last sponsoring of fungible tokens approval in a collection
- **/
- fungibleApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
- /**
- * Collection id (controlled?2), owning user (real)
- **/
- fungibleTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
- /**
- * Last sponsoring of NFT approval in a collection
- **/
- nftApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Collection id (controlled?2), token id (controlled?2)
- **/
- nftTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Last sponsoring of RFT approval in a collection
- **/
- refungibleApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, u32, AccountId32]>;
- /**
- * Collection id (controlled?2), token id (controlled?2)
- **/
- reFungibleTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, u32, AccountId32]>;
- /**
- * Last sponsoring of token property setting // todo:doc rephrase this and the following
- **/
- tokenPropertyBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- vesting: {
- /**
- * Vesting schedules of an account.
- *
- * VestingSchedules: map AccountId => Vec<VestingSchedule>
- **/
- vestingSchedules: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<Vec<OrmlVestingVestingSchedule>>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- xcmpQueue: {
- /**
- * Counter for the related counted storage map
- **/
- counterForOverweight: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Inbound aggregate XCMP messages. It can only be one per ParaId/block.
- **/
- inboundXcmpMessages: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
- /**
- * Status of the inbound XCMP channels.
- **/
- inboundXcmpStatus: AugmentedQuery<ApiType, () => Observable<Vec<CumulusPalletXcmpQueueInboundChannelDetails>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The messages outbound in a given XCMP channel.
- **/
- outboundXcmpMessages: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u16 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32, u16]> & QueryableStorageEntry<ApiType, [u32, u16]>;
- /**
- * The non-empty XCMP channels in order of becoming non-empty, and the index of the first
- * and last outbound message. If the two indices are equal, then it indicates an empty
- * queue and there must be a non-`Ok` `OutboundStatus`. We assume queues grow no greater
- * than 65535 items. Queue indices for normal messages begin at one; zero is reserved in
- * case of the need to send a high-priority signal message this block.
- * The bool is true if there is a signal message waiting to be sent.
- **/
- outboundXcmpStatus: AugmentedQuery<ApiType, () => Observable<Vec<CumulusPalletXcmpQueueOutboundChannelDetails>>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The messages that exceeded max individual message weight budget.
- *
- * These message stay in this storage map until they are manually dispatched via
- * `service_overweight`.
- **/
- overweight: AugmentedQuery<ApiType, (arg: u64 | AnyNumber | Uint8Array) => Observable<Option<ITuple<[u32, u32, Bytes]>>>, [u64]> & QueryableStorageEntry<ApiType, [u64]>;
- /**
- * The number of overweight messages ever recorded in `Overweight`. Also doubles as the next
- * available free overweight index.
- **/
- overweightCount: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * The configuration which controls the dynamics of the outbound queue.
- **/
- queueConfig: AugmentedQuery<ApiType, () => Observable<CumulusPalletXcmpQueueQueueConfigData>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Whether or not the XCMP queue is suspended from executing incoming XCMs or not.
- **/
- queueSuspended: AugmentedQuery<ApiType, () => Observable<bool>, []> & QueryableStorageEntry<ApiType, []>;
- /**
- * Any signal messages waiting to be sent.
- **/
- signalMessages: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Bytes>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
- /**
- * Generic query
- **/
- [key: string]: QueryableStorageEntry<ApiType>;
- };
- } // AugmentedQueries
-} // declare module
js-packages/types/src/augment-api-rpc.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-rpc.ts
+++ /dev/null
@@ -1,618 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/rpc-core/types/jsonrpc';
-
-import type { PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo } from './default/index.js';
-import type { AugmentedRpc } from '@polkadot/rpc-core/types';
-import type { Metadata, StorageKey } from '@polkadot/types';
-import type { Bytes, HashMap, Json, Null, Option, Text, U256, U64, Vec, bool, f64, u32, u64 } from '@polkadot/types-codec';
-import type { AnyNumber, Codec } from '@polkadot/types-codec/types';
-import type { ExtrinsicOrHash, ExtrinsicStatus } from '@polkadot/types/interfaces/author';
-import type { EpochAuthorship } from '@polkadot/types/interfaces/babe';
-import type { BeefySignedCommitment } from '@polkadot/types/interfaces/beefy';
-import type { BlockHash } from '@polkadot/types/interfaces/chain';
-import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';
-import type { AuthorityId } from '@polkadot/types/interfaces/consensus';
-import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequestV1 } from '@polkadot/types/interfaces/contracts';
-import type { BlockStats } from '@polkadot/types/interfaces/dev';
-import type { CreatedBlock } from '@polkadot/types/interfaces/engine';
-import type { EthAccount, EthCallRequest, EthFeeHistory, EthFilter, EthFilterChanges, EthLog, EthReceipt, EthRichBlock, EthSubKind, EthSubParams, EthSyncStatus, EthTransaction, EthTransactionRequest, EthWork } from '@polkadot/types/interfaces/eth';
-import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
-import type { EncodedFinalityProofs, JustificationNotification, ReportedRoundStates } from '@polkadot/types/interfaces/grandpa';
-import type { MmrHash, MmrLeafBatchProof } from '@polkadot/types/interfaces/mmr';
-import type { StorageKind } from '@polkadot/types/interfaces/offchain';
-import type { FeeDetails, RuntimeDispatchInfoV1 } from '@polkadot/types/interfaces/payment';
-import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
-import type { AccountId, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';
-import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';
-import type { ApplyExtrinsicResult, ChainProperties, ChainType, Health, NetworkState, NodeRole, PeerInfo, SyncState } from '@polkadot/types/interfaces/system';
-import type { IExtrinsic, Observable } from '@polkadot/types/types';
-
-export type __AugmentedRpc = AugmentedRpc<() => unknown>;
-
-declare module '@polkadot/rpc-core/types/jsonrpc' {
- interface RpcInterface {
- author: {
- /**
- * Returns true if the keystore has private keys for the given public key and key type.
- **/
- hasKey: AugmentedRpc<(publicKey: Bytes | string | Uint8Array, keyType: Text | string) => Observable<bool>>;
- /**
- * Returns true if the keystore has private keys for the given session public keys.
- **/
- hasSessionKeys: AugmentedRpc<(sessionKeys: Bytes | string | Uint8Array) => Observable<bool>>;
- /**
- * Insert a key into the keystore.
- **/
- insertKey: AugmentedRpc<(keyType: Text | string, suri: Text | string, publicKey: Bytes | string | Uint8Array) => Observable<Bytes>>;
- /**
- * Returns all pending extrinsics, potentially grouped by sender
- **/
- pendingExtrinsics: AugmentedRpc<() => Observable<Vec<Extrinsic>>>;
- /**
- * Remove given extrinsic from the pool and temporarily ban it to prevent reimporting
- **/
- removeExtrinsic: AugmentedRpc<(bytesOrHash: Vec<ExtrinsicOrHash> | (ExtrinsicOrHash | { Hash: any } | { Extrinsic: any } | string | Uint8Array)[]) => Observable<Vec<Hash>>>;
- /**
- * Generate new session keys and returns the corresponding public keys
- **/
- rotateKeys: AugmentedRpc<() => Observable<Bytes>>;
- /**
- * Submit and subscribe to watch an extrinsic until unsubscribed
- **/
- submitAndWatchExtrinsic: AugmentedRpc<(extrinsic: Extrinsic | IExtrinsic | string | Uint8Array) => Observable<ExtrinsicStatus>>;
- /**
- * Submit a fully formatted extrinsic for block inclusion
- **/
- submitExtrinsic: AugmentedRpc<(extrinsic: Extrinsic | IExtrinsic | string | Uint8Array) => Observable<Hash>>;
- };
- babe: {
- /**
- * Returns data about which slots (primary or secondary) can be claimed in the current epoch with the keys in the keystore
- **/
- epochAuthorship: AugmentedRpc<() => Observable<HashMap<AuthorityId, EpochAuthorship>>>;
- };
- beefy: {
- /**
- * Returns hash of the latest BEEFY finalized block as seen by this client.
- **/
- getFinalizedHead: AugmentedRpc<() => Observable<H256>>;
- /**
- * Returns the block most recently finalized by BEEFY, alongside side its justification.
- **/
- subscribeJustifications: AugmentedRpc<() => Observable<BeefySignedCommitment>>;
- };
- chain: {
- /**
- * Get header and body of a relay chain block
- **/
- getBlock: AugmentedRpc<(hash?: BlockHash | string | Uint8Array) => Observable<SignedBlock>>;
- /**
- * Get the block hash for a specific block
- **/
- getBlockHash: AugmentedRpc<(blockNumber?: BlockNumber | AnyNumber | Uint8Array) => Observable<BlockHash>>;
- /**
- * Get hash of the last finalized block in the canon chain
- **/
- getFinalizedHead: AugmentedRpc<() => Observable<BlockHash>>;
- /**
- * Retrieves the header for a specific block
- **/
- getHeader: AugmentedRpc<(hash?: BlockHash | string | Uint8Array) => Observable<Header>>;
- /**
- * Retrieves the newest header via subscription
- **/
- subscribeAllHeads: AugmentedRpc<() => Observable<Header>>;
- /**
- * Retrieves the best finalized header via subscription
- **/
- subscribeFinalizedHeads: AugmentedRpc<() => Observable<Header>>;
- /**
- * Retrieves the best header via subscription
- **/
- subscribeNewHeads: AugmentedRpc<() => Observable<Header>>;
- };
- childstate: {
- /**
- * Returns the keys with prefix from a child storage, leave empty to get all the keys
- **/
- getKeys: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, prefix: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
- /**
- * Returns the keys with prefix from a child storage with pagination support
- **/
- getKeysPaged: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, prefix: StorageKey | string | Uint8Array | any, count: u32 | AnyNumber | Uint8Array, startKey?: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
- /**
- * Returns a child storage entry at a specific block state
- **/
- getStorage: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Option<StorageData>>>;
- /**
- * Returns child storage entries for multiple keys at a specific block state
- **/
- getStorageEntries: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: Hash | string | Uint8Array) => Observable<Vec<Option<StorageData>>>>;
- /**
- * Returns the hash of a child storage entry at a block state
- **/
- getStorageHash: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Option<Hash>>>;
- /**
- * Returns the size of a child storage entry at a block state
- **/
- getStorageSize: AugmentedRpc<(childKey: PrefixedStorageKey | string | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: Hash | string | Uint8Array) => Observable<Option<u64>>>;
- };
- contracts: {
- /**
- * @deprecated Use the runtime interface `api.call.contractsApi.call` instead
- * Executes a call to a contract
- **/
- call: AugmentedRpc<(callRequest: ContractCallRequest | { origin?: any; dest?: any; value?: any; gasLimit?: any; storageDepositLimit?: any; inputData?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractExecResult>>;
- /**
- * @deprecated Use the runtime interface `api.call.contractsApi.getStorage` instead
- * Returns the value under a specified storage key in a contract
- **/
- getStorage: AugmentedRpc<(address: AccountId | string | Uint8Array, key: H256 | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Option<Bytes>>>;
- /**
- * @deprecated Use the runtime interface `api.call.contractsApi.instantiate` instead
- * Instantiate a new contract
- **/
- instantiate: AugmentedRpc<(request: InstantiateRequestV1 | { origin?: any; value?: any; gasLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;
- /**
- * @deprecated Not available in newer versions of the contracts interfaces
- * Returns the projected time a given contract will be able to sustain paying its rent
- **/
- rentProjection: AugmentedRpc<(address: AccountId | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Option<BlockNumber>>>;
- /**
- * @deprecated Use the runtime interface `api.call.contractsApi.uploadCode` instead
- * Upload new code without instantiating a contract from it
- **/
- uploadCode: AugmentedRpc<(uploadRequest: CodeUploadRequest | { origin?: any; code?: any; storageDepositLimit?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<CodeUploadResult>>;
- };
- dev: {
- /**
- * Reexecute the specified `block_hash` and gather statistics while doing so
- **/
- getBlockStats: AugmentedRpc<(at: Hash | string | Uint8Array) => Observable<Option<BlockStats>>>;
- };
- engine: {
- /**
- * Instructs the manual-seal authorship task to create a new block
- **/
- createBlock: AugmentedRpc<(createEmpty: bool | boolean | Uint8Array, finalize: bool | boolean | Uint8Array, parentHash?: BlockHash | string | Uint8Array) => Observable<CreatedBlock>>;
- /**
- * Instructs the manual-seal authorship task to finalize a block
- **/
- finalizeBlock: AugmentedRpc<(hash: BlockHash | string | Uint8Array, justification?: Justification) => Observable<bool>>;
- };
- eth: {
- /**
- * Returns accounts list.
- **/
- accounts: AugmentedRpc<() => Observable<Vec<H160>>>;
- /**
- * Returns the blockNumber
- **/
- blockNumber: AugmentedRpc<() => Observable<U256>>;
- /**
- * Call contract, returning the output data.
- **/
- call: AugmentedRpc<(request: EthCallRequest | { from?: any; to?: any; gasPrice?: any; gas?: any; value?: any; data?: any; nonce?: any } | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<Bytes>>;
- /**
- * Returns the chain ID used for transaction signing at the current best block. None is returned if not available.
- **/
- chainId: AugmentedRpc<() => Observable<U64>>;
- /**
- * Returns block author.
- **/
- coinbase: AugmentedRpc<() => Observable<H160>>;
- /**
- * Estimate gas needed for execution of given contract.
- **/
- estimateGas: AugmentedRpc<(request: EthCallRequest | { from?: any; to?: any; gasPrice?: any; gas?: any; value?: any; data?: any; nonce?: any } | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
- /**
- * Returns fee history for given block count & reward percentiles
- **/
- feeHistory: AugmentedRpc<(blockCount: U256 | AnyNumber | Uint8Array, newestBlock: BlockNumber | AnyNumber | Uint8Array, rewardPercentiles: Option<Vec<f64>> | null | Uint8Array | Vec<f64> | (f64)[]) => Observable<EthFeeHistory>>;
- /**
- * Returns current gas price.
- **/
- gasPrice: AugmentedRpc<() => Observable<U256>>;
- /**
- * Returns balance of the given account.
- **/
- getBalance: AugmentedRpc<(address: H160 | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
- /**
- * Returns block with given hash.
- **/
- getBlockByHash: AugmentedRpc<(hash: H256 | string | Uint8Array, full: bool | boolean | Uint8Array) => Observable<Option<EthRichBlock>>>;
- /**
- * Returns block with given number.
- **/
- getBlockByNumber: AugmentedRpc<(block: BlockNumber | AnyNumber | Uint8Array, full: bool | boolean | Uint8Array) => Observable<Option<EthRichBlock>>>;
- /**
- * Returns the number of transactions in a block with given hash.
- **/
- getBlockTransactionCountByHash: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<U256>>;
- /**
- * Returns the number of transactions in a block with given block number.
- **/
- getBlockTransactionCountByNumber: AugmentedRpc<(block: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
- /**
- * Returns the code at given address at given time (block number).
- **/
- getCode: AugmentedRpc<(address: H160 | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<Bytes>>;
- /**
- * Returns filter changes since last poll.
- **/
- getFilterChanges: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array) => Observable<EthFilterChanges>>;
- /**
- * Returns all logs matching given filter (in a range 'from' - 'to').
- **/
- getFilterLogs: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array) => Observable<Vec<EthLog>>>;
- /**
- * Returns logs matching given filter object.
- **/
- getLogs: AugmentedRpc<(filter: EthFilter | { fromBlock?: any; toBlock?: any; blockHash?: any; address?: any; topics?: any } | string | Uint8Array) => Observable<Vec<EthLog>>>;
- /**
- * Returns proof for account and storage.
- **/
- getProof: AugmentedRpc<(address: H160 | string | Uint8Array, storageKeys: Vec<H256> | (H256 | string | Uint8Array)[], number: BlockNumber | AnyNumber | Uint8Array) => Observable<EthAccount>>;
- /**
- * Returns content of the storage at given address.
- **/
- getStorageAt: AugmentedRpc<(address: H160 | string | Uint8Array, index: U256 | AnyNumber | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<H256>>;
- /**
- * Returns transaction at given block hash and index.
- **/
- getTransactionByBlockHashAndIndex: AugmentedRpc<(hash: H256 | string | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthTransaction>>;
- /**
- * Returns transaction by given block number and index.
- **/
- getTransactionByBlockNumberAndIndex: AugmentedRpc<(number: BlockNumber | AnyNumber | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthTransaction>>;
- /**
- * Get transaction by its hash.
- **/
- getTransactionByHash: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<EthTransaction>>;
- /**
- * Returns the number of transactions sent from given address at given time (block number).
- **/
- getTransactionCount: AugmentedRpc<(address: H160 | string | Uint8Array, number?: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
- /**
- * Returns transaction receipt by transaction hash.
- **/
- getTransactionReceipt: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<EthReceipt>>;
- /**
- * Returns an uncles at given block and index.
- **/
- getUncleByBlockHashAndIndex: AugmentedRpc<(hash: H256 | string | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthRichBlock>>;
- /**
- * Returns an uncles at given block and index.
- **/
- getUncleByBlockNumberAndIndex: AugmentedRpc<(number: BlockNumber | AnyNumber | Uint8Array, index: U256 | AnyNumber | Uint8Array) => Observable<EthRichBlock>>;
- /**
- * Returns the number of uncles in a block with given hash.
- **/
- getUncleCountByBlockHash: AugmentedRpc<(hash: H256 | string | Uint8Array) => Observable<U256>>;
- /**
- * Returns the number of uncles in a block with given block number.
- **/
- getUncleCountByBlockNumber: AugmentedRpc<(number: BlockNumber | AnyNumber | Uint8Array) => Observable<U256>>;
- /**
- * Returns the hash of the current block, the seedHash, and the boundary condition to be met.
- **/
- getWork: AugmentedRpc<() => Observable<EthWork>>;
- /**
- * Returns the number of hashes per second that the node is mining with.
- **/
- hashrate: AugmentedRpc<() => Observable<U256>>;
- /**
- * Returns max priority fee per gas
- **/
- maxPriorityFeePerGas: AugmentedRpc<() => Observable<U256>>;
- /**
- * Returns true if client is actively mining new blocks.
- **/
- mining: AugmentedRpc<() => Observable<bool>>;
- /**
- * Returns id of new block filter.
- **/
- newBlockFilter: AugmentedRpc<() => Observable<U256>>;
- /**
- * Returns id of new filter.
- **/
- newFilter: AugmentedRpc<(filter: EthFilter | { fromBlock?: any; toBlock?: any; blockHash?: any; address?: any; topics?: any } | string | Uint8Array) => Observable<U256>>;
- /**
- * Returns id of new block filter.
- **/
- newPendingTransactionFilter: AugmentedRpc<() => Observable<U256>>;
- /**
- * Returns protocol version encoded as a string (quotes are necessary).
- **/
- protocolVersion: AugmentedRpc<() => Observable<u64>>;
- /**
- * Sends signed transaction, returning its hash.
- **/
- sendRawTransaction: AugmentedRpc<(bytes: Bytes | string | Uint8Array) => Observable<H256>>;
- /**
- * Sends transaction; will block waiting for signer to return the transaction hash
- **/
- sendTransaction: AugmentedRpc<(tx: EthTransactionRequest | { from?: any; to?: any; gasPrice?: any; gas?: any; value?: any; data?: any; nonce?: any } | string | Uint8Array) => Observable<H256>>;
- /**
- * Used for submitting mining hashrate.
- **/
- submitHashrate: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array, hash: H256 | string | Uint8Array) => Observable<bool>>;
- /**
- * Used for submitting a proof-of-work solution.
- **/
- submitWork: AugmentedRpc<(nonce: H64 | string | Uint8Array, headerHash: H256 | string | Uint8Array, mixDigest: H256 | string | Uint8Array) => Observable<bool>>;
- /**
- * Subscribe to Eth subscription.
- **/
- subscribe: AugmentedRpc<(kind: EthSubKind | 'newHeads' | 'logs' | 'newPendingTransactions' | 'syncing' | number | Uint8Array, params?: EthSubParams | { None: any } | { Logs: any } | string | Uint8Array) => Observable<Null>>;
- /**
- * Returns an object with data about the sync status or false.
- **/
- syncing: AugmentedRpc<() => Observable<EthSyncStatus>>;
- /**
- * Uninstalls filter.
- **/
- uninstallFilter: AugmentedRpc<(index: U256 | AnyNumber | Uint8Array) => Observable<bool>>;
- };
- grandpa: {
- /**
- * Prove finality for the given block number, returning the Justification for the last block in the set.
- **/
- proveFinality: AugmentedRpc<(blockNumber: BlockNumber | AnyNumber | Uint8Array) => Observable<Option<EncodedFinalityProofs>>>;
- /**
- * Returns the state of the current best round state as well as the ongoing background rounds
- **/
- roundState: AugmentedRpc<() => Observable<ReportedRoundStates>>;
- /**
- * Subscribes to grandpa justifications
- **/
- subscribeJustifications: AugmentedRpc<() => Observable<JustificationNotification>>;
- };
- mmr: {
- /**
- * Generate MMR proof for the given block numbers.
- **/
- generateProof: AugmentedRpc<(blockNumbers: Vec<u64> | (u64 | AnyNumber | Uint8Array)[], bestKnownBlockNumber?: u64 | AnyNumber | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<MmrLeafBatchProof>>;
- /**
- * Get the MMR root hash for the current best block.
- **/
- root: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<MmrHash>>;
- /**
- * Verify an MMR proof
- **/
- verifyProof: AugmentedRpc<(proof: MmrLeafBatchProof | { blockHash?: any; leaves?: any; proof?: any } | string | Uint8Array) => Observable<bool>>;
- /**
- * Verify an MMR proof statelessly given an mmr_root
- **/
- verifyProofStateless: AugmentedRpc<(root: MmrHash | string | Uint8Array, proof: MmrLeafBatchProof | { blockHash?: any; leaves?: any; proof?: any } | string | Uint8Array) => Observable<bool>>;
- };
- net: {
- /**
- * Returns true if client is actively listening for network connections. Otherwise false.
- **/
- listening: AugmentedRpc<() => Observable<bool>>;
- /**
- * Returns number of peers connected to node.
- **/
- peerCount: AugmentedRpc<() => Observable<Text>>;
- /**
- * Returns protocol version.
- **/
- version: AugmentedRpc<() => Observable<Text>>;
- };
- offchain: {
- /**
- * Get offchain local storage under given key and prefix
- **/
- localStorageGet: AugmentedRpc<(kind: StorageKind | 'PERSISTENT' | 'LOCAL' | number | Uint8Array, key: Bytes | string | Uint8Array) => Observable<Option<Bytes>>>;
- /**
- * Set offchain local storage under given key and prefix
- **/
- localStorageSet: AugmentedRpc<(kind: StorageKind | 'PERSISTENT' | 'LOCAL' | number | Uint8Array, key: Bytes | string | Uint8Array, value: Bytes | string | Uint8Array) => Observable<Null>>;
- };
- payment: {
- /**
- * @deprecated Use `api.call.transactionPaymentApi.queryFeeDetails` instead
- * Query the detailed fee of a given encoded extrinsic
- **/
- queryFeeDetails: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<FeeDetails>>;
- /**
- * @deprecated Use `api.call.transactionPaymentApi.queryInfo` instead
- * Retrieves the fee information for an encoded extrinsic
- **/
- queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfoV1>>;
- };
- rpc: {
- /**
- * Retrieves the list of RPC methods that are exposed by the node
- **/
- methods: AugmentedRpc<() => Observable<RpcMethods>>;
- };
- state: {
- /**
- * Perform a call to a builtin on the chain
- **/
- call: AugmentedRpc<(method: Text | string, data: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<Bytes>>;
- /**
- * Retrieves the keys with prefix of a specific child storage
- **/
- getChildKeys: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
- /**
- * Returns proof of storage for child key entries at a specific block state.
- **/
- getChildReadProof: AugmentedRpc<(childStorageKey: PrefixedStorageKey | string | Uint8Array, keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: BlockHash | string | Uint8Array) => Observable<ReadProof>>;
- /**
- * Retrieves the child storage for a key
- **/
- getChildStorage: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<StorageData>>;
- /**
- * Retrieves the child storage hash
- **/
- getChildStorageHash: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Hash>>;
- /**
- * Retrieves the child storage size
- **/
- getChildStorageSize: AugmentedRpc<(childStorageKey: StorageKey | string | Uint8Array | any, childDefinition: StorageKey | string | Uint8Array | any, childType: u32 | AnyNumber | Uint8Array, key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<u64>>;
- /**
- * @deprecated Use `api.rpc.state.getKeysPaged` to retrieve keys
- * Retrieves the keys with a certain prefix
- **/
- getKeys: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
- /**
- * Returns the keys with prefix with pagination support.
- **/
- getKeysPaged: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, count: u32 | AnyNumber | Uint8Array, startKey?: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<StorageKey>>>;
- /**
- * Returns the runtime metadata
- **/
- getMetadata: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<Metadata>>;
- /**
- * @deprecated Use `api.rpc.state.getKeysPaged` to retrieve keys
- * Returns the keys with prefix, leave empty to get all the keys (deprecated: Use getKeysPaged)
- **/
- getPairs: AugmentedRpc<(prefix: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Vec<KeyValue>>>;
- /**
- * Returns proof of storage entries at a specific block state
- **/
- getReadProof: AugmentedRpc<(keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: BlockHash | string | Uint8Array) => Observable<ReadProof>>;
- /**
- * Get the runtime version
- **/
- getRuntimeVersion: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<RuntimeVersion>>;
- /**
- * Retrieves the storage for a key
- **/
- getStorage: AugmentedRpc<<T = Codec>(key: StorageKey | string | Uint8Array | any, block?: Hash | Uint8Array | string) => Observable<T>>;
- /**
- * Retrieves the storage hash
- **/
- getStorageHash: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<Hash>>;
- /**
- * Retrieves the storage size
- **/
- getStorageSize: AugmentedRpc<(key: StorageKey | string | Uint8Array | any, at?: BlockHash | string | Uint8Array) => Observable<u64>>;
- /**
- * Query historical storage entries (by key) starting from a start block
- **/
- queryStorage: AugmentedRpc<<T = Codec[]>(keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], fromBlock?: Hash | Uint8Array | string, toBlock?: Hash | Uint8Array | string) => Observable<[Hash, T][]>>;
- /**
- * Query storage entries (by key) starting at block hash given as the second parameter
- **/
- queryStorageAt: AugmentedRpc<<T = Codec[]>(keys: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[], at?: Hash | Uint8Array | string) => Observable<T>>;
- /**
- * Retrieves the runtime version via subscription
- **/
- subscribeRuntimeVersion: AugmentedRpc<() => Observable<RuntimeVersion>>;
- /**
- * Subscribes to storage changes for the provided keys
- **/
- subscribeStorage: AugmentedRpc<<T = Codec[]>(keys?: Vec<StorageKey> | (StorageKey | string | Uint8Array | any)[]) => Observable<T>>;
- /**
- * Provides a way to trace the re-execution of a single block
- **/
- traceBlock: AugmentedRpc<(block: Hash | string | Uint8Array, targets: Option<Text> | null | Uint8Array | Text | string, storageKeys: Option<Text> | null | Uint8Array | Text | string, methods: Option<Text> | null | Uint8Array | Text | string) => Observable<TraceBlockResponse>>;
- /**
- * Check current migration state
- **/
- trieMigrationStatus: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<MigrationStatusResult>>;
- };
- syncstate: {
- /**
- * Returns the json-serialized chainspec running the node, with a sync state.
- **/
- genSyncSpec: AugmentedRpc<(raw: bool | boolean | Uint8Array) => Observable<Json>>;
- };
- system: {
- /**
- * Retrieves the next accountIndex as available on the node
- **/
- accountNextIndex: AugmentedRpc<(accountId: AccountId | string | Uint8Array) => Observable<Index>>;
- /**
- * Adds the supplied directives to the current log filter
- **/
- addLogFilter: AugmentedRpc<(directives: Text | string) => Observable<Null>>;
- /**
- * Adds a reserved peer
- **/
- addReservedPeer: AugmentedRpc<(peer: Text | string) => Observable<Text>>;
- /**
- * Retrieves the chain
- **/
- chain: AugmentedRpc<() => Observable<Text>>;
- /**
- * Retrieves the chain type
- **/
- chainType: AugmentedRpc<() => Observable<ChainType>>;
- /**
- * Dry run an extrinsic at a given block
- **/
- dryRun: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ApplyExtrinsicResult>>;
- /**
- * Return health status of the node
- **/
- health: AugmentedRpc<() => Observable<Health>>;
- /**
- * The addresses include a trailing /p2p/ with the local PeerId, and are thus suitable to be passed to addReservedPeer or as a bootnode address for example
- **/
- localListenAddresses: AugmentedRpc<() => Observable<Vec<Text>>>;
- /**
- * Returns the base58-encoded PeerId of the node
- **/
- localPeerId: AugmentedRpc<() => Observable<Text>>;
- /**
- * Retrieves the node name
- **/
- name: AugmentedRpc<() => Observable<Text>>;
- /**
- * Returns current state of the network
- **/
- networkState: AugmentedRpc<() => Observable<NetworkState>>;
- /**
- * Returns the roles the node is running as
- **/
- nodeRoles: AugmentedRpc<() => Observable<Vec<NodeRole>>>;
- /**
- * Returns the currently connected peers
- **/
- peers: AugmentedRpc<() => Observable<Vec<PeerInfo>>>;
- /**
- * Get a custom set of properties as a JSON object, defined in the chain spec
- **/
- properties: AugmentedRpc<() => Observable<ChainProperties>>;
- /**
- * Remove a reserved peer
- **/
- removeReservedPeer: AugmentedRpc<(peerId: Text | string) => Observable<Text>>;
- /**
- * Returns the list of reserved peers
- **/
- reservedPeers: AugmentedRpc<() => Observable<Vec<Text>>>;
- /**
- * Resets the log filter to Substrate defaults
- **/
- resetLogFilter: AugmentedRpc<() => Observable<Null>>;
- /**
- * Returns the state of the syncing of the node
- **/
- syncState: AugmentedRpc<() => Observable<SyncState>>;
- /**
- * Retrieves the version of the node
- **/
- version: AugmentedRpc<() => Observable<Text>>;
- };
- web3: {
- /**
- * Returns current client version.
- **/
- clientVersion: AugmentedRpc<() => Observable<Text>>;
- /**
- * Returns sha3 of the given data
- **/
- sha3: AugmentedRpc<(data: Bytes | string | Uint8Array) => Observable<H256>>;
- };
- } // RpcInterface
-} // declare module
js-packages/types/src/augment-api-runtime.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-runtime.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/api-base/types/calls';
-
-import type { ApiTypes, AugmentedCall, DecoratedCallBase } from '@polkadot/api-base/types';
-import type { Bytes, Null, Option, Result, U256, Vec, bool, u256, u32, u64 } from '@polkadot/types-codec';
-import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
-import type { CheckInherentsResult, InherentData } from '@polkadot/types/interfaces/blockbuilder';
-import type { BlockHash } from '@polkadot/types/interfaces/chain';
-import type { AuthorityId } from '@polkadot/types/interfaces/consensus';
-import type { CollationInfo } from '@polkadot/types/interfaces/cumulus';
-import type { BlockV2, EthReceiptV3, EthTransactionStatus, TransactionV2 } from '@polkadot/types/interfaces/eth';
-import type { EvmAccount, EvmCallInfoV2, EvmCreateInfoV2 } from '@polkadot/types/interfaces/evm';
-import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
-import type { OpaqueMetadata } from '@polkadot/types/interfaces/metadata';
-import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
-import type { AccountId, Balance, Block, H160, H256, Header, Index, KeyTypeId, Permill, SlotDuration, Weight } from '@polkadot/types/interfaces/runtime';
-import type { RuntimeVersion } from '@polkadot/types/interfaces/state';
-import type { ApplyExtrinsicResult, DispatchError } from '@polkadot/types/interfaces/system';
-import type { TransactionSource, TransactionValidity } from '@polkadot/types/interfaces/txqueue';
-import type { IExtrinsic, Observable } from '@polkadot/types/types';
-
-export type __AugmentedCall<ApiType extends ApiTypes> = AugmentedCall<ApiType>;
-export type __DecoratedCallBase<ApiType extends ApiTypes> = DecoratedCallBase<ApiType>;
-
-declare module '@polkadot/api-base/types/calls' {
- interface AugmentedCalls<ApiType extends ApiTypes> {
- /** 0xbc9d89904f5b923f/1 */
- accountNonceApi: {
- /**
- * The API to query account nonce (aka transaction index)
- **/
- accountNonce: AugmentedCall<ApiType, (accountId: AccountId | string | Uint8Array) => Observable<Index>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xdd718d5cc53262d4/1 */
- auraApi: {
- /**
- * Return the current set of authorities.
- **/
- authorities: AugmentedCall<ApiType, () => Observable<Vec<AuthorityId>>>;
- /**
- * Returns the slot duration for Aura.
- **/
- slotDuration: AugmentedCall<ApiType, () => Observable<SlotDuration>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0x40fe3ad401f8959a/6 */
- blockBuilder: {
- /**
- * Apply the given extrinsic.
- **/
- applyExtrinsic: AugmentedCall<ApiType, (extrinsic: Extrinsic | IExtrinsic | string | Uint8Array) => Observable<ApplyExtrinsicResult>>;
- /**
- * Check that the inherents are valid.
- **/
- checkInherents: AugmentedCall<ApiType, (block: Block | { header?: any; extrinsics?: any } | string | Uint8Array, data: InherentData | { data?: any } | string | Uint8Array) => Observable<CheckInherentsResult>>;
- /**
- * Finish the current block.
- **/
- finalizeBlock: AugmentedCall<ApiType, () => Observable<Header>>;
- /**
- * Generate inherent extrinsics.
- **/
- inherentExtrinsics: AugmentedCall<ApiType, (inherent: InherentData | { data?: any } | string | Uint8Array) => Observable<Vec<Extrinsic>>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xea93e3f16f3d6962/2 */
- collectCollationInfo: {
- /**
- * Collect information about a collation.
- **/
- collectCollationInfo: AugmentedCall<ApiType, (header: Header | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array) => Observable<CollationInfo>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xe65b00e46cedd0aa/2 */
- convertTransactionRuntimeApi: {
- /**
- * Converts an Ethereum-style transaction to Extrinsic
- **/
- convertTransaction: AugmentedCall<ApiType, (transaction: TransactionV2 | { Legacy: any } | { EIP2930: any } | { EIP1559: any } | string | Uint8Array) => Observable<Extrinsic>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xdf6acb689907609b/4 */
- core: {
- /**
- * Execute the given block.
- **/
- executeBlock: AugmentedCall<ApiType, (block: Block | { header?: any; extrinsics?: any } | string | Uint8Array) => Observable<Null>>;
- /**
- * Initialize a block with the given header.
- **/
- initializeBlock: AugmentedCall<ApiType, (header: Header | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array) => Observable<Null>>;
- /**
- * Returns the version of the runtime.
- **/
- version: AugmentedCall<ApiType, () => Observable<RuntimeVersion>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0x582211f65bb14b89/5 */
- ethereumRuntimeRPCApi: {
- /**
- * Returns pallet_evm::Accounts by address.
- **/
- accountBasic: AugmentedCall<ApiType, (address: H160 | string | Uint8Array) => Observable<EvmAccount>>;
- /**
- * For a given account address, returns pallet_evm::AccountCodes.
- **/
- accountCodeAt: AugmentedCall<ApiType, (address: H160 | string | Uint8Array) => Observable<Bytes>>;
- /**
- * Returns the converted FindAuthor::find_author authority id.
- **/
- author: AugmentedCall<ApiType, () => Observable<H160>>;
- /**
- * Returns a frame_ethereum::call response. If `estimate` is true,
- **/
- call: AugmentedCall<ApiType, (from: H160 | string | Uint8Array, to: H160 | string | Uint8Array, data: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: U256 | AnyNumber | Uint8Array, maxFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, estimate: bool | boolean | Uint8Array, accessList: Option<Vec<ITuple<[H160, Vec<H256>]>>> | null | Uint8Array | Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => Observable<Result<EvmCallInfoV2, DispatchError>>>;
- /**
- * Returns runtime defined pallet_evm::ChainId.
- **/
- chainId: AugmentedCall<ApiType, () => Observable<u64>>;
- /**
- * Returns a frame_ethereum::call response. If `estimate` is true,
- **/
- create: AugmentedCall<ApiType, (from: H160 | string | Uint8Array, data: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: U256 | AnyNumber | Uint8Array, maxFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, estimate: bool | boolean | Uint8Array, accessList: Option<Vec<ITuple<[H160, Vec<H256>]>>> | null | Uint8Array | Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => Observable<Result<EvmCreateInfoV2, DispatchError>>>;
- /**
- * Return all the current data for a block in a single runtime call.
- **/
- currentAll: AugmentedCall<ApiType, () => Observable<ITuple<[Option<BlockV2>, Option<Vec<EthReceiptV3>>, Option<Vec<EthTransactionStatus>>]>>>;
- /**
- * Return the current block.
- **/
- currentBlock: AugmentedCall<ApiType, () => Observable<BlockV2>>;
- /**
- * Return the current receipt.
- **/
- currentReceipts: AugmentedCall<ApiType, () => Observable<Option<Vec<EthReceiptV3>>>>;
- /**
- * Return the current transaction status.
- **/
- currentTransactionStatuses: AugmentedCall<ApiType, () => Observable<Option<Vec<EthTransactionStatus>>>>;
- /**
- * Return the elasticity multiplier.
- **/
- elasticity: AugmentedCall<ApiType, () => Observable<Option<Permill>>>;
- /**
- * Receives a `Vec<OpaqueExtrinsic>` and filters all the ethereum transactions.
- **/
- extrinsicFilter: AugmentedCall<ApiType, (xts: Vec<Extrinsic> | (Extrinsic | IExtrinsic | string | Uint8Array)[]) => Observable<Vec<TransactionV2>>>;
- /**
- * Returns FixedGasPrice::min_gas_price
- **/
- gasPrice: AugmentedCall<ApiType, () => Observable<u256>>;
- /**
- * For a given account address and index, returns pallet_evm::AccountStorages.
- **/
- storageAt: AugmentedCall<ApiType, (address: H160 | string | Uint8Array, index: u256 | AnyNumber | Uint8Array) => Observable<H256>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0x37e397fc7c91f5e4/2 */
- metadata: {
- /**
- * Returns the metadata of a runtime
- **/
- metadata: AugmentedCall<ApiType, () => Observable<OpaqueMetadata>>;
- /**
- * Returns the metadata at a given version.
- **/
- metadataAtVersion: AugmentedCall<ApiType, (version: u32 | AnyNumber | Uint8Array) => Observable<Option<OpaqueMetadata>>>;
- /**
- * Returns the supported metadata versions.
- **/
- metadataVersions: AugmentedCall<ApiType, () => Observable<Vec<u32>>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xf78b278be53f454c/2 */
- offchainWorkerApi: {
- /**
- * Starts the off-chain task for given block header.
- **/
- offchainWorker: AugmentedCall<ApiType, (header: Header | { parentHash?: any; number?: any; stateRoot?: any; extrinsicsRoot?: any; digest?: any } | string | Uint8Array) => Observable<Null>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xab3c0572291feb8b/1 */
- sessionKeys: {
- /**
- * Decode the given public session keys.
- **/
- decodeSessionKeys: AugmentedCall<ApiType, (encoded: Bytes | string | Uint8Array) => Observable<Option<Vec<ITuple<[Bytes, KeyTypeId]>>>>>;
- /**
- * Generate a set of session keys with optionally using the given seed.
- **/
- generateSessionKeys: AugmentedCall<ApiType, (seed: Option<Bytes> | null | Uint8Array | Bytes | string) => Observable<Bytes>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0xd2bc9897eed08f15/3 */
- taggedTransactionQueue: {
- /**
- * Validate the transaction.
- **/
- validateTransaction: AugmentedCall<ApiType, (source: TransactionSource | 'InBlock' | 'Local' | 'External' | number | Uint8Array, tx: Extrinsic | IExtrinsic | string | Uint8Array, blockHash: BlockHash | string | Uint8Array) => Observable<TransactionValidity>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- /** 0x37c8bb1350a9a2a8/4 */
- transactionPaymentApi: {
- /**
- * The transaction fee details
- **/
- queryFeeDetails: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<FeeDetails>>;
- /**
- * The transaction info
- **/
- queryInfo: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<RuntimeDispatchInfo>>;
- /**
- * Query the output of the current LengthToFee given some input
- **/
- queryLengthToFee: AugmentedCall<ApiType, (length: u32 | AnyNumber | Uint8Array) => Observable<Balance>>;
- /**
- * Query the output of the current WeightToFee given some input
- **/
- queryWeightToFee: AugmentedCall<ApiType, (weight: Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => Observable<Balance>>;
- /**
- * Generic call
- **/
- [key: string]: DecoratedCallBase<ApiType>;
- };
- } // AugmentedCalls
-} // declare module
js-packages/types/src/augment-api-tx.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api-tx.ts
+++ /dev/null
@@ -1,1250 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/api-base/types/submittable';
-
-import type { ApiTypes, AugmentedSubmittable, SubmittableExtrinsic, SubmittableExtrinsicFunction } from '@polkadot/api-base/types';
-import type { Data } from '@polkadot/types';
-import type { Bytes, Compact, Option, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
-import type { AnyNumber, IMethod, ITuple } from '@polkadot/types-codec/types';
-import type { AccountId32, Call, H160, H256, MultiAddress } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumLog, EthereumTransactionTransactionV2, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime, OpalRuntimeOriginCaller, OpalRuntimeRuntimeCommonSessionKeys, OrmlVestingVestingSchedule, PalletConfigurationAppPromotionConfiguration, PalletDemocracyConviction, PalletDemocracyMetadataOwner, PalletDemocracyVoteAccountVote, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletIdentityBitFlags, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletIdentityRegistration, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletStateTrieMigrationProgress, SpWeightsWeightV2Weight, StagingXcmV3MultiLocation, StagingXcmV3WeightLimit, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation, StagingXcmVersionedXcm, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission } from '@polkadot/types/lookup';
-
-export type __AugmentedSubmittable = AugmentedSubmittable<() => unknown>;
-export type __SubmittableExtrinsic<ApiType extends ApiTypes> = SubmittableExtrinsic<ApiType>;
-export type __SubmittableExtrinsicFunction<ApiType extends ApiTypes> = SubmittableExtrinsicFunction<ApiType>;
-
-declare module '@polkadot/api-base/types/submittable' {
- interface AugmentedSubmittables<ApiType extends ApiTypes> {
- appPromotion: {
- /**
- * See [`Pallet::force_unstake`].
- **/
- forceUnstake: AugmentedSubmittable<(pendingBlocks: Vec<u32> | (u32 | AnyNumber | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<u32>]>;
- /**
- * See [`Pallet::payout_stakers`].
- **/
- payoutStakers: AugmentedSubmittable<(stakersNumber: Option<u8> | null | Uint8Array | u8 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u8>]>;
- /**
- * See [`Pallet::set_admin_address`].
- **/
- setAdminAddress: AugmentedSubmittable<(admin: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * See [`Pallet::sponsor_collection`].
- **/
- sponsorCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::sponsor_contract`].
- **/
- sponsorContract: AugmentedSubmittable<(contractId: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
- /**
- * See [`Pallet::stake`].
- **/
- stake: AugmentedSubmittable<(amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u128]>;
- /**
- * See [`Pallet::stop_sponsoring_collection`].
- **/
- stopSponsoringCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::stop_sponsoring_contract`].
- **/
- stopSponsoringContract: AugmentedSubmittable<(contractId: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
- /**
- * See [`Pallet::unstake_all`].
- **/
- unstakeAll: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::unstake_partial`].
- **/
- unstakePartial: AugmentedSubmittable<(amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u128]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- balances: {
- /**
- * See [`Pallet::force_set_balance`].
- **/
- forceSetBalance: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, newFree: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
- /**
- * See [`Pallet::force_transfer`].
- **/
- forceTransfer: AugmentedSubmittable<(source: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress, Compact<u128>]>;
- /**
- * See [`Pallet::force_unreserve`].
- **/
- forceUnreserve: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, u128]>;
- /**
- * See [`Pallet::set_balance_deprecated`].
- **/
- setBalanceDeprecated: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, newFree: Compact<u128> | AnyNumber | Uint8Array, oldReserved: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>, Compact<u128>]>;
- /**
- * See [`Pallet::transfer`].
- **/
- transfer: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
- /**
- * See [`Pallet::transfer_all`].
- **/
- transferAll: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, keepAlive: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, bool]>;
- /**
- * See [`Pallet::transfer_allow_death`].
- **/
- transferAllowDeath: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
- /**
- * See [`Pallet::transfer_keep_alive`].
- **/
- transferKeepAlive: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Compact<u128>]>;
- /**
- * See [`Pallet::upgrade_accounts`].
- **/
- upgradeAccounts: AugmentedSubmittable<(who: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- collatorSelection: {
- /**
- * See [`Pallet::add_invulnerable`].
- **/
- addInvulnerable: AugmentedSubmittable<(updated: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
- /**
- * See [`Pallet::force_release_license`].
- **/
- forceReleaseLicense: AugmentedSubmittable<(who: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
- /**
- * See [`Pallet::get_license`].
- **/
- getLicense: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::offboard`].
- **/
- offboard: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::onboard`].
- **/
- onboard: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::release_license`].
- **/
- releaseLicense: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::remove_invulnerable`].
- **/
- removeInvulnerable: AugmentedSubmittable<(who: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- configuration: {
- /**
- * See [`Pallet::set_app_promotion_configuration_override`].
- **/
- setAppPromotionConfigurationOverride: AugmentedSubmittable<(configuration: PalletConfigurationAppPromotionConfiguration | { recalculationInterval?: any; pendingInterval?: any; intervalIncome?: any; maxStakersPerCalculation?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletConfigurationAppPromotionConfiguration]>;
- /**
- * See [`Pallet::set_collator_selection_desired_collators`].
- **/
- setCollatorSelectionDesiredCollators: AugmentedSubmittable<(max: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
- /**
- * See [`Pallet::set_collator_selection_kick_threshold`].
- **/
- setCollatorSelectionKickThreshold: AugmentedSubmittable<(threshold: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
- /**
- * See [`Pallet::set_collator_selection_license_bond`].
- **/
- setCollatorSelectionLicenseBond: AugmentedSubmittable<(amount: Option<u128> | null | Uint8Array | u128 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u128>]>;
- /**
- * See [`Pallet::set_min_gas_price_override`].
- **/
- setMinGasPriceOverride: AugmentedSubmittable<(coeff: Option<u64> | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u64>]>;
- /**
- * See [`Pallet::set_weight_to_fee_coefficient_override`].
- **/
- setWeightToFeeCoefficientOverride: AugmentedSubmittable<(coeff: Option<u64> | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u64>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- council: {
- /**
- * See [`Pallet::close`].
- **/
- close: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, proposalWeightBound: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, SpWeightsWeightV2Weight, Compact<u32>]>;
- /**
- * See [`Pallet::disapprove_proposal`].
- **/
- disapproveProposal: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
- /**
- * See [`Pallet::execute`].
- **/
- execute: AugmentedSubmittable<(proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, Compact<u32>]>;
- /**
- * See [`Pallet::propose`].
- **/
- propose: AugmentedSubmittable<(threshold: Compact<u32> | AnyNumber | Uint8Array, proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Call, Compact<u32>]>;
- /**
- * See [`Pallet::set_members`].
- **/
- setMembers: AugmentedSubmittable<(newMembers: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[], prime: Option<AccountId32> | null | Uint8Array | AccountId32 | string, oldCount: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>, Option<AccountId32>, u32]>;
- /**
- * See [`Pallet::vote`].
- **/
- vote: AugmentedSubmittable<(proposal: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, bool]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- councilMembership: {
- /**
- * See [`Pallet::add_member`].
- **/
- addMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::change_key`].
- **/
- changeKey: AugmentedSubmittable<(updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::clear_prime`].
- **/
- clearPrime: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::remove_member`].
- **/
- removeMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::reset_members`].
- **/
- resetMembers: AugmentedSubmittable<(members: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
- /**
- * See [`Pallet::set_prime`].
- **/
- setPrime: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::swap_member`].
- **/
- swapMember: AugmentedSubmittable<(remove: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, add: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- cumulusXcm: {
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- democracy: {
- /**
- * See [`Pallet::blacklist`].
- **/
- blacklist: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, maybeRefIndex: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [H256, Option<u32>]>;
- /**
- * See [`Pallet::cancel_proposal`].
- **/
- cancelProposal: AugmentedSubmittable<(propIndex: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
- /**
- * See [`Pallet::cancel_referendum`].
- **/
- cancelReferendum: AugmentedSubmittable<(refIndex: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
- /**
- * See [`Pallet::clear_public_proposals`].
- **/
- clearPublicProposals: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::delegate`].
- **/
- delegate: AugmentedSubmittable<(to: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, conviction: PalletDemocracyConviction | 'None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x' | 'Locked6x' | number | Uint8Array, balance: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletDemocracyConviction, u128]>;
- /**
- * See [`Pallet::emergency_cancel`].
- **/
- emergencyCancel: AugmentedSubmittable<(refIndex: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::external_propose`].
- **/
- externalPropose: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded]>;
- /**
- * See [`Pallet::external_propose_default`].
- **/
- externalProposeDefault: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded]>;
- /**
- * See [`Pallet::external_propose_majority`].
- **/
- externalProposeMajority: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded]>;
- /**
- * See [`Pallet::fast_track`].
- **/
- fastTrack: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, votingPeriod: u32 | AnyNumber | Uint8Array, delay: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, u32, u32]>;
- /**
- * See [`Pallet::propose`].
- **/
- propose: AugmentedSubmittable<(proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array, value: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [FrameSupportPreimagesBounded, Compact<u128>]>;
- /**
- * See [`Pallet::remove_other_vote`].
- **/
- removeOtherVote: AugmentedSubmittable<(target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, u32]>;
- /**
- * See [`Pallet::remove_vote`].
- **/
- removeVote: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::second`].
- **/
- second: AugmentedSubmittable<(proposal: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
- /**
- * See [`Pallet::set_metadata`].
- **/
- setMetadata: AugmentedSubmittable<(owner: PalletDemocracyMetadataOwner | { External: any } | { Proposal: any } | { Referendum: any } | string | Uint8Array, maybeHash: Option<H256> | null | Uint8Array | H256 | string) => SubmittableExtrinsic<ApiType>, [PalletDemocracyMetadataOwner, Option<H256>]>;
- /**
- * See [`Pallet::undelegate`].
- **/
- undelegate: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::unlock`].
- **/
- unlock: AugmentedSubmittable<(target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::veto_external`].
- **/
- vetoExternal: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
- /**
- * See [`Pallet::vote`].
- **/
- vote: AugmentedSubmittable<(refIndex: Compact<u32> | AnyNumber | Uint8Array, vote: PalletDemocracyVoteAccountVote | { Standard: any } | { Split: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, PalletDemocracyVoteAccountVote]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- dmpQueue: {
- /**
- * See [`Pallet::service_overweight`].
- **/
- serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u64, SpWeightsWeightV2Weight]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- ethereum: {
- /**
- * See [`Pallet::transact`].
- **/
- transact: AugmentedSubmittable<(transaction: EthereumTransactionTransactionV2 | { Legacy: any } | { EIP2930: any } | { EIP1559: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [EthereumTransactionTransactionV2]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- evm: {
- /**
- * See [`Pallet::call`].
- **/
- call: AugmentedSubmittable<(source: H160 | string | Uint8Array, target: H160 | string | Uint8Array, input: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: u64 | AnyNumber | Uint8Array, maxFeePerGas: U256 | AnyNumber | Uint8Array, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, accessList: Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => SubmittableExtrinsic<ApiType>, [H160, H160, Bytes, U256, u64, U256, Option<U256>, Option<U256>, Vec<ITuple<[H160, Vec<H256>]>>]>;
- /**
- * See [`Pallet::create`].
- **/
- create: AugmentedSubmittable<(source: H160 | string | Uint8Array, init: Bytes | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: u64 | AnyNumber | Uint8Array, maxFeePerGas: U256 | AnyNumber | Uint8Array, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, accessList: Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => SubmittableExtrinsic<ApiType>, [H160, Bytes, U256, u64, U256, Option<U256>, Option<U256>, Vec<ITuple<[H160, Vec<H256>]>>]>;
- /**
- * See [`Pallet::create2`].
- **/
- create2: AugmentedSubmittable<(source: H160 | string | Uint8Array, init: Bytes | string | Uint8Array, salt: H256 | string | Uint8Array, value: U256 | AnyNumber | Uint8Array, gasLimit: u64 | AnyNumber | Uint8Array, maxFeePerGas: U256 | AnyNumber | Uint8Array, maxPriorityFeePerGas: Option<U256> | null | Uint8Array | U256 | AnyNumber, nonce: Option<U256> | null | Uint8Array | U256 | AnyNumber, accessList: Vec<ITuple<[H160, Vec<H256>]>> | ([H160 | string | Uint8Array, Vec<H256> | (H256 | string | Uint8Array)[]])[]) => SubmittableExtrinsic<ApiType>, [H160, Bytes, H256, U256, u64, U256, Option<U256>, Option<U256>, Vec<ITuple<[H160, Vec<H256>]>>]>;
- /**
- * See [`Pallet::withdraw`].
- **/
- withdraw: AugmentedSubmittable<(address: H160 | string | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160, u128]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- evmContractHelpers: {
- /**
- * See [`Pallet::migrate_from_self_sponsoring`].
- **/
- migrateFromSelfSponsoring: AugmentedSubmittable<(addresses: Vec<H160> | (H160 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<H160>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- evmMigration: {
- /**
- * See [`Pallet::begin`].
- **/
- begin: AugmentedSubmittable<(address: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
- /**
- * See [`Pallet::finish`].
- **/
- finish: AugmentedSubmittable<(address: H160 | string | Uint8Array, code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160, Bytes]>;
- /**
- * See [`Pallet::insert_eth_logs`].
- **/
- insertEthLogs: AugmentedSubmittable<(logs: Vec<EthereumLog> | (EthereumLog | { address?: any; topics?: any; data?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<EthereumLog>]>;
- /**
- * See [`Pallet::insert_events`].
- **/
- insertEvents: AugmentedSubmittable<(events: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>]>;
- /**
- * See [`Pallet::remove_rmrk_data`].
- **/
- removeRmrkData: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::set_data`].
- **/
- setData: AugmentedSubmittable<(address: H160 | string | Uint8Array, data: Vec<ITuple<[H256, H256]>> | ([H256 | string | Uint8Array, H256 | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [H160, Vec<ITuple<[H256, H256]>>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- fellowshipCollective: {
- /**
- * See [`Pallet::add_member`].
- **/
- addMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::cleanup_poll`].
- **/
- cleanupPoll: AugmentedSubmittable<(pollIndex: u32 | AnyNumber | Uint8Array, max: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
- /**
- * See [`Pallet::demote_member`].
- **/
- demoteMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::promote_member`].
- **/
- promoteMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::remove_member`].
- **/
- removeMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, minRank: u16 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, u16]>;
- /**
- * See [`Pallet::vote`].
- **/
- vote: AugmentedSubmittable<(poll: u32 | AnyNumber | Uint8Array, aye: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- fellowshipReferenda: {
- /**
- * See [`Pallet::cancel`].
- **/
- cancel: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::kill`].
- **/
- kill: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::nudge_referendum`].
- **/
- nudgeReferendum: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::one_fewer_deciding`].
- **/
- oneFewerDeciding: AugmentedSubmittable<(track: u16 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u16]>;
- /**
- * See [`Pallet::place_decision_deposit`].
- **/
- placeDecisionDeposit: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::refund_decision_deposit`].
- **/
- refundDecisionDeposit: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::refund_submission_deposit`].
- **/
- refundSubmissionDeposit: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::set_metadata`].
- **/
- setMetadata: AugmentedSubmittable<(index: u32 | AnyNumber | Uint8Array, maybeHash: Option<H256> | null | Uint8Array | H256 | string) => SubmittableExtrinsic<ApiType>, [u32, Option<H256>]>;
- /**
- * See [`Pallet::submit`].
- **/
- submit: AugmentedSubmittable<(proposalOrigin: OpalRuntimeOriginCaller | { system: any } | { Void: any } | { Council: any } | { TechnicalCommittee: any } | { PolkadotXcm: any } | { CumulusXcm: any } | { Origins: any } | { Ethereum: any } | string | Uint8Array, proposal: FrameSupportPreimagesBounded | { Legacy: any } | { Inline: any } | { Lookup: any } | string | Uint8Array, enactmentMoment: FrameSupportScheduleDispatchTime | { At: any } | { After: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [OpalRuntimeOriginCaller, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- foreignAssets: {
- /**
- * See [`Pallet::register_foreign_asset`].
- **/
- registerForeignAsset: AugmentedSubmittable<(owner: AccountId32 | string | Uint8Array, location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, metadata: PalletForeignAssetsModuleAssetMetadata | { name?: any; symbol?: any; decimals?: any; minimalBalance?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32, StagingXcmVersionedMultiLocation, PalletForeignAssetsModuleAssetMetadata]>;
- /**
- * See [`Pallet::update_foreign_asset`].
- **/
- updateForeignAsset: AugmentedSubmittable<(foreignAssetId: u32 | AnyNumber | Uint8Array, location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, metadata: PalletForeignAssetsModuleAssetMetadata | { name?: any; symbol?: any; decimals?: any; minimalBalance?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, StagingXcmVersionedMultiLocation, PalletForeignAssetsModuleAssetMetadata]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- identity: {
- /**
- * See [`Pallet::add_registrar`].
- **/
- addRegistrar: AugmentedSubmittable<(account: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::add_sub`].
- **/
- addSub: AugmentedSubmittable<(sub: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, data: Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Data]>;
- /**
- * See [`Pallet::cancel_request`].
- **/
- cancelRequest: AugmentedSubmittable<(regIndex: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::clear_identity`].
- **/
- clearIdentity: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::force_insert_identities`].
- **/
- forceInsertIdentities: AugmentedSubmittable<(identities: Vec<ITuple<[AccountId32, PalletIdentityRegistration]>> | ([AccountId32 | string | Uint8Array, PalletIdentityRegistration | { judgements?: any; deposit?: any; info?: any } | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[AccountId32, PalletIdentityRegistration]>>]>;
- /**
- * See [`Pallet::force_remove_identities`].
- **/
- forceRemoveIdentities: AugmentedSubmittable<(identities: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
- /**
- * See [`Pallet::force_set_subs`].
- **/
- forceSetSubs: AugmentedSubmittable<(subs: Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>> | ([AccountId32 | string | Uint8Array, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]> | [u128 | AnyNumber | Uint8Array, Vec<ITuple<[AccountId32, Data]>> | ([AccountId32 | string | Uint8Array, Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array])[]]])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>>]>;
- /**
- * See [`Pallet::kill_identity`].
- **/
- killIdentity: AugmentedSubmittable<(target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::provide_judgement`].
- **/
- provideJudgement: AugmentedSubmittable<(regIndex: Compact<u32> | AnyNumber | Uint8Array, target: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, judgement: PalletIdentityJudgement | { Unknown: any } | { FeePaid: any } | { Reasonable: any } | { KnownGood: any } | { OutOfDate: any } | { LowQuality: any } | { Erroneous: any } | string | Uint8Array, identity: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, MultiAddress, PalletIdentityJudgement, H256]>;
- /**
- * See [`Pallet::quit_sub`].
- **/
- quitSub: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::remove_sub`].
- **/
- removeSub: AugmentedSubmittable<(sub: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::rename_sub`].
- **/
- renameSub: AugmentedSubmittable<(sub: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, data: Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Data]>;
- /**
- * See [`Pallet::request_judgement`].
- **/
- requestJudgement: AugmentedSubmittable<(regIndex: Compact<u32> | AnyNumber | Uint8Array, maxFee: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Compact<u128>]>;
- /**
- * See [`Pallet::set_account_id`].
- **/
- setAccountId: AugmentedSubmittable<(index: Compact<u32> | AnyNumber | Uint8Array, updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, MultiAddress]>;
- /**
- * See [`Pallet::set_fee`].
- **/
- setFee: AugmentedSubmittable<(index: Compact<u32> | AnyNumber | Uint8Array, fee: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Compact<u128>]>;
- /**
- * See [`Pallet::set_fields`].
- **/
- setFields: AugmentedSubmittable<(index: Compact<u32> | AnyNumber | Uint8Array, fields: PalletIdentityBitFlags) => SubmittableExtrinsic<ApiType>, [Compact<u32>, PalletIdentityBitFlags]>;
- /**
- * See [`Pallet::set_identity`].
- **/
- setIdentity: AugmentedSubmittable<(info: PalletIdentityIdentityInfo | { additional?: any; display?: any; legal?: any; web?: any; riot?: any; email?: any; pgpFingerprint?: any; image?: any; twitter?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletIdentityIdentityInfo]>;
- /**
- * See [`Pallet::set_subs`].
- **/
- setSubs: AugmentedSubmittable<(subs: Vec<ITuple<[AccountId32, Data]>> | ([AccountId32 | string | Uint8Array, Data | { None: any } | { Raw: any } | { BlakeTwo256: any } | { Sha256: any } | { Keccak256: any } | { ShaThree256: any } | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[AccountId32, Data]>>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- inflation: {
- /**
- * See [`Pallet::start_inflation`].
- **/
- startInflation: AugmentedSubmittable<(inflationStartRelayBlock: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- maintenance: {
- /**
- * See [`Pallet::disable`].
- **/
- disable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::enable`].
- **/
- enable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- parachainInfo: {
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- parachainSystem: {
- /**
- * See [`Pallet::authorize_upgrade`].
- **/
- authorizeUpgrade: AugmentedSubmittable<(codeHash: H256 | string | Uint8Array, checkVersion: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, bool]>;
- /**
- * See [`Pallet::enact_authorized_upgrade`].
- **/
- enactAuthorizedUpgrade: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * See [`Pallet::set_validation_data`].
- **/
- setValidationData: AugmentedSubmittable<(data: CumulusPrimitivesParachainInherentParachainInherentData | { validationData?: any; relayChainState?: any; downwardMessages?: any; horizontalMessages?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [CumulusPrimitivesParachainInherentParachainInherentData]>;
- /**
- * See [`Pallet::sudo_send_upward_message`].
- **/
- sudoSendUpwardMessage: AugmentedSubmittable<(message: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- polkadotXcm: {
- /**
- * See [`Pallet::execute`].
- **/
- execute: AugmentedSubmittable<(message: StagingXcmVersionedXcm | { V2: any } | { V3: any } | string | Uint8Array, maxWeight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedXcm, SpWeightsWeightV2Weight]>;
- /**
- * See [`Pallet::force_default_xcm_version`].
- **/
- forceDefaultXcmVersion: AugmentedSubmittable<(maybeXcmVersion: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
- /**
- * See [`Pallet::force_subscribe_version_notify`].
- **/
- forceSubscribeVersionNotify: AugmentedSubmittable<(location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation]>;
- /**
- * See [`Pallet::force_suspension`].
- **/
- forceSuspension: AugmentedSubmittable<(suspended: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [bool]>;
- /**
- * See [`Pallet::force_unsubscribe_version_notify`].
- **/
- forceUnsubscribeVersionNotify: AugmentedSubmittable<(location: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation]>;
- /**
- * See [`Pallet::force_xcm_version`].
- **/
- forceXcmVersion: AugmentedSubmittable<(location: StagingXcmV3MultiLocation | { parents?: any; interior?: any } | string | Uint8Array, version: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmV3MultiLocation, u32]>;
- /**
- * See [`Pallet::limited_reserve_transfer_assets`].
- **/
- limitedReserveTransferAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array, weightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::limited_teleport_assets`].
- **/
- limitedTeleportAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array, weightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::reserve_transfer_assets`].
- **/
- reserveTransferAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32]>;
- /**
- * See [`Pallet::send`].
- **/
- send: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, message: StagingXcmVersionedXcm | { V2: any } | { V3: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedXcm]>;
- /**
- * See [`Pallet::teleport_assets`].
- **/
- teleportAssets: AugmentedSubmittable<(dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, beneficiary: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeAssetItem: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiLocation, StagingXcmVersionedMultiAssets, u32]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- preimage: {
- /**
- * See [`Pallet::note_preimage`].
- **/
- notePreimage: AugmentedSubmittable<(bytes: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * See [`Pallet::request_preimage`].
- **/
- requestPreimage: AugmentedSubmittable<(hash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
- /**
- * See [`Pallet::unnote_preimage`].
- **/
- unnotePreimage: AugmentedSubmittable<(hash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
- /**
- * See [`Pallet::unrequest_preimage`].
- **/
- unrequestPreimage: AugmentedSubmittable<(hash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- scheduler: {
- /**
- * See [`Pallet::cancel`].
- **/
- cancel: AugmentedSubmittable<(when: u32 | AnyNumber | Uint8Array, index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
- /**
- * See [`Pallet::cancel_named`].
- **/
- cancelNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed]>;
- /**
- * See [`Pallet::schedule`].
- **/
- schedule: AugmentedSubmittable<(when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
- /**
- * See [`Pallet::schedule_after`].
- **/
- scheduleAfter: AugmentedSubmittable<(after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
- /**
- * See [`Pallet::schedule_named`].
- **/
- scheduleNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
- /**
- * See [`Pallet::schedule_named_after`].
- **/
- scheduleNamedAfter: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: u8 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, u8, Call]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- session: {
- /**
- * See [`Pallet::purge_keys`].
- **/
- purgeKeys: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::set_keys`].
- **/
- setKeys: AugmentedSubmittable<(keys: OpalRuntimeRuntimeCommonSessionKeys | { aura?: any } | string | Uint8Array, proof: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [OpalRuntimeRuntimeCommonSessionKeys, Bytes]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- stateTrieMigration: {
- /**
- * See [`Pallet::continue_migrate`].
- **/
- continueMigrate: AugmentedSubmittable<(limits: PalletStateTrieMigrationMigrationLimits | { size_?: any; item?: any } | string | Uint8Array, realSizeUpper: u32 | AnyNumber | Uint8Array, witnessTask: PalletStateTrieMigrationMigrationTask | { progressTop?: any; progressChild?: any; size_?: any; topItems?: any; childItems?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletStateTrieMigrationMigrationLimits, u32, PalletStateTrieMigrationMigrationTask]>;
- /**
- * See [`Pallet::control_auto_migration`].
- **/
- controlAutoMigration: AugmentedSubmittable<(maybeConfig: Option<PalletStateTrieMigrationMigrationLimits> | null | Uint8Array | PalletStateTrieMigrationMigrationLimits | { size_?: any; item?: any } | string) => SubmittableExtrinsic<ApiType>, [Option<PalletStateTrieMigrationMigrationLimits>]>;
- /**
- * See [`Pallet::force_set_progress`].
- **/
- forceSetProgress: AugmentedSubmittable<(progressTop: PalletStateTrieMigrationProgress | { ToStart: any } | { LastKey: any } | { Complete: any } | string | Uint8Array, progressChild: PalletStateTrieMigrationProgress | { ToStart: any } | { LastKey: any } | { Complete: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletStateTrieMigrationProgress, PalletStateTrieMigrationProgress]>;
- /**
- * See [`Pallet::migrate_custom_child`].
- **/
- migrateCustomChild: AugmentedSubmittable<(root: Bytes | string | Uint8Array, childKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[], totalSize: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes, Vec<Bytes>, u32]>;
- /**
- * See [`Pallet::migrate_custom_top`].
- **/
- migrateCustomTop: AugmentedSubmittable<(keys: Vec<Bytes> | (Bytes | string | Uint8Array)[], witnessSize: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>, u32]>;
- /**
- * See [`Pallet::set_signed_max_limits`].
- **/
- setSignedMaxLimits: AugmentedSubmittable<(limits: PalletStateTrieMigrationMigrationLimits | { size_?: any; item?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletStateTrieMigrationMigrationLimits]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- structure: {
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- sudo: {
- /**
- * See [`Pallet::set_key`].
- **/
- setKey: AugmentedSubmittable<(updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::sudo`].
- **/
- sudo: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call]>;
- /**
- * See [`Pallet::sudo_as`].
- **/
- sudoAs: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Call]>;
- /**
- * See [`Pallet::sudo_unchecked_weight`].
- **/
- sudoUncheckedWeight: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array, weight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, SpWeightsWeightV2Weight]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- system: {
- /**
- * See [`Pallet::kill_prefix`].
- **/
- killPrefix: AugmentedSubmittable<(prefix: Bytes | string | Uint8Array, subkeys: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes, u32]>;
- /**
- * See [`Pallet::kill_storage`].
- **/
- killStorage: AugmentedSubmittable<(keys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>]>;
- /**
- * See [`Pallet::remark`].
- **/
- remark: AugmentedSubmittable<(remark: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * See [`Pallet::remark_with_event`].
- **/
- remarkWithEvent: AugmentedSubmittable<(remark: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * See [`Pallet::set_code`].
- **/
- setCode: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * See [`Pallet::set_code_without_checks`].
- **/
- setCodeWithoutChecks: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes]>;
- /**
- * See [`Pallet::set_heap_pages`].
- **/
- setHeapPages: AugmentedSubmittable<(pages: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u64]>;
- /**
- * See [`Pallet::set_storage`].
- **/
- setStorage: AugmentedSubmittable<(items: Vec<ITuple<[Bytes, Bytes]>> | ([Bytes | string | Uint8Array, Bytes | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[Bytes, Bytes]>>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- technicalCommittee: {
- /**
- * See [`Pallet::close`].
- **/
- close: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, proposalWeightBound: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, SpWeightsWeightV2Weight, Compact<u32>]>;
- /**
- * See [`Pallet::disapprove_proposal`].
- **/
- disapproveProposal: AugmentedSubmittable<(proposalHash: H256 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256]>;
- /**
- * See [`Pallet::execute`].
- **/
- execute: AugmentedSubmittable<(proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, Compact<u32>]>;
- /**
- * See [`Pallet::propose`].
- **/
- propose: AugmentedSubmittable<(threshold: Compact<u32> | AnyNumber | Uint8Array, proposal: Call | IMethod | string | Uint8Array, lengthBound: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Call, Compact<u32>]>;
- /**
- * See [`Pallet::set_members`].
- **/
- setMembers: AugmentedSubmittable<(newMembers: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[], prime: Option<AccountId32> | null | Uint8Array | AccountId32 | string, oldCount: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>, Option<AccountId32>, u32]>;
- /**
- * See [`Pallet::vote`].
- **/
- vote: AugmentedSubmittable<(proposal: H256 | string | Uint8Array, index: Compact<u32> | AnyNumber | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [H256, Compact<u32>, bool]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- technicalCommitteeMembership: {
- /**
- * See [`Pallet::add_member`].
- **/
- addMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::change_key`].
- **/
- changeKey: AugmentedSubmittable<(updated: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::clear_prime`].
- **/
- clearPrime: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::remove_member`].
- **/
- removeMember: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::reset_members`].
- **/
- resetMembers: AugmentedSubmittable<(members: Vec<AccountId32> | (AccountId32 | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<AccountId32>]>;
- /**
- * See [`Pallet::set_prime`].
- **/
- setPrime: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::swap_member`].
- **/
- swapMember: AugmentedSubmittable<(remove: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, add: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- testUtils: {
- /**
- * See `Pallet::batch_all`.
- **/
- batchAll: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
- /**
- * See `Pallet::enable`.
- **/
- enable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See `Pallet::inc_test_value`.
- **/
- incTestValue: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See `Pallet::just_take_fee`.
- **/
- justTakeFee: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See `Pallet::set_test_value`.
- **/
- setTestValue: AugmentedSubmittable<(value: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See `Pallet::set_test_value_and_rollback`.
- **/
- setTestValueAndRollback: AugmentedSubmittable<(value: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- timestamp: {
- /**
- * See [`Pallet::set`].
- **/
- set: AugmentedSubmittable<(now: Compact<u64> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u64>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- tokens: {
- /**
- * See [`Pallet::force_transfer`].
- **/
- forceTransfer: AugmentedSubmittable<(source: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, MultiAddress, PalletForeignAssetsAssetId, Compact<u128>]>;
- /**
- * See [`Pallet::set_balance`].
- **/
- setBalance: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, newFree: Compact<u128> | AnyNumber | Uint8Array, newReserved: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, Compact<u128>, Compact<u128>]>;
- /**
- * See [`Pallet::transfer`].
- **/
- transfer: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, Compact<u128>]>;
- /**
- * See [`Pallet::transfer_all`].
- **/
- transferAll: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, keepAlive: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, bool]>;
- /**
- * See [`Pallet::transfer_keep_alive`].
- **/
- transferKeepAlive: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: Compact<u128> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, PalletForeignAssetsAssetId, Compact<u128>]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- treasury: {
- /**
- * See [`Pallet::approve_proposal`].
- **/
- approveProposal: AugmentedSubmittable<(proposalId: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
- /**
- * See [`Pallet::propose_spend`].
- **/
- proposeSpend: AugmentedSubmittable<(value: Compact<u128> | AnyNumber | Uint8Array, beneficiary: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, MultiAddress]>;
- /**
- * See [`Pallet::reject_proposal`].
- **/
- rejectProposal: AugmentedSubmittable<(proposalId: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
- /**
- * See [`Pallet::remove_approval`].
- **/
- removeApproval: AugmentedSubmittable<(proposalId: Compact<u32> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>]>;
- /**
- * See [`Pallet::spend`].
- **/
- spend: AugmentedSubmittable<(amount: Compact<u128> | AnyNumber | Uint8Array, beneficiary: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u128>, MultiAddress]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- unique: {
- /**
- * See [`Pallet::add_collection_admin`].
- **/
- addCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newAdminId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * See [`Pallet::add_to_allow_list`].
- **/
- addToAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * See [`Pallet::approve`].
- **/
- approve: AugmentedSubmittable<(spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
- /**
- * See [`Pallet::approve_from`].
- **/
- approveFrom: AugmentedSubmittable<(from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, to: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
- /**
- * See [`Pallet::burn_from`].
- **/
- burnFrom: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32, u128]>;
- /**
- * See [`Pallet::burn_item`].
- **/
- burnItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
- /**
- * See [`Pallet::change_collection_owner`].
- **/
- changeCollectionOwner: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newOwner: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
- /**
- * See [`Pallet::confirm_sponsorship`].
- **/
- confirmSponsorship: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::create_collection`].
- **/
- createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;
- /**
- * See [`Pallet::create_collection_ex`].
- **/
- createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; limits?: any; permissions?: any; tokenPropertyPermissions?: any; properties?: any; adminList?: any; pendingSponsor?: any; flags?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
- /**
- * See [`Pallet::create_item`].
- **/
- createItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, data: UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCreateItemData]>;
- /**
- * See [`Pallet::create_multiple_items`].
- **/
- createMultipleItems: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemsData: Vec<UpDataStructsCreateItemData> | (UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, Vec<UpDataStructsCreateItemData>]>;
- /**
- * See [`Pallet::create_multiple_items_ex`].
- **/
- createMultipleItemsEx: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, data: UpDataStructsCreateItemExData | { NFT: any } | { Fungible: any } | { RefungibleMultipleItems: any } | { RefungibleMultipleOwners: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCreateItemExData]>;
- /**
- * See [`Pallet::delete_collection_properties`].
- **/
- deleteCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<Bytes>]>;
- /**
- * See [`Pallet::delete_token_properties`].
- **/
- deleteTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<Bytes>]>;
- /**
- * See [`Pallet::destroy_collection`].
- **/
- destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::force_repair_collection`].
- **/
- forceRepairCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::force_repair_item`].
- **/
- forceRepairItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
- /**
- * See [`Pallet::remove_collection_admin`].
- **/
- removeCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, accountId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * See [`Pallet::remove_collection_sponsor`].
- **/
- removeCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::remove_from_allow_list`].
- **/
- removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- /**
- * See [`Pallet::repartition`].
- **/
- repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
- /**
- * See [`Pallet::set_allowance_for_all`].
- **/
- setAllowanceForAll: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
- /**
- * See [`Pallet::set_collection_limits`].
- **/
- setCollectionLimits: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newLimit: UpDataStructsCollectionLimits | { accountTokenOwnershipLimit?: any; sponsoredDataSize?: any; sponsoredDataRateLimit?: any; tokenLimit?: any; sponsorTransferTimeout?: any; sponsorApproveTimeout?: any; ownerCanTransfer?: any; ownerCanDestroy?: any; transfersEnabled?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionLimits]>;
- /**
- * See [`Pallet::set_collection_permissions`].
- **/
- setCollectionPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newPermission: UpDataStructsCollectionPermissions | { access?: any; mintMode?: any; nesting?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionPermissions]>;
- /**
- * See [`Pallet::set_collection_properties`].
- **/
- setCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsProperty>]>;
- /**
- * See [`Pallet::set_collection_sponsor`].
- **/
- setCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newSponsor: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
- /**
- * See [`Pallet::set_token_properties`].
- **/
- setTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<UpDataStructsProperty>]>;
- /**
- * See [`Pallet::set_token_property_permissions`].
- **/
- setTokenPropertyPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyPermissions: Vec<UpDataStructsPropertyKeyPermission> | (UpDataStructsPropertyKeyPermission | { key?: any; permission?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsPropertyKeyPermission>]>;
- /**
- * See [`Pallet::set_transfers_enabled_flag`].
- **/
- setTransfersEnabledFlag: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, value: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
- /**
- * See [`Pallet::transfer`].
- **/
- transfer: AugmentedSubmittable<(recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
- /**
- * See [`Pallet::transfer_from`].
- **/
- transferFrom: AugmentedSubmittable<(from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- utility: {
- /**
- * See [`Pallet::as_derivative`].
- **/
- asDerivative: AugmentedSubmittable<(index: u16 | AnyNumber | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u16, Call]>;
- /**
- * See [`Pallet::batch`].
- **/
- batch: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
- /**
- * See [`Pallet::batch_all`].
- **/
- batchAll: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
- /**
- * See [`Pallet::dispatch_as`].
- **/
- dispatchAs: AugmentedSubmittable<(asOrigin: OpalRuntimeOriginCaller | { system: any } | { Void: any } | { Council: any } | { TechnicalCommittee: any } | { PolkadotXcm: any } | { CumulusXcm: any } | { Origins: any } | { Ethereum: any } | string | Uint8Array, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [OpalRuntimeOriginCaller, Call]>;
- /**
- * See [`Pallet::force_batch`].
- **/
- forceBatch: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
- /**
- * See [`Pallet::with_weight`].
- **/
- withWeight: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array, weight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, SpWeightsWeightV2Weight]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- vesting: {
- /**
- * See [`Pallet::claim`].
- **/
- claim: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::claim_for`].
- **/
- claimFor: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress]>;
- /**
- * See [`Pallet::update_vesting_schedules`].
- **/
- updateVestingSchedules: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, vestingSchedules: Vec<OrmlVestingVestingSchedule> | (OrmlVestingVestingSchedule | { start?: any; period?: any; periodCount?: any; perPeriod?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [MultiAddress, Vec<OrmlVestingVestingSchedule>]>;
- /**
- * See [`Pallet::vested_transfer`].
- **/
- vestedTransfer: AugmentedSubmittable<(dest: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, schedule: OrmlVestingVestingSchedule | { start?: any; period?: any; periodCount?: any; perPeriod?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, OrmlVestingVestingSchedule]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- xcmpQueue: {
- /**
- * See [`Pallet::resume_xcm_execution`].
- **/
- resumeXcmExecution: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::service_overweight`].
- **/
- serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u64, SpWeightsWeightV2Weight]>;
- /**
- * See [`Pallet::suspend_xcm_execution`].
- **/
- suspendXcmExecution: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
- /**
- * See [`Pallet::update_drop_threshold`].
- **/
- updateDropThreshold: AugmentedSubmittable<(updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::update_resume_threshold`].
- **/
- updateResumeThreshold: AugmentedSubmittable<(updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::update_suspend_threshold`].
- **/
- updateSuspendThreshold: AugmentedSubmittable<(updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
- /**
- * See [`Pallet::update_threshold_weight`].
- **/
- updateThresholdWeight: AugmentedSubmittable<(updated: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [SpWeightsWeightV2Weight]>;
- /**
- * See [`Pallet::update_weight_restrict_decay`].
- **/
- updateWeightRestrictDecay: AugmentedSubmittable<(updated: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [SpWeightsWeightV2Weight]>;
- /**
- * See [`Pallet::update_xcmp_max_individual_weight`].
- **/
- updateXcmpMaxIndividualWeight: AugmentedSubmittable<(updated: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [SpWeightsWeightV2Weight]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- xTokens: {
- /**
- * See [`Pallet::transfer`].
- **/
- transfer: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletForeignAssetsAssetId, u128, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::transfer_multiasset`].
- **/
- transferMultiasset: AugmentedSubmittable<(asset: StagingXcmVersionedMultiAsset | { V2: any } | { V3: any } | string | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::transfer_multiassets`].
- **/
- transferMultiassets: AugmentedSubmittable<(assets: StagingXcmVersionedMultiAssets | { V2: any } | { V3: any } | string | Uint8Array, feeItem: u32 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiAssets, u32, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::transfer_multiasset_with_fee`].
- **/
- transferMultiassetWithFee: AugmentedSubmittable<(asset: StagingXcmVersionedMultiAsset | { V2: any } | { V3: any } | string | Uint8Array, fee: StagingXcmVersionedMultiAsset | { V2: any } | { V3: any } | string | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::transfer_multicurrencies`].
- **/
- transferMulticurrencies: AugmentedSubmittable<(currencies: Vec<ITuple<[PalletForeignAssetsAssetId, u128]>> | ([PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, u128 | AnyNumber | Uint8Array])[], feeItem: u32 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<ITuple<[PalletForeignAssetsAssetId, u128]>>, u32, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
- /**
- * See [`Pallet::transfer_with_fee`].
- **/
- transferWithFee: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetId | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, fee: u128 | AnyNumber | Uint8Array, dest: StagingXcmVersionedMultiLocation | { V2: any } | { V3: any } | string | Uint8Array, destWeightLimit: StagingXcmV3WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletForeignAssetsAssetId, u128, u128, StagingXcmVersionedMultiLocation, StagingXcmV3WeightLimit]>;
- /**
- * Generic tx
- **/
- [key: string]: SubmittableExtrinsicFunction<ApiType>;
- };
- } // AugmentedSubmittables
-} // declare module
js-packages/types/src/augment-api.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-api.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
-/* eslint-disable */
-
-import './augment-api-consts.js';
-import './augment-api-errors.js';
-import './augment-api-events.js';
-import './augment-api-query.js';
-import './augment-api-tx.js';
-import './augment-api-rpc.js';
-import './augment-api-runtime.js';
js-packages/types/src/augment-types.tsdiffbeforeafterboth--- a/js-packages/types/src/augment-types.ts
+++ /dev/null
@@ -1,1232 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/types/types/registry';
-
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemCodeUpgradeAuthorization, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity, CumulusPalletParachainSystemUnincludedSegmentAncestor, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate, CumulusPalletParachainSystemUnincludedSegmentSegmentTracker, CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OpalRuntimeRuntimeCommonSessionKeys, OpalRuntimeRuntimeHoldReason, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesIdAmount, PalletBalancesReasons, PalletBalancesReserveData, PalletCollatorSelectionCall, PalletCollatorSelectionError, PalletCollatorSelectionEvent, PalletCollatorSelectionHoldReason, PalletCollectiveCall, PalletCollectiveError, PalletCollectiveEvent, PalletCollectiveRawOrigin, PalletCollectiveVotes, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletConfigurationEvent, PalletDemocracyCall, PalletDemocracyConviction, PalletDemocracyDelegations, PalletDemocracyError, PalletDemocracyEvent, PalletDemocracyMetadataOwner, PalletDemocracyReferendumInfo, PalletDemocracyReferendumStatus, PalletDemocracyTally, PalletDemocracyVoteAccountVote, PalletDemocracyVotePriorLock, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCodeMetadata, PalletEvmCoderSubstrateError, PalletEvmContractHelpersCall, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletGovOriginsOrigin, PalletIdentityBitFlags, PalletIdentityCall, PalletIdentityError, PalletIdentityEvent, PalletIdentityIdentityField, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletMembershipCall, PalletMembershipError, PalletMembershipEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletPreimageCall, PalletPreimageError, PalletPreimageEvent, PalletPreimageRequestStatus, PalletRankedCollectiveCall, PalletRankedCollectiveError, PalletRankedCollectiveEvent, PalletRankedCollectiveMemberRecord, PalletRankedCollectiveTally, PalletRankedCollectiveVoteRecord, PalletReferendaCall, PalletReferendaCurve, PalletReferendaDecidingStatus, PalletReferendaDeposit, PalletReferendaError, PalletReferendaEvent, PalletReferendaReferendumInfo, PalletReferendaReferendumStatus, PalletReferendaTrackInfo, PalletRefungibleError, PalletSchedulerCall, PalletSchedulerError, PalletSchedulerEvent, PalletSchedulerScheduled, PalletSessionCall, PalletSessionError, PalletSessionEvent, PalletStateTrieMigrationCall, PalletStateTrieMigrationError, PalletStateTrieMigrationEvent, PalletStateTrieMigrationMigrationCompute, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletStateTrieMigrationProgress, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUtilityCall, PalletUtilityError, PalletUtilityEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PalletXcmQueryStatus, PalletXcmRemoteLockedFungibleRecord, PalletXcmVersionMigrationStage, ParachainInfoCall, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat, PolkadotPrimitivesV5AbridgedHostConfiguration, PolkadotPrimitivesV5AbridgedHrmpChannel, PolkadotPrimitivesV5PersistedValidationData, PolkadotPrimitivesV5UpgradeGoAhead, PolkadotPrimitivesV5UpgradeRestriction, PolkadotPrimitivesVstagingAsyncBackingParams, SpArithmeticArithmeticError, SpConsensusAuraSr25519AppSr25519Public, SpCoreCryptoKeyTypeId, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Public, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, StagingXcmDoubleEncoded, StagingXcmV2BodyId, StagingXcmV2BodyPart, StagingXcmV2Instruction, StagingXcmV2Junction, StagingXcmV2MultiAsset, StagingXcmV2MultiLocation, StagingXcmV2MultiassetAssetId, StagingXcmV2MultiassetAssetInstance, StagingXcmV2MultiassetFungibility, StagingXcmV2MultiassetMultiAssetFilter, StagingXcmV2MultiassetMultiAssets, StagingXcmV2MultiassetWildFungibility, StagingXcmV2MultiassetWildMultiAsset, StagingXcmV2MultilocationJunctions, StagingXcmV2NetworkId, StagingXcmV2OriginKind, StagingXcmV2Response, StagingXcmV2TraitsError, StagingXcmV2WeightLimit, StagingXcmV2Xcm, StagingXcmV3Instruction, StagingXcmV3Junction, StagingXcmV3JunctionBodyId, StagingXcmV3JunctionBodyPart, StagingXcmV3JunctionNetworkId, StagingXcmV3Junctions, StagingXcmV3MaybeErrorCode, StagingXcmV3MultiAsset, StagingXcmV3MultiLocation, StagingXcmV3MultiassetAssetId, StagingXcmV3MultiassetAssetInstance, StagingXcmV3MultiassetFungibility, StagingXcmV3MultiassetMultiAssetFilter, StagingXcmV3MultiassetMultiAssets, StagingXcmV3MultiassetWildFungibility, StagingXcmV3MultiassetWildMultiAsset, StagingXcmV3PalletInfo, StagingXcmV3QueryResponseInfo, StagingXcmV3Response, StagingXcmV3TraitsError, StagingXcmV3TraitsOutcome, StagingXcmV3WeightLimit, StagingXcmV3Xcm, StagingXcmVersionedAssetId, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation, StagingXcmVersionedResponse, StagingXcmVersionedXcm, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission,
- UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue } from '@polkadot/types/lookup';
-import type { Data, StorageKey } from '@polkadot/types';
-import type { BitVec, Bool, Bytes, F32, F64, I128, I16, I256, I32, I64, I8, ISize, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, f32, f64, i128, i16, i256, i32, i64, i8, isize, 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';
-import type { BlockAttestations, IncludedBlocks, MoreAttestations } from '@polkadot/types/interfaces/attestations';
-import type { RawAuraPreDigest } from '@polkadot/types/interfaces/aura';
-import type { ExtrinsicOrHash, ExtrinsicStatus } from '@polkadot/types/interfaces/author';
-import type { UncleEntryItem } from '@polkadot/types/interfaces/authorship';
-import type { AllowedSlots, BabeAuthorityWeight, BabeBlockWeight, BabeEpochConfiguration, BabeEquivocationProof, BabeGenesisConfiguration, BabeGenesisConfigurationV1, BabeWeight, Epoch, EpochAuthorship, MaybeRandomness, MaybeVrf, NextConfigDescriptor, NextConfigDescriptorV1, OpaqueKeyOwnershipProof, Randomness, RawBabePreDigest, RawBabePreDigestCompat, RawBabePreDigestPrimary, RawBabePreDigestPrimaryTo159, RawBabePreDigestSecondaryPlain, RawBabePreDigestSecondaryTo159, RawBabePreDigestSecondaryVRF, RawBabePreDigestTo159, SlotNumber, VrfData, VrfOutput, VrfProof } from '@polkadot/types/interfaces/babe';
-import type { AccountData, BalanceLock, BalanceLockTo212, BalanceStatus, Reasons, ReserveData, ReserveIdentifier, VestingSchedule, WithdrawReasons } from '@polkadot/types/interfaces/balances';
-import type { BeefyAuthoritySet, BeefyCommitment, BeefyEquivocationProof, BeefyId, BeefyNextAuthoritySet, BeefyPayload, BeefyPayloadId, BeefySignedCommitment, BeefyVoteMessage, MmrRootHash, ValidatorSet, ValidatorSetId } from '@polkadot/types/interfaces/beefy';
-import type { BenchmarkBatch, BenchmarkConfig, BenchmarkList, BenchmarkMetadata, BenchmarkParameter, BenchmarkResult } from '@polkadot/types/interfaces/benchmark';
-import type { CheckInherentsResult, InherentData, InherentIdentifier } from '@polkadot/types/interfaces/blockbuilder';
-import type { BridgeMessageId, BridgedBlockHash, BridgedBlockNumber, BridgedHeader, CallOrigin, ChainId, DeliveredMessages, DispatchFeePayment, InboundLaneData, InboundRelayer, InitializationData, LaneId, MessageData, MessageKey, MessageNonce, MessagesDeliveryProofOf, MessagesProofOf, OperatingMode, OutboundLaneData, OutboundMessageFee, OutboundPayload, Parameter, RelayerId, UnrewardedRelayer, UnrewardedRelayersState } from '@polkadot/types/interfaces/bridges';
-import type { BlockHash } from '@polkadot/types/interfaces/chain';
-import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';
-import type { StatementKind } from '@polkadot/types/interfaces/claims';
-import type { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective';
-import type { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus';
-import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractExecResultU64, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractInstantiateResultU64, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts';
-import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractConstructorSpecV4, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEnvironmentV4, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMessageSpecV3, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractMetadataV4, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi';
-import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan';
-import type { CollationInfo, CollationInfoV1, ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus';
-import type { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy';
-import type { BlockStats } from '@polkadot/types/interfaces/dev';
-import type { ApprovalFlag, DefunctVoter, Renouncing, SetIndex, Vote, VoteIndex, VoteThreshold, VoterInfo } from '@polkadot/types/interfaces/elections';
-import type { CreatedBlock, ImportedAux } from '@polkadot/types/interfaces/engine';
-import type { BlockV0, BlockV1, BlockV2, EIP1559Transaction, EIP2930Transaction, EthAccessList, EthAccessListItem, EthAccount, EthAddress, EthBlock, EthBloom, EthCallRequest, EthFeeHistory, EthFilter, EthFilterAddress, EthFilterChanges, EthFilterTopic, EthFilterTopicEntry, EthFilterTopicInner, EthHeader, EthLog, EthReceipt, EthReceiptV0, EthReceiptV3, EthRichBlock, EthRichHeader, EthStorageProof, EthSubKind, EthSubParams, EthSubResult, EthSyncInfo, EthSyncStatus, EthTransaction, EthTransactionAction, EthTransactionCondition, EthTransactionRequest, EthTransactionSignature, EthTransactionStatus, EthWork, EthereumAccountId, EthereumAddress, EthereumLookupSource, EthereumSignature, LegacyTransaction, TransactionV0, TransactionV1, TransactionV2 } from '@polkadot/types/interfaces/eth';
-import type { EvmAccount, EvmCallInfo, EvmCallInfoV2, EvmCreateInfo, EvmCreateInfoV2, EvmLog, EvmVicinity, EvmWeightInfo, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed } from '@polkadot/types/interfaces/evm';
-import type { AnySignature, EcdsaSignature, Ed25519Signature, Era, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV4, ExtrinsicSignature, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV4, ImmortalEra, MortalEra, MultiSignature, Signature, SignerPayload, Sr25519Signature } from '@polkadot/types/interfaces/extrinsics';
-import type { FungiblesAccessError } from '@polkadot/types/interfaces/fungibles';
-import type { AssetOptions, Owner, PermissionLatest, PermissionVersions, PermissionsV1 } from '@polkadot/types/interfaces/genericAsset';
-import type { ActiveGilt, ActiveGiltsTotal, ActiveIndex, GiltBid } from '@polkadot/types/interfaces/gilt';
-import type { AuthorityIndex, AuthorityList, AuthoritySet, AuthoritySetChange, AuthoritySetChanges, AuthorityWeight, DelayKind, DelayKindBest, EncodedFinalityProofs, ForkTreePendingChange, ForkTreePendingChangeNode, GrandpaCommit, GrandpaEquivocation, GrandpaEquivocationProof, GrandpaEquivocationValue, GrandpaJustification, GrandpaPrecommit, GrandpaPrevote, GrandpaSignedPrecommit, JustificationNotification, KeyOwnerProof, NextAuthority, PendingChange, PendingPause, PendingResume, Precommits, Prevotes, ReportedRoundStates, RoundState, SetId, StoredPendingChange, StoredState } from '@polkadot/types/interfaces/grandpa';
-import type { IdentityFields, IdentityInfo, IdentityInfoAdditional, IdentityInfoTo198, IdentityJudgement, RegistrarIndex, RegistrarInfo, Registration, RegistrationJudgement, RegistrationTo198 } from '@polkadot/types/interfaces/identity';
-import type { AuthIndex, AuthoritySignature, Heartbeat, HeartbeatTo244, OpaqueMultiaddr, OpaqueNetworkState, OpaquePeerId } from '@polkadot/types/interfaces/imOnline';
-import type { CallIndex, LotteryConfig } from '@polkadot/types/interfaces/lottery';
-import type { CustomMetadata15, CustomValueMetadata15, ErrorMetadataLatest, ErrorMetadataV10, ErrorMetadataV11, ErrorMetadataV12, ErrorMetadataV13, ErrorMetadataV14, ErrorMetadataV9, EventMetadataLatest, EventMetadataV10, EventMetadataV11, EventMetadataV12, EventMetadataV13, EventMetadataV14, EventMetadataV9, ExtrinsicMetadataLatest, ExtrinsicMetadataV11, ExtrinsicMetadataV12, ExtrinsicMetadataV13, ExtrinsicMetadataV14, ExtrinsicMetadataV15, FunctionArgumentMetadataLatest, FunctionArgumentMetadataV10, FunctionArgumentMetadataV11, FunctionArgumentMetadataV12, FunctionArgumentMetadataV13, FunctionArgumentMetadataV14, FunctionArgumentMetadataV9, FunctionMetadataLatest, FunctionMetadataV10, FunctionMetadataV11, FunctionMetadataV12, FunctionMetadataV13, FunctionMetadataV14, FunctionMetadataV9, MetadataAll, MetadataLatest, MetadataV10, MetadataV11, MetadataV12, MetadataV13, MetadataV14, MetadataV15, MetadataV9, ModuleConstantMetadataV10, ModuleConstantMetadataV11, ModuleConstantMetadataV12, ModuleConstantMetadataV13, ModuleConstantMetadataV9, ModuleMetadataV10, ModuleMetadataV11, ModuleMetadataV12, ModuleMetadataV13, ModuleMetadataV9, OpaqueMetadata, OuterEnums15, PalletCallMetadataLatest, PalletCallMetadataV14, PalletConstantMetadataLatest, PalletConstantMetadataV14, PalletErrorMetadataLatest, PalletErrorMetadataV14, PalletEventMetadataLatest, PalletEventMetadataV14, PalletMetadataLatest, PalletMetadataV14, PalletMetadataV15, PalletStorageMetadataLatest, PalletStorageMetadataV14, PortableType, PortableTypeV14, RuntimeApiMetadataLatest, RuntimeApiMetadataV15, RuntimeApiMethodMetadataV15, RuntimeApiMethodParamMetadataV15, SignedExtensionMetadataLatest, SignedExtensionMetadataV14, StorageEntryMetadataLatest, StorageEntryMetadataV10, StorageEntryMetadataV11, StorageEntryMetadataV12, StorageEntryMetadataV13, StorageEntryMetadataV14, StorageEntryMetadataV9, StorageEntryModifierLatest, StorageEntryModifierV10, StorageEntryModifierV11, StorageEntryModifierV12, StorageEntryModifierV13, StorageEntryModifierV14, StorageEntryModifierV9, StorageEntryTypeLatest, StorageEntryTypeV10, StorageEntryTypeV11, StorageEntryTypeV12, StorageEntryTypeV13, StorageEntryTypeV14, StorageEntryTypeV9, StorageHasher, StorageHasherV10, StorageHasherV11, StorageHasherV12, StorageHasherV13, StorageHasherV14, StorageHasherV9, StorageMetadataV10, StorageMetadataV11, StorageMetadataV12, StorageMetadataV13, StorageMetadataV9 } from '@polkadot/types/interfaces/metadata';
-import type { MmrBatchProof, MmrEncodableOpaqueLeaf, MmrError, MmrHash, MmrLeafBatchProof, MmrLeafIndex, MmrLeafProof, MmrNodeIndex, MmrProof } from '@polkadot/types/interfaces/mmr';
-import type { NftCollectionId, NftItemId } from '@polkadot/types/interfaces/nfts';
-import type { NpApiError, NpPoolId } from '@polkadot/types/interfaces/nompools';
-import type { StorageKind } from '@polkadot/types/interfaces/offchain';
-import type { DeferredOffenceOf, Kind, OffenceDetails, Offender, OpaqueTimeSlot, ReportIdOf, Reporter } from '@polkadot/types/interfaces/offences';
-import type { AbridgedCandidateReceipt, AbridgedHostConfiguration, AbridgedHrmpChannel, AssignmentId, AssignmentKind, AttestedCandidate, AuctionIndex, AuthorityDiscoveryId, AvailabilityBitfield, AvailabilityBitfieldRecord, BackedCandidate, Bidder, BufferedSessionChange, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateInfo, CandidatePendingAvailability, CandidateReceipt, CollatorId, CollatorSignature, CommittedCandidateReceipt, CoreAssignment, CoreIndex, CoreOccupied, CoreState, DisputeLocation, DisputeProof, DisputeResult, DisputeState, DisputeStatement, DisputeStatementSet, DisputesTimeSlot, DoubleVoteReport, DownwardMessage, ExecutorParam, ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GlobalValidationData, GlobalValidationSchedule, GroupIndex, GroupRotationInfo, HeadData, HostConfiguration, HrmpChannel, HrmpChannelId, HrmpOpenChannelRequest, InboundDownwardMessage, InboundHrmpMessage, InboundHrmpMessages, IncomingParachain, IncomingParachainDeploy, IncomingParachainFixed, InvalidDisputeStatementKind, LeasePeriod, LeasePeriodOf, LocalValidationData, MessageIngestionType, MessageQueueChain, MessagingStateSnapshot, MessagingStateSnapshotEgressEntry, MultiDisputeStatementSet, NewBidder, OccupiedCore, OccupiedCoreAssumption, OldV1SessionInfo, OutboundHrmpMessage, ParaGenesisArgs, ParaId, ParaInfo, ParaLifecycle, ParaPastCodeMeta, ParaScheduling, ParaValidatorIndex, ParachainDispatchOrigin, ParachainInherentData, ParachainProposal, ParachainsInherentData, ParathreadClaim, ParathreadClaimQueue, ParathreadEntry, PendingSlashes, PersistedValidationData, PvfCheckStatement, PvfExecTimeoutKind, PvfPrepTimeoutKind, QueuedParathread, RegisteredParachainInfo, RelayBlockNumber, RelayChainBlockNumber, RelayChainHash, RelayHash, Remark, ReplacementTimes, Retriable, ScheduledCore, Scheduling, ScrapedOnChainVotes, ServiceQuality, SessionInfo, SessionInfoValidatorGroup, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, SlashingOffenceKind, SlotRange, SlotRange10, Statement, SubId, SystemInherentData, TransientValidationData, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidationData, ValidationDataType, ValidationFunctionParams, ValidatorSignature, ValidityAttestation, VecInboundHrmpMessage, WinnersData, WinnersData10, WinnersDataTuple, WinnersDataTuple10, WinningData, WinningData10, WinningDataEntry } from '@polkadot/types/interfaces/parachains';
-import type { FeeDetails, InclusionFee, RuntimeDispatchInfo, RuntimeDispatchInfoV1, RuntimeDispatchInfoV2 } from '@polkadot/types/interfaces/payment';
-import type { Approvals } from '@polkadot/types/interfaces/poll';
-import type { ProxyAnnouncement, ProxyDefinition, ProxyType } from '@polkadot/types/interfaces/proxy';
-import type { AccountStatus, AccountValidity } from '@polkadot/types/interfaces/purchase';
-import type { ActiveRecovery, RecoveryConfig } from '@polkadot/types/interfaces/recovery';
-import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
-import type { AccountId, AccountId20, AccountId32, AccountId33, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, BlockNumberFor, BlockNumberOf, Call, CallHash, CallHashOf, ChangesTrieConfiguration, ChangesTrieSignal, CodecHash, Consensus, ConsensusEngineId, CrateVersion, Digest, DigestItem, EncodedJustification, ExtrinsicsWeight, Fixed128, Fixed64, FixedI128, FixedI64, FixedU128, FixedU64, H1024, H128, H160, H2048, H256, H32, H512, H64, Hash, Header, HeaderPartial, I32F32, Index, IndicesLookupSource, Justification, Justifications, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, ModuleId, Moment, MultiAddress, MultiSigner, OpaqueCall, Origin, OriginCaller, PalletId, PalletVersion, PalletsOrigin, Pays, PerU16, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Releases, RuntimeCall, RuntimeDbWeight, RuntimeEvent, Seal, SealV0, SignedBlock, SignedBlockWithJustification, SignedBlockWithJustifications, Slot, SlotDuration, StorageData, StorageInfo, StorageProof, TransactionInfo, TransactionLongevity, TransactionPriority, TransactionStorageProof, TransactionTag, U32F32, ValidatorId, ValidatorIdOf, Weight, WeightMultiplier, WeightV0, WeightV1, WeightV2 } from '@polkadot/types/interfaces/runtime';
-import type { Si0Field, Si0LookupTypeId, Si0Path, Si0Type, Si0TypeDef, Si0TypeDefArray, Si0TypeDefBitSequence, Si0TypeDefCompact, Si0TypeDefComposite, Si0TypeDefPhantom, Si0TypeDefPrimitive, Si0TypeDefSequence, Si0TypeDefTuple, Si0TypeDefVariant, Si0TypeParameter, Si0Variant, Si1Field, Si1LookupTypeId, Si1Path, Si1Type, Si1TypeDef, Si1TypeDefArray, Si1TypeDefBitSequence, Si1TypeDefCompact, Si1TypeDefComposite, Si1TypeDefPrimitive, Si1TypeDefSequence, Si1TypeDefTuple, Si1TypeDefVariant, Si1TypeParameter, Si1Variant, SiField, SiLookupTypeId, SiPath, SiType, SiTypeDef, SiTypeDefArray, SiTypeDefBitSequence, SiTypeDefCompact, SiTypeDefComposite, SiTypeDefPrimitive, SiTypeDefSequence, SiTypeDefTuple, SiTypeDefVariant, SiTypeParameter, SiVariant } from '@polkadot/types/interfaces/scaleInfo';
-import type { Period, Priority, SchedulePeriod, SchedulePriority, Scheduled, ScheduledTo254, TaskAddress } from '@polkadot/types/interfaces/scheduler';
-import type { BeefyKey, FullIdentification, IdentificationTuple, Keys, MembershipProof, SessionIndex, SessionKeys1, SessionKeys10, SessionKeys10B, SessionKeys2, SessionKeys3, SessionKeys4, SessionKeys5, SessionKeys6, SessionKeys6B, SessionKeys7, SessionKeys7B, SessionKeys8, SessionKeys8B, SessionKeys9, SessionKeys9B, ValidatorCount } from '@polkadot/types/interfaces/session';
-import type { Bid, BidKind, SocietyJudgement, SocietyVote, StrikeCount, VouchingStatus } from '@polkadot/types/interfaces/society';
-import type { ActiveEraInfo, CompactAssignments, CompactAssignmentsTo257, CompactAssignmentsTo265, CompactAssignmentsWith16, CompactAssignmentsWith24, CompactScore, CompactScoreCompact, ElectionCompute, ElectionPhase, ElectionResult, ElectionScore, ElectionSize, ElectionStatus, EraIndex, EraPoints, EraRewardPoints, EraRewards, Exposure, ExtendedBalance, Forcing, IndividualExposure, KeyType, MomentOf, Nominations, NominatorIndex, NominatorIndexCompact, OffchainAccuracy, OffchainAccuracyCompact, PhragmenScore, Points, RawSolution, RawSolutionTo265, RawSolutionWith16, RawSolutionWith24, ReadySolution, RewardDestination, RewardPoint, RoundSnapshot, SeatHolder, SignedSubmission, SignedSubmissionOf, SignedSubmissionTo276, SlashJournalEntry, SlashingSpans, SlashingSpansTo204, SolutionOrSnapshotSize, SolutionSupport, SolutionSupports, SpanIndex, SpanRecord, StakingLedger, StakingLedgerTo223, StakingLedgerTo240, SubmissionIndicesOf, Supports, UnappliedSlash, UnappliedSlashOther, UnlockChunk, ValidatorIndex, ValidatorIndexCompact, ValidatorPrefs, ValidatorPrefsTo145, ValidatorPrefsTo196, ValidatorPrefsWithBlocked, ValidatorPrefsWithCommission, VoteWeight, Voter } from '@polkadot/types/interfaces/staking';
-import type { ApiId, BlockTrace, BlockTraceEvent, BlockTraceEventData, BlockTraceSpan, KeyValueOption, MigrationStatusResult, ReadProof, RuntimeVersion, RuntimeVersionApi, RuntimeVersionPartial, RuntimeVersionPre3, RuntimeVersionPre4, SpecVersion, StorageChangeSet, TraceBlockResponse, TraceError } from '@polkadot/types/interfaces/state';
-import type { WeightToFeeCoefficient } from '@polkadot/types/interfaces/support';
-import type { AccountInfo, AccountInfoWithDualRefCount, AccountInfoWithProviders, AccountInfoWithRefCount, AccountInfoWithRefCountU8, AccountInfoWithTripleRefCount, ApplyExtrinsicResult, ApplyExtrinsicResultPre6, ArithmeticError, BlockLength, BlockWeights, ChainProperties, ChainType, ConsumedWeight, DigestOf, DispatchClass, DispatchError, DispatchErrorModule, DispatchErrorModulePre6, DispatchErrorModuleU8, DispatchErrorModuleU8a, DispatchErrorPre6, DispatchErrorPre6First, DispatchErrorTo198, DispatchInfo, DispatchInfoTo190, DispatchInfoTo244, DispatchOutcome, DispatchOutcomePre6, DispatchResult, DispatchResultOf, DispatchResultTo198, Event, EventId, EventIndex, EventRecord, Health, InvalidTransaction, Key, LastRuntimeUpgradeInfo, NetworkState, NetworkStatePeerset, NetworkStatePeersetInfo, NodeRole, NotConnectedPeer, Peer, PeerEndpoint, PeerEndpointAddr, PeerInfo, PeerPing, PerDispatchClassU32, PerDispatchClassWeight, PerDispatchClassWeightsPerClass, Phase, RawOrigin, RefCount, RefCountTo259, SyncState, SystemOrigin, TokenError, TransactionValidityError, TransactionalError, UnknownTransaction, WeightPerClass } from '@polkadot/types/interfaces/system';
-import type { Bounty, BountyIndex, BountyStatus, BountyStatusActive, BountyStatusCuratorProposed, BountyStatusPendingPayout, OpenTip, OpenTipFinderTo225, OpenTipTip, OpenTipTo225, TreasuryProposal } from '@polkadot/types/interfaces/treasury';
-import type { Multiplier } from '@polkadot/types/interfaces/txpayment';
-import type { TransactionSource, TransactionValidity, ValidTransaction } from '@polkadot/types/interfaces/txqueue';
-import type { ClassDetails, ClassId, ClassMetadata, DepositBalance, DepositBalanceOf, DestroyWitness, InstanceDetails, InstanceId, InstanceMetadata } from '@polkadot/types/interfaces/uniques';
-import type { Multisig, Timepoint } from '@polkadot/types/interfaces/utility';
-import type { VestingInfo } from '@polkadot/types/interfaces/vesting';
-import type { AssetInstance, AssetInstanceV0, AssetInstanceV1, AssetInstanceV2, BodyId, BodyPart, DoubleEncodedCall, Fungibility, FungibilityV0, FungibilityV1, FungibilityV2, InboundStatus, InstructionV2, InteriorMultiLocation, Junction, JunctionV0, JunctionV1, JunctionV2, Junctions, JunctionsV1, JunctionsV2, MultiAsset, MultiAssetFilter, MultiAssetFilterV1, MultiAssetFilterV2, MultiAssetV0, MultiAssetV1, MultiAssetV2, MultiAssets, MultiAssetsV1, MultiAssetsV2, MultiLocation, MultiLocationV0, MultiLocationV1, MultiLocationV2, NetworkId, OriginKindV0, OriginKindV1, OriginKindV2, OutboundStatus, Outcome, QueryId, QueryStatus, QueueConfigData, Response, ResponseV0, ResponseV1, ResponseV2, ResponseV2Error, ResponseV2Result, VersionMigrationStage, VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, VersionedResponse, VersionedXcm, WeightLimitV2, WildFungibility, WildFungibilityV0, WildFungibilityV1, WildFungibilityV2, WildMultiAsset, WildMultiAssetV1, WildMultiAssetV2, Xcm, XcmAssetId, XcmError, XcmErrorV0, XcmErrorV1, XcmErrorV2, XcmOrder, XcmOrderV0, XcmOrderV1, XcmOrderV2, XcmOrigin, XcmOriginKind, XcmV0, XcmV1, XcmV2, XcmVersion, XcmpMessageFormat } from '@polkadot/types/interfaces/xcm';
-
-declare module '@polkadot/types/types/registry' {
- interface InterfaceTypes {
- AbridgedCandidateReceipt: AbridgedCandidateReceipt;
- AbridgedHostConfiguration: AbridgedHostConfiguration;
- AbridgedHrmpChannel: AbridgedHrmpChannel;
- AccountData: AccountData;
- AccountId: AccountId;
- AccountId20: AccountId20;
- AccountId32: AccountId32;
- AccountId33: AccountId33;
- AccountIdOf: AccountIdOf;
- AccountIndex: AccountIndex;
- AccountInfo: AccountInfo;
- AccountInfoWithDualRefCount: AccountInfoWithDualRefCount;
- AccountInfoWithProviders: AccountInfoWithProviders;
- AccountInfoWithRefCount: AccountInfoWithRefCount;
- AccountInfoWithRefCountU8: AccountInfoWithRefCountU8;
- AccountInfoWithTripleRefCount: AccountInfoWithTripleRefCount;
- AccountStatus: AccountStatus;
- AccountValidity: AccountValidity;
- AccountVote: AccountVote;
- AccountVoteSplit: AccountVoteSplit;
- AccountVoteStandard: AccountVoteStandard;
- ActiveEraInfo: ActiveEraInfo;
- ActiveGilt: ActiveGilt;
- ActiveGiltsTotal: ActiveGiltsTotal;
- ActiveIndex: ActiveIndex;
- ActiveRecovery: ActiveRecovery;
- Address: Address;
- AliveContractInfo: AliveContractInfo;
- AllowedSlots: AllowedSlots;
- AnySignature: AnySignature;
- ApiId: ApiId;
- ApplyExtrinsicResult: ApplyExtrinsicResult;
- ApplyExtrinsicResultPre6: ApplyExtrinsicResultPre6;
- ApprovalFlag: ApprovalFlag;
- Approvals: Approvals;
- ArithmeticError: ArithmeticError;
- AssetApproval: AssetApproval;
- AssetApprovalKey: AssetApprovalKey;
- AssetBalance: AssetBalance;
- AssetDestroyWitness: AssetDestroyWitness;
- AssetDetails: AssetDetails;
- AssetId: AssetId;
- AssetInstance: AssetInstance;
- AssetInstanceV0: AssetInstanceV0;
- AssetInstanceV1: AssetInstanceV1;
- AssetInstanceV2: AssetInstanceV2;
- AssetMetadata: AssetMetadata;
- AssetOptions: AssetOptions;
- AssignmentId: AssignmentId;
- AssignmentKind: AssignmentKind;
- AttestedCandidate: AttestedCandidate;
- AuctionIndex: AuctionIndex;
- AuthIndex: AuthIndex;
- AuthorityDiscoveryId: AuthorityDiscoveryId;
- AuthorityId: AuthorityId;
- AuthorityIndex: AuthorityIndex;
- AuthorityList: AuthorityList;
- AuthoritySet: AuthoritySet;
- AuthoritySetChange: AuthoritySetChange;
- AuthoritySetChanges: AuthoritySetChanges;
- AuthoritySignature: AuthoritySignature;
- AuthorityWeight: AuthorityWeight;
- AvailabilityBitfield: AvailabilityBitfield;
- AvailabilityBitfieldRecord: AvailabilityBitfieldRecord;
- BabeAuthorityWeight: BabeAuthorityWeight;
- BabeBlockWeight: BabeBlockWeight;
- BabeEpochConfiguration: BabeEpochConfiguration;
- BabeEquivocationProof: BabeEquivocationProof;
- BabeGenesisConfiguration: BabeGenesisConfiguration;
- BabeGenesisConfigurationV1: BabeGenesisConfigurationV1;
- BabeWeight: BabeWeight;
- BackedCandidate: BackedCandidate;
- Balance: Balance;
- BalanceLock: BalanceLock;
- BalanceLockTo212: BalanceLockTo212;
- BalanceOf: BalanceOf;
- BalanceStatus: BalanceStatus;
- BeefyAuthoritySet: BeefyAuthoritySet;
- BeefyCommitment: BeefyCommitment;
- BeefyEquivocationProof: BeefyEquivocationProof;
- BeefyId: BeefyId;
- BeefyKey: BeefyKey;
- BeefyNextAuthoritySet: BeefyNextAuthoritySet;
- BeefyPayload: BeefyPayload;
- BeefyPayloadId: BeefyPayloadId;
- BeefySignedCommitment: BeefySignedCommitment;
- BeefyVoteMessage: BeefyVoteMessage;
- BenchmarkBatch: BenchmarkBatch;
- BenchmarkConfig: BenchmarkConfig;
- BenchmarkList: BenchmarkList;
- BenchmarkMetadata: BenchmarkMetadata;
- BenchmarkParameter: BenchmarkParameter;
- BenchmarkResult: BenchmarkResult;
- Bid: Bid;
- Bidder: Bidder;
- BidKind: BidKind;
- BitVec: BitVec;
- Block: Block;
- BlockAttestations: BlockAttestations;
- BlockHash: BlockHash;
- BlockLength: BlockLength;
- BlockNumber: BlockNumber;
- BlockNumberFor: BlockNumberFor;
- BlockNumberOf: BlockNumberOf;
- BlockStats: BlockStats;
- BlockTrace: BlockTrace;
- BlockTraceEvent: BlockTraceEvent;
- BlockTraceEventData: BlockTraceEventData;
- BlockTraceSpan: BlockTraceSpan;
- BlockV0: BlockV0;
- BlockV1: BlockV1;
- BlockV2: BlockV2;
- BlockWeights: BlockWeights;
- BodyId: BodyId;
- BodyPart: BodyPart;
- bool: bool;
- Bool: Bool;
- Bounty: Bounty;
- BountyIndex: BountyIndex;
- BountyStatus: BountyStatus;
- BountyStatusActive: BountyStatusActive;
- BountyStatusCuratorProposed: BountyStatusCuratorProposed;
- BountyStatusPendingPayout: BountyStatusPendingPayout;
- BridgedBlockHash: BridgedBlockHash;
- BridgedBlockNumber: BridgedBlockNumber;
- BridgedHeader: BridgedHeader;
- BridgeMessageId: BridgeMessageId;
- BufferedSessionChange: BufferedSessionChange;
- Bytes: Bytes;
- Call: Call;
- CallHash: CallHash;
- CallHashOf: CallHashOf;
- CallIndex: CallIndex;
- CallOrigin: CallOrigin;
- CandidateCommitments: CandidateCommitments;
- CandidateDescriptor: CandidateDescriptor;
- CandidateEvent: CandidateEvent;
- CandidateHash: CandidateHash;
- CandidateInfo: CandidateInfo;
- CandidatePendingAvailability: CandidatePendingAvailability;
- CandidateReceipt: CandidateReceipt;
- ChainId: ChainId;
- ChainProperties: ChainProperties;
- ChainType: ChainType;
- ChangesTrieConfiguration: ChangesTrieConfiguration;
- ChangesTrieSignal: ChangesTrieSignal;
- CheckInherentsResult: CheckInherentsResult;
- ClassDetails: ClassDetails;
- ClassId: ClassId;
- ClassMetadata: ClassMetadata;
- CodecHash: CodecHash;
- CodeHash: CodeHash;
- CodeSource: CodeSource;
- CodeUploadRequest: CodeUploadRequest;
- CodeUploadResult: CodeUploadResult;
- CodeUploadResultValue: CodeUploadResultValue;
- CollationInfo: CollationInfo;
- CollationInfoV1: CollationInfoV1;
- CollatorId: CollatorId;
- CollatorSignature: CollatorSignature;
- CollectiveOrigin: CollectiveOrigin;
- CommittedCandidateReceipt: CommittedCandidateReceipt;
- CompactAssignments: CompactAssignments;
- CompactAssignmentsTo257: CompactAssignmentsTo257;
- CompactAssignmentsTo265: CompactAssignmentsTo265;
- CompactAssignmentsWith16: CompactAssignmentsWith16;
- CompactAssignmentsWith24: CompactAssignmentsWith24;
- CompactScore: CompactScore;
- CompactScoreCompact: CompactScoreCompact;
- ConfigData: ConfigData;
- Consensus: Consensus;
- ConsensusEngineId: ConsensusEngineId;
- ConsumedWeight: ConsumedWeight;
- ContractCallFlags: ContractCallFlags;
- ContractCallRequest: ContractCallRequest;
- ContractConstructorSpecLatest: ContractConstructorSpecLatest;
- ContractConstructorSpecV0: ContractConstructorSpecV0;
- ContractConstructorSpecV1: ContractConstructorSpecV1;
- ContractConstructorSpecV2: ContractConstructorSpecV2;
- ContractConstructorSpecV3: ContractConstructorSpecV3;
- ContractConstructorSpecV4: ContractConstructorSpecV4;
- ContractContractSpecV0: ContractContractSpecV0;
- ContractContractSpecV1: ContractContractSpecV1;
- ContractContractSpecV2: ContractContractSpecV2;
- ContractContractSpecV3: ContractContractSpecV3;
- ContractContractSpecV4: ContractContractSpecV4;
- ContractCryptoHasher: ContractCryptoHasher;
- ContractDiscriminant: ContractDiscriminant;
- ContractDisplayName: ContractDisplayName;
- ContractEnvironmentV4: ContractEnvironmentV4;
- ContractEventParamSpecLatest: ContractEventParamSpecLatest;
- ContractEventParamSpecV0: ContractEventParamSpecV0;
- ContractEventParamSpecV2: ContractEventParamSpecV2;
- ContractEventSpecLatest: ContractEventSpecLatest;
- ContractEventSpecV0: ContractEventSpecV0;
- ContractEventSpecV1: ContractEventSpecV1;
- ContractEventSpecV2: ContractEventSpecV2;
- ContractExecResult: ContractExecResult;
- ContractExecResultOk: ContractExecResultOk;
- ContractExecResultResult: ContractExecResultResult;
- ContractExecResultSuccessTo255: ContractExecResultSuccessTo255;
- ContractExecResultSuccessTo260: ContractExecResultSuccessTo260;
- ContractExecResultTo255: ContractExecResultTo255;
- ContractExecResultTo260: ContractExecResultTo260;
- ContractExecResultTo267: ContractExecResultTo267;
- ContractExecResultU64: ContractExecResultU64;
- ContractInfo: ContractInfo;
- ContractInstantiateResult: ContractInstantiateResult;
- ContractInstantiateResultTo267: ContractInstantiateResultTo267;
- ContractInstantiateResultTo299: ContractInstantiateResultTo299;
- ContractInstantiateResultU64: ContractInstantiateResultU64;
- ContractLayoutArray: ContractLayoutArray;
- ContractLayoutCell: ContractLayoutCell;
- ContractLayoutEnum: ContractLayoutEnum;
- ContractLayoutHash: ContractLayoutHash;
- ContractLayoutHashingStrategy: ContractLayoutHashingStrategy;
- ContractLayoutKey: ContractLayoutKey;
- ContractLayoutStruct: ContractLayoutStruct;
- ContractLayoutStructField: ContractLayoutStructField;
- ContractMessageParamSpecLatest: ContractMessageParamSpecLatest;
- ContractMessageParamSpecV0: ContractMessageParamSpecV0;
- ContractMessageParamSpecV2: ContractMessageParamSpecV2;
- ContractMessageSpecLatest: ContractMessageSpecLatest;
- ContractMessageSpecV0: ContractMessageSpecV0;
- ContractMessageSpecV1: ContractMessageSpecV1;
- ContractMessageSpecV2: ContractMessageSpecV2;
- ContractMessageSpecV3: ContractMessageSpecV3;
- ContractMetadata: ContractMetadata;
- ContractMetadataLatest: ContractMetadataLatest;
- ContractMetadataV0: ContractMetadataV0;
- ContractMetadataV1: ContractMetadataV1;
- ContractMetadataV2: ContractMetadataV2;
- ContractMetadataV3: ContractMetadataV3;
- ContractMetadataV4: ContractMetadataV4;
- ContractProject: ContractProject;
- ContractProjectContract: ContractProjectContract;
- ContractProjectInfo: ContractProjectInfo;
- ContractProjectSource: ContractProjectSource;
- ContractProjectV0: ContractProjectV0;
- ContractReturnFlags: ContractReturnFlags;
- ContractSelector: ContractSelector;
- ContractStorageKey: ContractStorageKey;
- ContractStorageLayout: ContractStorageLayout;
- ContractTypeSpec: ContractTypeSpec;
- Conviction: Conviction;
- CoreAssignment: CoreAssignment;
- CoreIndex: CoreIndex;
- CoreOccupied: CoreOccupied;
- CoreState: CoreState;
- CrateVersion: CrateVersion;
- CreatedBlock: CreatedBlock;
- CustomMetadata15: CustomMetadata15;
- CustomValueMetadata15: CustomValueMetadata15;
- Data: Data;
- DeferredOffenceOf: DeferredOffenceOf;
- DefunctVoter: DefunctVoter;
- DelayKind: DelayKind;
- DelayKindBest: DelayKindBest;
- Delegations: Delegations;
- DeletedContract: DeletedContract;
- DeliveredMessages: DeliveredMessages;
- DepositBalance: DepositBalance;
- DepositBalanceOf: DepositBalanceOf;
- DestroyWitness: DestroyWitness;
- Digest: Digest;
- DigestItem: DigestItem;
- DigestOf: DigestOf;
- DispatchClass: DispatchClass;
- DispatchError: DispatchError;
- DispatchErrorModule: DispatchErrorModule;
- DispatchErrorModulePre6: DispatchErrorModulePre6;
- DispatchErrorModuleU8: DispatchErrorModuleU8;
- DispatchErrorModuleU8a: DispatchErrorModuleU8a;
- DispatchErrorPre6: DispatchErrorPre6;
- DispatchErrorPre6First: DispatchErrorPre6First;
- DispatchErrorTo198: DispatchErrorTo198;
- DispatchFeePayment: DispatchFeePayment;
- DispatchInfo: DispatchInfo;
- DispatchInfoTo190: DispatchInfoTo190;
- DispatchInfoTo244: DispatchInfoTo244;
- DispatchOutcome: DispatchOutcome;
- DispatchOutcomePre6: DispatchOutcomePre6;
- DispatchResult: DispatchResult;
- DispatchResultOf: DispatchResultOf;
- DispatchResultTo198: DispatchResultTo198;
- DisputeLocation: DisputeLocation;
- DisputeProof: DisputeProof;
- DisputeResult: DisputeResult;
- DisputeState: DisputeState;
- DisputeStatement: DisputeStatement;
- DisputeStatementSet: DisputeStatementSet;
- DisputesTimeSlot: DisputesTimeSlot;
- DoubleEncodedCall: DoubleEncodedCall;
- DoubleVoteReport: DoubleVoteReport;
- DownwardMessage: DownwardMessage;
- EcdsaSignature: EcdsaSignature;
- Ed25519Signature: Ed25519Signature;
- EIP1559Transaction: EIP1559Transaction;
- EIP2930Transaction: EIP2930Transaction;
- ElectionCompute: ElectionCompute;
- ElectionPhase: ElectionPhase;
- ElectionResult: ElectionResult;
- ElectionScore: ElectionScore;
- ElectionSize: ElectionSize;
- ElectionStatus: ElectionStatus;
- EncodedFinalityProofs: EncodedFinalityProofs;
- EncodedJustification: EncodedJustification;
- Epoch: Epoch;
- EpochAuthorship: EpochAuthorship;
- Era: Era;
- EraIndex: EraIndex;
- EraPoints: EraPoints;
- EraRewardPoints: EraRewardPoints;
- EraRewards: EraRewards;
- ErrorMetadataLatest: ErrorMetadataLatest;
- ErrorMetadataV10: ErrorMetadataV10;
- ErrorMetadataV11: ErrorMetadataV11;
- ErrorMetadataV12: ErrorMetadataV12;
- ErrorMetadataV13: ErrorMetadataV13;
- ErrorMetadataV14: ErrorMetadataV14;
- ErrorMetadataV9: ErrorMetadataV9;
- EthAccessList: EthAccessList;
- EthAccessListItem: EthAccessListItem;
- EthAccount: EthAccount;
- EthAddress: EthAddress;
- EthBlock: EthBlock;
- EthBloom: EthBloom;
- EthCallRequest: EthCallRequest;
- EthereumAccountId: EthereumAccountId;
- EthereumAddress: EthereumAddress;
- EthereumLookupSource: EthereumLookupSource;
- EthereumSignature: EthereumSignature;
- EthFeeHistory: EthFeeHistory;
- EthFilter: EthFilter;
- EthFilterAddress: EthFilterAddress;
- EthFilterChanges: EthFilterChanges;
- EthFilterTopic: EthFilterTopic;
- EthFilterTopicEntry: EthFilterTopicEntry;
- EthFilterTopicInner: EthFilterTopicInner;
- EthHeader: EthHeader;
- EthLog: EthLog;
- EthReceipt: EthReceipt;
- EthReceiptV0: EthReceiptV0;
- EthReceiptV3: EthReceiptV3;
- EthRichBlock: EthRichBlock;
- EthRichHeader: EthRichHeader;
- EthStorageProof: EthStorageProof;
- EthSubKind: EthSubKind;
- EthSubParams: EthSubParams;
- EthSubResult: EthSubResult;
- EthSyncInfo: EthSyncInfo;
- EthSyncStatus: EthSyncStatus;
- EthTransaction: EthTransaction;
- EthTransactionAction: EthTransactionAction;
- EthTransactionCondition: EthTransactionCondition;
- EthTransactionRequest: EthTransactionRequest;
- EthTransactionSignature: EthTransactionSignature;
- EthTransactionStatus: EthTransactionStatus;
- EthWork: EthWork;
- Event: Event;
- EventId: EventId;
- EventIndex: EventIndex;
- EventMetadataLatest: EventMetadataLatest;
- EventMetadataV10: EventMetadataV10;
- EventMetadataV11: EventMetadataV11;
- EventMetadataV12: EventMetadataV12;
- EventMetadataV13: EventMetadataV13;
- EventMetadataV14: EventMetadataV14;
- EventMetadataV9: EventMetadataV9;
- EventRecord: EventRecord;
- EvmAccount: EvmAccount;
- EvmCallInfo: EvmCallInfo;
- EvmCallInfoV2: EvmCallInfoV2;
- EvmCreateInfo: EvmCreateInfo;
- EvmCreateInfoV2: EvmCreateInfoV2;
- EvmLog: EvmLog;
- EvmVicinity: EvmVicinity;
- EvmWeightInfo: EvmWeightInfo;
- ExecReturnValue: ExecReturnValue;
- ExecutorParam: ExecutorParam;
- ExecutorParams: ExecutorParams;
- ExecutorParamsHash: ExecutorParamsHash;
- ExitError: ExitError;
- ExitFatal: ExitFatal;
- ExitReason: ExitReason;
- ExitRevert: ExitRevert;
- ExitSucceed: ExitSucceed;
- ExplicitDisputeStatement: ExplicitDisputeStatement;
- Exposure: Exposure;
- ExtendedBalance: ExtendedBalance;
- Extrinsic: Extrinsic;
- ExtrinsicEra: ExtrinsicEra;
- ExtrinsicMetadataLatest: ExtrinsicMetadataLatest;
- ExtrinsicMetadataV11: ExtrinsicMetadataV11;
- ExtrinsicMetadataV12: ExtrinsicMetadataV12;
- ExtrinsicMetadataV13: ExtrinsicMetadataV13;
- ExtrinsicMetadataV14: ExtrinsicMetadataV14;
- ExtrinsicMetadataV15: ExtrinsicMetadataV15;
- ExtrinsicOrHash: ExtrinsicOrHash;
- ExtrinsicPayload: ExtrinsicPayload;
- ExtrinsicPayloadUnknown: ExtrinsicPayloadUnknown;
- ExtrinsicPayloadV4: ExtrinsicPayloadV4;
- ExtrinsicSignature: ExtrinsicSignature;
- ExtrinsicSignatureV4: ExtrinsicSignatureV4;
- ExtrinsicStatus: ExtrinsicStatus;
- ExtrinsicsWeight: ExtrinsicsWeight;
- ExtrinsicUnknown: ExtrinsicUnknown;
- ExtrinsicV4: ExtrinsicV4;
- f32: f32;
- F32: F32;
- f64: f64;
- F64: F64;
- FeeDetails: FeeDetails;
- Fixed128: Fixed128;
- Fixed64: Fixed64;
- FixedI128: FixedI128;
- FixedI64: FixedI64;
- FixedU128: FixedU128;
- FixedU64: FixedU64;
- Forcing: Forcing;
- ForkTreePendingChange: ForkTreePendingChange;
- ForkTreePendingChangeNode: ForkTreePendingChangeNode;
- FullIdentification: FullIdentification;
- FunctionArgumentMetadataLatest: FunctionArgumentMetadataLatest;
- FunctionArgumentMetadataV10: FunctionArgumentMetadataV10;
- FunctionArgumentMetadataV11: FunctionArgumentMetadataV11;
- FunctionArgumentMetadataV12: FunctionArgumentMetadataV12;
- FunctionArgumentMetadataV13: FunctionArgumentMetadataV13;
- FunctionArgumentMetadataV14: FunctionArgumentMetadataV14;
- FunctionArgumentMetadataV9: FunctionArgumentMetadataV9;
- FunctionMetadataLatest: FunctionMetadataLatest;
- FunctionMetadataV10: FunctionMetadataV10;
- FunctionMetadataV11: FunctionMetadataV11;
- FunctionMetadataV12: FunctionMetadataV12;
- FunctionMetadataV13: FunctionMetadataV13;
- FunctionMetadataV14: FunctionMetadataV14;
- FunctionMetadataV9: FunctionMetadataV9;
- FundIndex: FundIndex;
- FundInfo: FundInfo;
- Fungibility: Fungibility;
- FungibilityV0: FungibilityV0;
- FungibilityV1: FungibilityV1;
- FungibilityV2: FungibilityV2;
- FungiblesAccessError: FungiblesAccessError;
- Gas: Gas;
- GiltBid: GiltBid;
- GlobalValidationData: GlobalValidationData;
- GlobalValidationSchedule: GlobalValidationSchedule;
- GrandpaCommit: GrandpaCommit;
- GrandpaEquivocation: GrandpaEquivocation;
- GrandpaEquivocationProof: GrandpaEquivocationProof;
- GrandpaEquivocationValue: GrandpaEquivocationValue;
- GrandpaJustification: GrandpaJustification;
- GrandpaPrecommit: GrandpaPrecommit;
- GrandpaPrevote: GrandpaPrevote;
- GrandpaSignedPrecommit: GrandpaSignedPrecommit;
- GroupIndex: GroupIndex;
- GroupRotationInfo: GroupRotationInfo;
- H1024: H1024;
- H128: H128;
- H160: H160;
- H2048: H2048;
- H256: H256;
- H32: H32;
- H512: H512;
- H64: H64;
- Hash: Hash;
- HeadData: HeadData;
- Header: Header;
- HeaderPartial: HeaderPartial;
- Health: Health;
- Heartbeat: Heartbeat;
- HeartbeatTo244: HeartbeatTo244;
- HostConfiguration: HostConfiguration;
- HostFnWeights: HostFnWeights;
- HostFnWeightsTo264: HostFnWeightsTo264;
- HrmpChannel: HrmpChannel;
- HrmpChannelId: HrmpChannelId;
- HrmpOpenChannelRequest: HrmpOpenChannelRequest;
- i128: i128;
- I128: I128;
- i16: i16;
- I16: I16;
- i256: i256;
- I256: I256;
- i32: i32;
- I32: I32;
- I32F32: I32F32;
- i64: i64;
- I64: I64;
- i8: i8;
- I8: I8;
- IdentificationTuple: IdentificationTuple;
- IdentityFields: IdentityFields;
- IdentityInfo: IdentityInfo;
- IdentityInfoAdditional: IdentityInfoAdditional;
- IdentityInfoTo198: IdentityInfoTo198;
- IdentityJudgement: IdentityJudgement;
- ImmortalEra: ImmortalEra;
- ImportedAux: ImportedAux;
- InboundDownwardMessage: InboundDownwardMessage;
- InboundHrmpMessage: InboundHrmpMessage;
- InboundHrmpMessages: InboundHrmpMessages;
- InboundLaneData: InboundLaneData;
- InboundRelayer: InboundRelayer;
- InboundStatus: InboundStatus;
- IncludedBlocks: IncludedBlocks;
- InclusionFee: InclusionFee;
- IncomingParachain: IncomingParachain;
- IncomingParachainDeploy: IncomingParachainDeploy;
- IncomingParachainFixed: IncomingParachainFixed;
- Index: Index;
- IndicesLookupSource: IndicesLookupSource;
- IndividualExposure: IndividualExposure;
- InherentData: InherentData;
- InherentIdentifier: InherentIdentifier;
- InitializationData: InitializationData;
- InstanceDetails: InstanceDetails;
- InstanceId: InstanceId;
- InstanceMetadata: InstanceMetadata;
- InstantiateRequest: InstantiateRequest;
- InstantiateRequestV1: InstantiateRequestV1;
- InstantiateRequestV2: InstantiateRequestV2;
- InstantiateReturnValue: InstantiateReturnValue;
- InstantiateReturnValueOk: InstantiateReturnValueOk;
- InstantiateReturnValueTo267: InstantiateReturnValueTo267;
- InstructionV2: InstructionV2;
- InstructionWeights: InstructionWeights;
- InteriorMultiLocation: InteriorMultiLocation;
- InvalidDisputeStatementKind: InvalidDisputeStatementKind;
- InvalidTransaction: InvalidTransaction;
- isize: isize;
- ISize: ISize;
- Json: Json;
- Junction: Junction;
- Junctions: Junctions;
- JunctionsV1: JunctionsV1;
- JunctionsV2: JunctionsV2;
- JunctionV0: JunctionV0;
- JunctionV1: JunctionV1;
- JunctionV2: JunctionV2;
- Justification: Justification;
- JustificationNotification: JustificationNotification;
- Justifications: Justifications;
- Key: Key;
- KeyOwnerProof: KeyOwnerProof;
- Keys: Keys;
- KeyType: KeyType;
- KeyTypeId: KeyTypeId;
- KeyValue: KeyValue;
- KeyValueOption: KeyValueOption;
- Kind: Kind;
- LaneId: LaneId;
- LastContribution: LastContribution;
- LastRuntimeUpgradeInfo: LastRuntimeUpgradeInfo;
- LeasePeriod: LeasePeriod;
- LeasePeriodOf: LeasePeriodOf;
- LegacyTransaction: LegacyTransaction;
- Limits: Limits;
- LimitsTo264: LimitsTo264;
- LocalValidationData: LocalValidationData;
- LockIdentifier: LockIdentifier;
- LookupSource: LookupSource;
- LookupTarget: LookupTarget;
- LotteryConfig: LotteryConfig;
- MaybeRandomness: MaybeRandomness;
- MaybeVrf: MaybeVrf;
- MemberCount: MemberCount;
- MembershipProof: MembershipProof;
- MessageData: MessageData;
- MessageId: MessageId;
- MessageIngestionType: MessageIngestionType;
- MessageKey: MessageKey;
- MessageNonce: MessageNonce;
- MessageQueueChain: MessageQueueChain;
- MessagesDeliveryProofOf: MessagesDeliveryProofOf;
- MessagesProofOf: MessagesProofOf;
- MessagingStateSnapshot: MessagingStateSnapshot;
- MessagingStateSnapshotEgressEntry: MessagingStateSnapshotEgressEntry;
- MetadataAll: MetadataAll;
- MetadataLatest: MetadataLatest;
- MetadataV10: MetadataV10;
- MetadataV11: MetadataV11;
- MetadataV12: MetadataV12;
- MetadataV13: MetadataV13;
- MetadataV14: MetadataV14;
- MetadataV15: MetadataV15;
- MetadataV9: MetadataV9;
- MigrationStatusResult: MigrationStatusResult;
- MmrBatchProof: MmrBatchProof;
- MmrEncodableOpaqueLeaf: MmrEncodableOpaqueLeaf;
- MmrError: MmrError;
- MmrHash: MmrHash;
- MmrLeafBatchProof: MmrLeafBatchProof;
- MmrLeafIndex: MmrLeafIndex;
- MmrLeafProof: MmrLeafProof;
- MmrNodeIndex: MmrNodeIndex;
- MmrProof: MmrProof;
- MmrRootHash: MmrRootHash;
- ModuleConstantMetadataV10: ModuleConstantMetadataV10;
- ModuleConstantMetadataV11: ModuleConstantMetadataV11;
- ModuleConstantMetadataV12: ModuleConstantMetadataV12;
- ModuleConstantMetadataV13: ModuleConstantMetadataV13;
- ModuleConstantMetadataV9: ModuleConstantMetadataV9;
- ModuleId: ModuleId;
- ModuleMetadataV10: ModuleMetadataV10;
- ModuleMetadataV11: ModuleMetadataV11;
- ModuleMetadataV12: ModuleMetadataV12;
- ModuleMetadataV13: ModuleMetadataV13;
- ModuleMetadataV9: ModuleMetadataV9;
- Moment: Moment;
- MomentOf: MomentOf;
- MoreAttestations: MoreAttestations;
- MortalEra: MortalEra;
- MultiAddress: MultiAddress;
- MultiAsset: MultiAsset;
- MultiAssetFilter: MultiAssetFilter;
- MultiAssetFilterV1: MultiAssetFilterV1;
- MultiAssetFilterV2: MultiAssetFilterV2;
- MultiAssets: MultiAssets;
- MultiAssetsV1: MultiAssetsV1;
- MultiAssetsV2: MultiAssetsV2;
- MultiAssetV0: MultiAssetV0;
- MultiAssetV1: MultiAssetV1;
- MultiAssetV2: MultiAssetV2;
- MultiDisputeStatementSet: MultiDisputeStatementSet;
- MultiLocation: MultiLocation;
- MultiLocationV0: MultiLocationV0;
- MultiLocationV1: MultiLocationV1;
- MultiLocationV2: MultiLocationV2;
- Multiplier: Multiplier;
- Multisig: Multisig;
- MultiSignature: MultiSignature;
- MultiSigner: MultiSigner;
- NetworkId: NetworkId;
- NetworkState: NetworkState;
- NetworkStatePeerset: NetworkStatePeerset;
- NetworkStatePeersetInfo: NetworkStatePeersetInfo;
- NewBidder: NewBidder;
- NextAuthority: NextAuthority;
- NextConfigDescriptor: NextConfigDescriptor;
- NextConfigDescriptorV1: NextConfigDescriptorV1;
- NftCollectionId: NftCollectionId;
- NftItemId: NftItemId;
- NodeRole: NodeRole;
- Nominations: Nominations;
- NominatorIndex: NominatorIndex;
- NominatorIndexCompact: NominatorIndexCompact;
- NotConnectedPeer: NotConnectedPeer;
- NpApiError: NpApiError;
- NpPoolId: NpPoolId;
- Null: Null;
- OccupiedCore: OccupiedCore;
- OccupiedCoreAssumption: OccupiedCoreAssumption;
- OffchainAccuracy: OffchainAccuracy;
- OffchainAccuracyCompact: OffchainAccuracyCompact;
- OffenceDetails: OffenceDetails;
- Offender: Offender;
- OldV1SessionInfo: OldV1SessionInfo;
- OpaqueCall: OpaqueCall;
- OpaqueKeyOwnershipProof: OpaqueKeyOwnershipProof;
- OpaqueMetadata: OpaqueMetadata;
- OpaqueMultiaddr: OpaqueMultiaddr;
- OpaqueNetworkState: OpaqueNetworkState;
- OpaquePeerId: OpaquePeerId;
- OpaqueTimeSlot: OpaqueTimeSlot;
- OpenTip: OpenTip;
- OpenTipFinderTo225: OpenTipFinderTo225;
- OpenTipTip: OpenTipTip;
- OpenTipTo225: OpenTipTo225;
- OperatingMode: OperatingMode;
- OptionBool: OptionBool;
- Origin: Origin;
- OriginCaller: OriginCaller;
- OriginKindV0: OriginKindV0;
- OriginKindV1: OriginKindV1;
- OriginKindV2: OriginKindV2;
- OutboundHrmpMessage: OutboundHrmpMessage;
- OutboundLaneData: OutboundLaneData;
- OutboundMessageFee: OutboundMessageFee;
- OutboundPayload: OutboundPayload;
- OutboundStatus: OutboundStatus;
- Outcome: Outcome;
- OuterEnums15: OuterEnums15;
- OverweightIndex: OverweightIndex;
- Owner: Owner;
- PageCounter: PageCounter;
- PageIndexData: PageIndexData;
- PalletCallMetadataLatest: PalletCallMetadataLatest;
- PalletCallMetadataV14: PalletCallMetadataV14;
- PalletConstantMetadataLatest: PalletConstantMetadataLatest;
- PalletConstantMetadataV14: PalletConstantMetadataV14;
- PalletErrorMetadataLatest: PalletErrorMetadataLatest;
- PalletErrorMetadataV14: PalletErrorMetadataV14;
- PalletEventMetadataLatest: PalletEventMetadataLatest;
- PalletEventMetadataV14: PalletEventMetadataV14;
- PalletId: PalletId;
- PalletMetadataLatest: PalletMetadataLatest;
- PalletMetadataV14: PalletMetadataV14;
- PalletMetadataV15: PalletMetadataV15;
- PalletsOrigin: PalletsOrigin;
- PalletStorageMetadataLatest: PalletStorageMetadataLatest;
- PalletStorageMetadataV14: PalletStorageMetadataV14;
- PalletVersion: PalletVersion;
- ParachainDispatchOrigin: ParachainDispatchOrigin;
- ParachainInherentData: ParachainInherentData;
- ParachainProposal: ParachainProposal;
- ParachainsInherentData: ParachainsInherentData;
- ParaGenesisArgs: ParaGenesisArgs;
- ParaId: ParaId;
- ParaInfo: ParaInfo;
- ParaLifecycle: ParaLifecycle;
- Parameter: Parameter;
- ParaPastCodeMeta: ParaPastCodeMeta;
- ParaScheduling: ParaScheduling;
- ParathreadClaim: ParathreadClaim;
- ParathreadClaimQueue: ParathreadClaimQueue;
- ParathreadEntry: ParathreadEntry;
- ParaValidatorIndex: ParaValidatorIndex;
- Pays: Pays;
- Peer: Peer;
- PeerEndpoint: PeerEndpoint;
- PeerEndpointAddr: PeerEndpointAddr;
- PeerInfo: PeerInfo;
- PeerPing: PeerPing;
- PendingChange: PendingChange;
- PendingPause: PendingPause;
- PendingResume: PendingResume;
- PendingSlashes: PendingSlashes;
- Perbill: Perbill;
- Percent: Percent;
- PerDispatchClassU32: PerDispatchClassU32;
- PerDispatchClassWeight: PerDispatchClassWeight;
- PerDispatchClassWeightsPerClass: PerDispatchClassWeightsPerClass;
- Period: Period;
- Permill: Permill;
- PermissionLatest: PermissionLatest;
- PermissionsV1: PermissionsV1;
- PermissionVersions: PermissionVersions;
- Perquintill: Perquintill;
- PersistedValidationData: PersistedValidationData;
- PerU16: PerU16;
- Phantom: Phantom;
- PhantomData: PhantomData;
- Phase: Phase;
- PhragmenScore: PhragmenScore;
- Points: Points;
- PortableType: PortableType;
- PortableTypeV14: PortableTypeV14;
- Precommits: Precommits;
- PrefabWasmModule: PrefabWasmModule;
- PrefixedStorageKey: PrefixedStorageKey;
- PreimageStatus: PreimageStatus;
- PreimageStatusAvailable: PreimageStatusAvailable;
- PreRuntime: PreRuntime;
- Prevotes: Prevotes;
- Priority: Priority;
- PriorLock: PriorLock;
- PropIndex: PropIndex;
- Proposal: Proposal;
- ProposalIndex: ProposalIndex;
- ProxyAnnouncement: ProxyAnnouncement;
- ProxyDefinition: ProxyDefinition;
- ProxyState: ProxyState;
- ProxyType: ProxyType;
- PvfCheckStatement: PvfCheckStatement;
- PvfExecTimeoutKind: PvfExecTimeoutKind;
- PvfPrepTimeoutKind: PvfPrepTimeoutKind;
- QueryId: QueryId;
- QueryStatus: QueryStatus;
- QueueConfigData: QueueConfigData;
- QueuedParathread: QueuedParathread;
- Randomness: Randomness;
- Raw: Raw;
- RawAuraPreDigest: RawAuraPreDigest;
- RawBabePreDigest: RawBabePreDigest;
- RawBabePreDigestCompat: RawBabePreDigestCompat;
- RawBabePreDigestPrimary: RawBabePreDigestPrimary;
- RawBabePreDigestPrimaryTo159: RawBabePreDigestPrimaryTo159;
- RawBabePreDigestSecondaryPlain: RawBabePreDigestSecondaryPlain;
- RawBabePreDigestSecondaryTo159: RawBabePreDigestSecondaryTo159;
- RawBabePreDigestSecondaryVRF: RawBabePreDigestSecondaryVRF;
- RawBabePreDigestTo159: RawBabePreDigestTo159;
- RawOrigin: RawOrigin;
- RawSolution: RawSolution;
- RawSolutionTo265: RawSolutionTo265;
- RawSolutionWith16: RawSolutionWith16;
- RawSolutionWith24: RawSolutionWith24;
- RawVRFOutput: RawVRFOutput;
- ReadProof: ReadProof;
- ReadySolution: ReadySolution;
- Reasons: Reasons;
- RecoveryConfig: RecoveryConfig;
- RefCount: RefCount;
- RefCountTo259: RefCountTo259;
- ReferendumIndex: ReferendumIndex;
- ReferendumInfo: ReferendumInfo;
- ReferendumInfoFinished: ReferendumInfoFinished;
- ReferendumInfoTo239: ReferendumInfoTo239;
- ReferendumStatus: ReferendumStatus;
- RegisteredParachainInfo: RegisteredParachainInfo;
- RegistrarIndex: RegistrarIndex;
- RegistrarInfo: RegistrarInfo;
- Registration: Registration;
- RegistrationJudgement: RegistrationJudgement;
- RegistrationTo198: RegistrationTo198;
- RelayBlockNumber: RelayBlockNumber;
- RelayChainBlockNumber: RelayChainBlockNumber;
- RelayChainHash: RelayChainHash;
- RelayerId: RelayerId;
- RelayHash: RelayHash;
- Releases: Releases;
- Remark: Remark;
- Renouncing: Renouncing;
- RentProjection: RentProjection;
- ReplacementTimes: ReplacementTimes;
- ReportedRoundStates: ReportedRoundStates;
- Reporter: Reporter;
- ReportIdOf: ReportIdOf;
- ReserveData: ReserveData;
- ReserveIdentifier: ReserveIdentifier;
- Response: Response;
- ResponseV0: ResponseV0;
- ResponseV1: ResponseV1;
- ResponseV2: ResponseV2;
- ResponseV2Error: ResponseV2Error;
- ResponseV2Result: ResponseV2Result;
- Retriable: Retriable;
- RewardDestination: RewardDestination;
- RewardPoint: RewardPoint;
- RoundSnapshot: RoundSnapshot;
- RoundState: RoundState;
- RpcMethods: RpcMethods;
- RuntimeApiMetadataLatest: RuntimeApiMetadataLatest;
- RuntimeApiMetadataV15: RuntimeApiMetadataV15;
- RuntimeApiMethodMetadataV15: RuntimeApiMethodMetadataV15;
- RuntimeApiMethodParamMetadataV15: RuntimeApiMethodParamMetadataV15;
- RuntimeCall: RuntimeCall;
- RuntimeDbWeight: RuntimeDbWeight;
- RuntimeDispatchInfo: RuntimeDispatchInfo;
- RuntimeDispatchInfoV1: RuntimeDispatchInfoV1;
- RuntimeDispatchInfoV2: RuntimeDispatchInfoV2;
- RuntimeEvent: RuntimeEvent;
- RuntimeVersion: RuntimeVersion;
- RuntimeVersionApi: RuntimeVersionApi;
- RuntimeVersionPartial: RuntimeVersionPartial;
- RuntimeVersionPre3: RuntimeVersionPre3;
- RuntimeVersionPre4: RuntimeVersionPre4;
- Schedule: Schedule;
- Scheduled: Scheduled;
- ScheduledCore: ScheduledCore;
- ScheduledTo254: ScheduledTo254;
- SchedulePeriod: SchedulePeriod;
- SchedulePriority: SchedulePriority;
- ScheduleTo212: ScheduleTo212;
- ScheduleTo258: ScheduleTo258;
- ScheduleTo264: ScheduleTo264;
- Scheduling: Scheduling;
- ScrapedOnChainVotes: ScrapedOnChainVotes;
- Seal: Seal;
- SealV0: SealV0;
- SeatHolder: SeatHolder;
- SeedOf: SeedOf;
- ServiceQuality: ServiceQuality;
- SessionIndex: SessionIndex;
- SessionInfo: SessionInfo;
- SessionInfoValidatorGroup: SessionInfoValidatorGroup;
- SessionKeys1: SessionKeys1;
- SessionKeys10: SessionKeys10;
- SessionKeys10B: SessionKeys10B;
- SessionKeys2: SessionKeys2;
- SessionKeys3: SessionKeys3;
- SessionKeys4: SessionKeys4;
- SessionKeys5: SessionKeys5;
- SessionKeys6: SessionKeys6;
- SessionKeys6B: SessionKeys6B;
- SessionKeys7: SessionKeys7;
- SessionKeys7B: SessionKeys7B;
- SessionKeys8: SessionKeys8;
- SessionKeys8B: SessionKeys8B;
- SessionKeys9: SessionKeys9;
- SessionKeys9B: SessionKeys9B;
- SetId: SetId;
- SetIndex: SetIndex;
- Si0Field: Si0Field;
- Si0LookupTypeId: Si0LookupTypeId;
- Si0Path: Si0Path;
- Si0Type: Si0Type;
- Si0TypeDef: Si0TypeDef;
- Si0TypeDefArray: Si0TypeDefArray;
- Si0TypeDefBitSequence: Si0TypeDefBitSequence;
- Si0TypeDefCompact: Si0TypeDefCompact;
- Si0TypeDefComposite: Si0TypeDefComposite;
- Si0TypeDefPhantom: Si0TypeDefPhantom;
- Si0TypeDefPrimitive: Si0TypeDefPrimitive;
- Si0TypeDefSequence: Si0TypeDefSequence;
- Si0TypeDefTuple: Si0TypeDefTuple;
- Si0TypeDefVariant: Si0TypeDefVariant;
- Si0TypeParameter: Si0TypeParameter;
- Si0Variant: Si0Variant;
- Si1Field: Si1Field;
- Si1LookupTypeId: Si1LookupTypeId;
- Si1Path: Si1Path;
- Si1Type: Si1Type;
- Si1TypeDef: Si1TypeDef;
- Si1TypeDefArray: Si1TypeDefArray;
- Si1TypeDefBitSequence: Si1TypeDefBitSequence;
- Si1TypeDefCompact: Si1TypeDefCompact;
- Si1TypeDefComposite: Si1TypeDefComposite;
- Si1TypeDefPrimitive: Si1TypeDefPrimitive;
- Si1TypeDefSequence: Si1TypeDefSequence;
- Si1TypeDefTuple: Si1TypeDefTuple;
- Si1TypeDefVariant: Si1TypeDefVariant;
- Si1TypeParameter: Si1TypeParameter;
- Si1Variant: Si1Variant;
- SiField: SiField;
- Signature: Signature;
- SignedAvailabilityBitfield: SignedAvailabilityBitfield;
- SignedAvailabilityBitfields: SignedAvailabilityBitfields;
- SignedBlock: SignedBlock;
- SignedBlockWithJustification: SignedBlockWithJustification;
- SignedBlockWithJustifications: SignedBlockWithJustifications;
- SignedExtensionMetadataLatest: SignedExtensionMetadataLatest;
- SignedExtensionMetadataV14: SignedExtensionMetadataV14;
- SignedSubmission: SignedSubmission;
- SignedSubmissionOf: SignedSubmissionOf;
- SignedSubmissionTo276: SignedSubmissionTo276;
- SignerPayload: SignerPayload;
- SigningContext: SigningContext;
- SiLookupTypeId: SiLookupTypeId;
- SiPath: SiPath;
- SiType: SiType;
- SiTypeDef: SiTypeDef;
- SiTypeDefArray: SiTypeDefArray;
- SiTypeDefBitSequence: SiTypeDefBitSequence;
- SiTypeDefCompact: SiTypeDefCompact;
- SiTypeDefComposite: SiTypeDefComposite;
- SiTypeDefPrimitive: SiTypeDefPrimitive;
- SiTypeDefSequence: SiTypeDefSequence;
- SiTypeDefTuple: SiTypeDefTuple;
- SiTypeDefVariant: SiTypeDefVariant;
- SiTypeParameter: SiTypeParameter;
- SiVariant: SiVariant;
- SlashingOffenceKind: SlashingOffenceKind;
- SlashingSpans: SlashingSpans;
- SlashingSpansTo204: SlashingSpansTo204;
- SlashJournalEntry: SlashJournalEntry;
- Slot: Slot;
- SlotDuration: SlotDuration;
- SlotNumber: SlotNumber;
- SlotRange: SlotRange;
- SlotRange10: SlotRange10;
- SocietyJudgement: SocietyJudgement;
- SocietyVote: SocietyVote;
- SolutionOrSnapshotSize: SolutionOrSnapshotSize;
- SolutionSupport: SolutionSupport;
- SolutionSupports: SolutionSupports;
- SpanIndex: SpanIndex;
- SpanRecord: SpanRecord;
- SpecVersion: SpecVersion;
- Sr25519Signature: Sr25519Signature;
- StakingLedger: StakingLedger;
- StakingLedgerTo223: StakingLedgerTo223;
- StakingLedgerTo240: StakingLedgerTo240;
- Statement: Statement;
- StatementKind: StatementKind;
- StorageChangeSet: StorageChangeSet;
- StorageData: StorageData;
- StorageDeposit: StorageDeposit;
- StorageEntryMetadataLatest: StorageEntryMetadataLatest;
- StorageEntryMetadataV10: StorageEntryMetadataV10;
- StorageEntryMetadataV11: StorageEntryMetadataV11;
- StorageEntryMetadataV12: StorageEntryMetadataV12;
- StorageEntryMetadataV13: StorageEntryMetadataV13;
- StorageEntryMetadataV14: StorageEntryMetadataV14;
- StorageEntryMetadataV9: StorageEntryMetadataV9;
- StorageEntryModifierLatest: StorageEntryModifierLatest;
- StorageEntryModifierV10: StorageEntryModifierV10;
- StorageEntryModifierV11: StorageEntryModifierV11;
- StorageEntryModifierV12: StorageEntryModifierV12;
- StorageEntryModifierV13: StorageEntryModifierV13;
- StorageEntryModifierV14: StorageEntryModifierV14;
- StorageEntryModifierV9: StorageEntryModifierV9;
- StorageEntryTypeLatest: StorageEntryTypeLatest;
- StorageEntryTypeV10: StorageEntryTypeV10;
- StorageEntryTypeV11: StorageEntryTypeV11;
- StorageEntryTypeV12: StorageEntryTypeV12;
- StorageEntryTypeV13: StorageEntryTypeV13;
- StorageEntryTypeV14: StorageEntryTypeV14;
- StorageEntryTypeV9: StorageEntryTypeV9;
- StorageHasher: StorageHasher;
- StorageHasherV10: StorageHasherV10;
- StorageHasherV11: StorageHasherV11;
- StorageHasherV12: StorageHasherV12;
- StorageHasherV13: StorageHasherV13;
- StorageHasherV14: StorageHasherV14;
- StorageHasherV9: StorageHasherV9;
- StorageInfo: StorageInfo;
- StorageKey: StorageKey;
- StorageKind: StorageKind;
- StorageMetadataV10: StorageMetadataV10;
- StorageMetadataV11: StorageMetadataV11;
- StorageMetadataV12: StorageMetadataV12;
- StorageMetadataV13: StorageMetadataV13;
- StorageMetadataV9: StorageMetadataV9;
- StorageProof: StorageProof;
- StoredPendingChange: StoredPendingChange;
- StoredState: StoredState;
- StrikeCount: StrikeCount;
- SubId: SubId;
- SubmissionIndicesOf: SubmissionIndicesOf;
- Supports: Supports;
- SyncState: SyncState;
- SystemInherentData: SystemInherentData;
- SystemOrigin: SystemOrigin;
- Tally: Tally;
- TaskAddress: TaskAddress;
- TAssetBalance: TAssetBalance;
- TAssetDepositBalance: TAssetDepositBalance;
- Text: Text;
- Timepoint: Timepoint;
- TokenError: TokenError;
- TombstoneContractInfo: TombstoneContractInfo;
- TraceBlockResponse: TraceBlockResponse;
- TraceError: TraceError;
- TransactionalError: TransactionalError;
- TransactionInfo: TransactionInfo;
- TransactionLongevity: TransactionLongevity;
- TransactionPriority: TransactionPriority;
- TransactionSource: TransactionSource;
- TransactionStorageProof: TransactionStorageProof;
- TransactionTag: TransactionTag;
- TransactionV0: TransactionV0;
- TransactionV1: TransactionV1;
- TransactionV2: TransactionV2;
- TransactionValidity: TransactionValidity;
- TransactionValidityError: TransactionValidityError;
- TransientValidationData: TransientValidationData;
- TreasuryProposal: TreasuryProposal;
- TrieId: TrieId;
- TrieIndex: TrieIndex;
- Type: Type;
- u128: u128;
- U128: U128;
- u16: u16;
- U16: U16;
- u256: u256;
- U256: U256;
- u32: u32;
- U32: U32;
- U32F32: U32F32;
- u64: u64;
- U64: U64;
- u8: u8;
- U8: U8;
- UnappliedSlash: UnappliedSlash;
- UnappliedSlashOther: UnappliedSlashOther;
- UncleEntryItem: UncleEntryItem;
- UnknownTransaction: UnknownTransaction;
- UnlockChunk: UnlockChunk;
- UnrewardedRelayer: UnrewardedRelayer;
- UnrewardedRelayersState: UnrewardedRelayersState;
- UpgradeGoAhead: UpgradeGoAhead;
- UpgradeRestriction: UpgradeRestriction;
- UpwardMessage: UpwardMessage;
- usize: usize;
- USize: USize;
- ValidationCode: ValidationCode;
- ValidationCodeHash: ValidationCodeHash;
- ValidationData: ValidationData;
- ValidationDataType: ValidationDataType;
- ValidationFunctionParams: ValidationFunctionParams;
- ValidatorCount: ValidatorCount;
- ValidatorId: ValidatorId;
- ValidatorIdOf: ValidatorIdOf;
- ValidatorIndex: ValidatorIndex;
- ValidatorIndexCompact: ValidatorIndexCompact;
- ValidatorPrefs: ValidatorPrefs;
- ValidatorPrefsTo145: ValidatorPrefsTo145;
- ValidatorPrefsTo196: ValidatorPrefsTo196;
- ValidatorPrefsWithBlocked: ValidatorPrefsWithBlocked;
- ValidatorPrefsWithCommission: ValidatorPrefsWithCommission;
- ValidatorSet: ValidatorSet;
- ValidatorSetId: ValidatorSetId;
- ValidatorSignature: ValidatorSignature;
- ValidDisputeStatementKind: ValidDisputeStatementKind;
- ValidityAttestation: ValidityAttestation;
- ValidTransaction: ValidTransaction;
- VecInboundHrmpMessage: VecInboundHrmpMessage;
- VersionedMultiAsset: VersionedMultiAsset;
- VersionedMultiAssets: VersionedMultiAssets;
- VersionedMultiLocation: VersionedMultiLocation;
- VersionedResponse: VersionedResponse;
- VersionedXcm: VersionedXcm;
- VersionMigrationStage: VersionMigrationStage;
- VestingInfo: VestingInfo;
- VestingSchedule: VestingSchedule;
- Vote: Vote;
- VoteIndex: VoteIndex;
- Voter: Voter;
- VoterInfo: VoterInfo;
- Votes: Votes;
- VotesTo230: VotesTo230;
- VoteThreshold: VoteThreshold;
- VoteWeight: VoteWeight;
- Voting: Voting;
- VotingDelegating: VotingDelegating;
- VotingDirect: VotingDirect;
- VotingDirectVote: VotingDirectVote;
- VouchingStatus: VouchingStatus;
- VrfData: VrfData;
- VrfOutput: VrfOutput;
- VrfProof: VrfProof;
- Weight: Weight;
- WeightLimitV2: WeightLimitV2;
- WeightMultiplier: WeightMultiplier;
- WeightPerClass: WeightPerClass;
- WeightToFeeCoefficient: WeightToFeeCoefficient;
- WeightV0: WeightV0;
- WeightV1: WeightV1;
- WeightV2: WeightV2;
- WildFungibility: WildFungibility;
- WildFungibilityV0: WildFungibilityV0;
- WildFungibilityV1: WildFungibilityV1;
- WildFungibilityV2: WildFungibilityV2;
- WildMultiAsset: WildMultiAsset;
- WildMultiAssetV1: WildMultiAssetV1;
- WildMultiAssetV2: WildMultiAssetV2;
- WinnersData: WinnersData;
- WinnersData10: WinnersData10;
- WinnersDataTuple: WinnersDataTuple;
- WinnersDataTuple10: WinnersDataTuple10;
- WinningData: WinningData;
- WinningData10: WinningData10;
- WinningDataEntry: WinningDataEntry;
- WithdrawReasons: WithdrawReasons;
- Xcm: Xcm;
- XcmAssetId: XcmAssetId;
- XcmError: XcmError;
- XcmErrorV0: XcmErrorV0;
- XcmErrorV1: XcmErrorV1;
- XcmErrorV2: XcmErrorV2;
- XcmOrder: XcmOrder;
- XcmOrderV0: XcmOrderV0;
- XcmOrderV1: XcmOrderV1;
- XcmOrderV2: XcmOrderV2;
- XcmOrigin: XcmOrigin;
- XcmOriginKind: XcmOriginKind;
- XcmpMessageFormat: XcmpMessageFormat;
- XcmV0: XcmV0;
- XcmV1: XcmV1;
- XcmV2: XcmV2;
- XcmVersion: XcmVersion;
- } // InterfaceTypes
-} // declare module
js-packages/types/src/default/definitions.tsdiffbeforeafterboth--- a/js-packages/types/src/default/definitions.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import types from '../lookup.js';
-
-export default {
- types,
- rpc: {},
-};
js-packages/types/src/default/index.tsdiffbeforeafterboth--- a/js-packages/types/src/default/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './types.js';
js-packages/types/src/default/types.tsdiffbeforeafterboth--- a/js-packages/types/src/default/types.ts
+++ /dev/null
@@ -1,5537 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-import type { Data } from '@polkadot/types';
-import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, i64, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
-import type { ITuple } from '@polkadot/types-codec/types';
-import type { Vote } from '@polkadot/types/interfaces/elections';
-import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
-import type { Event } from '@polkadot/types/interfaces/system';
-
-/** @name CumulusPalletDmpQueueCall */
-export interface CumulusPalletDmpQueueCall extends Enum {
- readonly isServiceOverweight: boolean;
- readonly asServiceOverweight: {
- readonly index: u64;
- readonly weightLimit: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'ServiceOverweight';
-}
-
-/** @name CumulusPalletDmpQueueConfigData */
-export interface CumulusPalletDmpQueueConfigData extends Struct {
- readonly maxIndividual: SpWeightsWeightV2Weight;
-}
-
-/** @name CumulusPalletDmpQueueError */
-export interface CumulusPalletDmpQueueError extends Enum {
- readonly isUnknown: boolean;
- readonly isOverLimit: boolean;
- readonly type: 'Unknown' | 'OverLimit';
-}
-
-/** @name CumulusPalletDmpQueueEvent */
-export interface CumulusPalletDmpQueueEvent extends Enum {
- readonly isInvalidFormat: boolean;
- readonly asInvalidFormat: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isUnsupportedVersion: boolean;
- readonly asUnsupportedVersion: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isExecutedDownward: boolean;
- readonly asExecutedDownward: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly outcome: StagingXcmV3TraitsOutcome;
- } & Struct;
- readonly isWeightExhausted: boolean;
- readonly asWeightExhausted: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly remainingWeight: SpWeightsWeightV2Weight;
- readonly requiredWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isOverweightEnqueued: boolean;
- readonly asOverweightEnqueued: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly overweightIndex: u64;
- readonly requiredWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isOverweightServiced: boolean;
- readonly asOverweightServiced: {
- readonly overweightIndex: u64;
- readonly weightUsed: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isMaxMessagesExhausted: boolean;
- readonly asMaxMessagesExhausted: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced' | 'MaxMessagesExhausted';
-}
-
-/** @name CumulusPalletDmpQueuePageIndexData */
-export interface CumulusPalletDmpQueuePageIndexData extends Struct {
- readonly beginUsed: u32;
- readonly endUsed: u32;
- readonly overweightCount: u64;
-}
-
-/** @name CumulusPalletParachainSystemCall */
-export interface CumulusPalletParachainSystemCall extends Enum {
- readonly isSetValidationData: boolean;
- readonly asSetValidationData: {
- readonly data: CumulusPrimitivesParachainInherentParachainInherentData;
- } & Struct;
- readonly isSudoSendUpwardMessage: boolean;
- readonly asSudoSendUpwardMessage: {
- readonly message: Bytes;
- } & Struct;
- readonly isAuthorizeUpgrade: boolean;
- readonly asAuthorizeUpgrade: {
- readonly codeHash: H256;
- readonly checkVersion: bool;
- } & Struct;
- readonly isEnactAuthorizedUpgrade: boolean;
- readonly asEnactAuthorizedUpgrade: {
- readonly code: Bytes;
- } & Struct;
- readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
-}
-
-/** @name CumulusPalletParachainSystemCodeUpgradeAuthorization */
-export interface CumulusPalletParachainSystemCodeUpgradeAuthorization extends Struct {
- readonly codeHash: H256;
- readonly checkVersion: bool;
-}
-
-/** @name CumulusPalletParachainSystemError */
-export interface CumulusPalletParachainSystemError extends Enum {
- readonly isOverlappingUpgrades: boolean;
- readonly isProhibitedByPolkadot: boolean;
- readonly isTooBig: boolean;
- readonly isValidationDataNotAvailable: boolean;
- readonly isHostConfigurationNotAvailable: boolean;
- readonly isNotScheduled: boolean;
- readonly isNothingAuthorized: boolean;
- readonly isUnauthorized: boolean;
- readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
-}
-
-/** @name CumulusPalletParachainSystemEvent */
-export interface CumulusPalletParachainSystemEvent extends Enum {
- readonly isValidationFunctionStored: boolean;
- readonly isValidationFunctionApplied: boolean;
- readonly asValidationFunctionApplied: {
- readonly relayChainBlockNum: u32;
- } & Struct;
- readonly isValidationFunctionDiscarded: boolean;
- readonly isUpgradeAuthorized: boolean;
- readonly asUpgradeAuthorized: {
- readonly codeHash: H256;
- } & Struct;
- readonly isDownwardMessagesReceived: boolean;
- readonly asDownwardMessagesReceived: {
- readonly count: u32;
- } & Struct;
- readonly isDownwardMessagesProcessed: boolean;
- readonly asDownwardMessagesProcessed: {
- readonly weightUsed: SpWeightsWeightV2Weight;
- readonly dmqHead: H256;
- } & Struct;
- readonly isUpwardMessageSent: boolean;
- readonly asUpwardMessageSent: {
- readonly messageHash: Option<U8aFixed>;
- } & Struct;
- readonly type: 'ValidationFunctionStored' | 'ValidationFunctionApplied' | 'ValidationFunctionDiscarded' | 'UpgradeAuthorized' | 'DownwardMessagesReceived' | 'DownwardMessagesProcessed' | 'UpwardMessageSent';
-}
-
-/** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot */
-export interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
- readonly dmqMqcHead: H256;
- readonly relayDispatchQueueRemainingCapacity: CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity;
- readonly ingressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
- readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
-}
-
-/** @name CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity */
-export interface CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity extends Struct {
- readonly remainingCount: u32;
- readonly remainingSize: u32;
-}
-
-/** @name CumulusPalletParachainSystemUnincludedSegmentAncestor */
-export interface CumulusPalletParachainSystemUnincludedSegmentAncestor extends Struct {
- readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
- readonly paraHeadHash: Option<H256>;
- readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
-}
-
-/** @name CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate */
-export interface CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate extends Struct {
- readonly msgCount: u32;
- readonly totalBytes: u32;
-}
-
-/** @name CumulusPalletParachainSystemUnincludedSegmentSegmentTracker */
-export interface CumulusPalletParachainSystemUnincludedSegmentSegmentTracker extends Struct {
- readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
- readonly hrmpWatermark: Option<u32>;
- readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
-}
-
-/** @name CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth */
-export interface CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth extends Struct {
- readonly umpMsgCount: u32;
- readonly umpTotalBytes: u32;
- readonly hrmpOutgoing: BTreeMap<u32, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate>;
-}
-
-/** @name CumulusPalletXcmCall */
-export interface CumulusPalletXcmCall extends Null {}
-
-/** @name CumulusPalletXcmError */
-export interface CumulusPalletXcmError extends Null {}
-
-/** @name CumulusPalletXcmEvent */
-export interface CumulusPalletXcmEvent extends Enum {
- readonly isInvalidFormat: boolean;
- readonly asInvalidFormat: U8aFixed;
- readonly isUnsupportedVersion: boolean;
- readonly asUnsupportedVersion: U8aFixed;
- readonly isExecutedDownward: boolean;
- readonly asExecutedDownward: ITuple<[U8aFixed, StagingXcmV3TraitsOutcome]>;
- readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward';
-}
-
-/** @name CumulusPalletXcmOrigin */
-export interface CumulusPalletXcmOrigin extends Enum {
- readonly isRelay: boolean;
- readonly isSiblingParachain: boolean;
- readonly asSiblingParachain: u32;
- readonly type: 'Relay' | 'SiblingParachain';
-}
-
-/** @name CumulusPalletXcmpQueueCall */
-export interface CumulusPalletXcmpQueueCall extends Enum {
- readonly isServiceOverweight: boolean;
- readonly asServiceOverweight: {
- readonly index: u64;
- readonly weightLimit: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isSuspendXcmExecution: boolean;
- readonly isResumeXcmExecution: boolean;
- readonly isUpdateSuspendThreshold: boolean;
- readonly asUpdateSuspendThreshold: {
- readonly new_: u32;
- } & Struct;
- readonly isUpdateDropThreshold: boolean;
- readonly asUpdateDropThreshold: {
- readonly new_: u32;
- } & Struct;
- readonly isUpdateResumeThreshold: boolean;
- readonly asUpdateResumeThreshold: {
- readonly new_: u32;
- } & Struct;
- readonly isUpdateThresholdWeight: boolean;
- readonly asUpdateThresholdWeight: {
- readonly new_: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isUpdateWeightRestrictDecay: boolean;
- readonly asUpdateWeightRestrictDecay: {
- readonly new_: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isUpdateXcmpMaxIndividualWeight: boolean;
- readonly asUpdateXcmpMaxIndividualWeight: {
- readonly new_: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
-}
-
-/** @name CumulusPalletXcmpQueueError */
-export interface CumulusPalletXcmpQueueError extends Enum {
- readonly isFailedToSend: boolean;
- readonly isBadXcmOrigin: boolean;
- readonly isBadXcm: boolean;
- readonly isBadOverweightIndex: boolean;
- readonly isWeightOverLimit: boolean;
- readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
-}
-
-/** @name CumulusPalletXcmpQueueEvent */
-export interface CumulusPalletXcmpQueueEvent extends Enum {
- readonly isSuccess: boolean;
- readonly asSuccess: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isFail: boolean;
- readonly asFail: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly error: StagingXcmV3TraitsError;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isBadVersion: boolean;
- readonly asBadVersion: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isBadFormat: boolean;
- readonly asBadFormat: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isXcmpMessageSent: boolean;
- readonly asXcmpMessageSent: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isOverweightEnqueued: boolean;
- readonly asOverweightEnqueued: {
- readonly sender: u32;
- readonly sentAt: u32;
- readonly index: u64;
- readonly required: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isOverweightServiced: boolean;
- readonly asOverweightServiced: {
- readonly index: u64;
- readonly used: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced';
-}
-
-/** @name CumulusPalletXcmpQueueInboundChannelDetails */
-export interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
- readonly sender: u32;
- readonly state: CumulusPalletXcmpQueueInboundState;
- readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat]>>;
-}
-
-/** @name CumulusPalletXcmpQueueInboundState */
-export interface CumulusPalletXcmpQueueInboundState extends Enum {
- readonly isOk: boolean;
- readonly isSuspended: boolean;
- readonly type: 'Ok' | 'Suspended';
-}
-
-/** @name CumulusPalletXcmpQueueOutboundChannelDetails */
-export interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
- readonly recipient: u32;
- readonly state: CumulusPalletXcmpQueueOutboundState;
- readonly signalsExist: bool;
- readonly firstIndex: u16;
- readonly lastIndex: u16;
-}
-
-/** @name CumulusPalletXcmpQueueOutboundState */
-export interface CumulusPalletXcmpQueueOutboundState extends Enum {
- readonly isOk: boolean;
- readonly isSuspended: boolean;
- readonly type: 'Ok' | 'Suspended';
-}
-
-/** @name CumulusPalletXcmpQueueQueueConfigData */
-export interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
- readonly suspendThreshold: u32;
- readonly dropThreshold: u32;
- readonly resumeThreshold: u32;
- readonly thresholdWeight: SpWeightsWeightV2Weight;
- readonly weightRestrictDecay: SpWeightsWeightV2Weight;
- readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight;
-}
-
-/** @name CumulusPrimitivesParachainInherentParachainInherentData */
-export interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
- readonly validationData: PolkadotPrimitivesV5PersistedValidationData;
- readonly relayChainState: SpTrieStorageProof;
- readonly downwardMessages: Vec<PolkadotCorePrimitivesInboundDownwardMessage>;
- readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
-}
-
-/** @name EthbloomBloom */
-export interface EthbloomBloom extends U8aFixed {}
-
-/** @name EthereumBlock */
-export interface EthereumBlock extends Struct {
- readonly header: EthereumHeader;
- readonly transactions: Vec<EthereumTransactionTransactionV2>;
- readonly ommers: Vec<EthereumHeader>;
-}
-
-/** @name EthereumHeader */
-export interface EthereumHeader extends Struct {
- readonly parentHash: H256;
- readonly ommersHash: H256;
- readonly beneficiary: H160;
- readonly stateRoot: H256;
- readonly transactionsRoot: H256;
- readonly receiptsRoot: H256;
- readonly logsBloom: EthbloomBloom;
- readonly difficulty: U256;
- readonly number: U256;
- readonly gasLimit: U256;
- readonly gasUsed: U256;
- readonly timestamp: u64;
- readonly extraData: Bytes;
- readonly mixHash: H256;
- readonly nonce: EthereumTypesHashH64;
-}
-
-/** @name EthereumLog */
-export interface EthereumLog extends Struct {
- readonly address: H160;
- readonly topics: Vec<H256>;
- readonly data: Bytes;
-}
-
-/** @name EthereumReceiptEip658ReceiptData */
-export interface EthereumReceiptEip658ReceiptData extends Struct {
- readonly statusCode: u8;
- readonly usedGas: U256;
- readonly logsBloom: EthbloomBloom;
- readonly logs: Vec<EthereumLog>;
-}
-
-/** @name EthereumReceiptReceiptV3 */
-export interface EthereumReceiptReceiptV3 extends Enum {
- readonly isLegacy: boolean;
- readonly asLegacy: EthereumReceiptEip658ReceiptData;
- readonly isEip2930: boolean;
- readonly asEip2930: EthereumReceiptEip658ReceiptData;
- readonly isEip1559: boolean;
- readonly asEip1559: EthereumReceiptEip658ReceiptData;
- readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
-}
-
-/** @name EthereumTransactionAccessListItem */
-export interface EthereumTransactionAccessListItem extends Struct {
- readonly address: H160;
- readonly storageKeys: Vec<H256>;
-}
-
-/** @name EthereumTransactionEip1559Transaction */
-export interface EthereumTransactionEip1559Transaction extends Struct {
- readonly chainId: u64;
- readonly nonce: U256;
- readonly maxPriorityFeePerGas: U256;
- readonly maxFeePerGas: U256;
- readonly gasLimit: U256;
- readonly action: EthereumTransactionTransactionAction;
- readonly value: U256;
- readonly input: Bytes;
- readonly accessList: Vec<EthereumTransactionAccessListItem>;
- readonly oddYParity: bool;
- readonly r: H256;
- readonly s: H256;
-}
-
-/** @name EthereumTransactionEip2930Transaction */
-export interface EthereumTransactionEip2930Transaction extends Struct {
- readonly chainId: u64;
- readonly nonce: U256;
- readonly gasPrice: U256;
- readonly gasLimit: U256;
- readonly action: EthereumTransactionTransactionAction;
- readonly value: U256;
- readonly input: Bytes;
- readonly accessList: Vec<EthereumTransactionAccessListItem>;
- readonly oddYParity: bool;
- readonly r: H256;
- readonly s: H256;
-}
-
-/** @name EthereumTransactionLegacyTransaction */
-export interface EthereumTransactionLegacyTransaction extends Struct {
- readonly nonce: U256;
- readonly gasPrice: U256;
- readonly gasLimit: U256;
- readonly action: EthereumTransactionTransactionAction;
- readonly value: U256;
- readonly input: Bytes;
- readonly signature: EthereumTransactionTransactionSignature;
-}
-
-/** @name EthereumTransactionTransactionAction */
-export interface EthereumTransactionTransactionAction extends Enum {
- readonly isCall: boolean;
- readonly asCall: H160;
- readonly isCreate: boolean;
- readonly type: 'Call' | 'Create';
-}
-
-/** @name EthereumTransactionTransactionSignature */
-export interface EthereumTransactionTransactionSignature extends Struct {
- readonly v: u64;
- readonly r: H256;
- readonly s: H256;
-}
-
-/** @name EthereumTransactionTransactionV2 */
-export interface EthereumTransactionTransactionV2 extends Enum {
- readonly isLegacy: boolean;
- readonly asLegacy: EthereumTransactionLegacyTransaction;
- readonly isEip2930: boolean;
- readonly asEip2930: EthereumTransactionEip2930Transaction;
- readonly isEip1559: boolean;
- readonly asEip1559: EthereumTransactionEip1559Transaction;
- readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
-}
-
-/** @name EthereumTypesHashH64 */
-export interface EthereumTypesHashH64 extends U8aFixed {}
-
-/** @name EvmCoreErrorExitError */
-export interface EvmCoreErrorExitError extends Enum {
- readonly isStackUnderflow: boolean;
- readonly isStackOverflow: boolean;
- readonly isInvalidJump: boolean;
- readonly isInvalidRange: boolean;
- readonly isDesignatedInvalid: boolean;
- readonly isCallTooDeep: boolean;
- readonly isCreateCollision: boolean;
- readonly isCreateContractLimit: boolean;
- readonly isOutOfOffset: boolean;
- readonly isOutOfGas: boolean;
- readonly isOutOfFund: boolean;
- readonly isPcUnderflow: boolean;
- readonly isCreateEmpty: boolean;
- readonly isOther: boolean;
- readonly asOther: Text;
- readonly isMaxNonce: boolean;
- readonly isInvalidCode: boolean;
- readonly asInvalidCode: u8;
- readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'MaxNonce' | 'InvalidCode';
-}
-
-/** @name EvmCoreErrorExitFatal */
-export interface EvmCoreErrorExitFatal extends Enum {
- readonly isNotSupported: boolean;
- readonly isUnhandledInterrupt: boolean;
- readonly isCallErrorAsFatal: boolean;
- readonly asCallErrorAsFatal: EvmCoreErrorExitError;
- readonly isOther: boolean;
- readonly asOther: Text;
- readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
-}
-
-/** @name EvmCoreErrorExitReason */
-export interface EvmCoreErrorExitReason extends Enum {
- readonly isSucceed: boolean;
- readonly asSucceed: EvmCoreErrorExitSucceed;
- readonly isError: boolean;
- readonly asError: EvmCoreErrorExitError;
- readonly isRevert: boolean;
- readonly asRevert: EvmCoreErrorExitRevert;
- readonly isFatal: boolean;
- readonly asFatal: EvmCoreErrorExitFatal;
- readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
-}
-
-/** @name EvmCoreErrorExitRevert */
-export interface EvmCoreErrorExitRevert extends Enum {
- readonly isReverted: boolean;
- readonly type: 'Reverted';
-}
-
-/** @name EvmCoreErrorExitSucceed */
-export interface EvmCoreErrorExitSucceed extends Enum {
- readonly isStopped: boolean;
- readonly isReturned: boolean;
- readonly isSuicided: boolean;
- readonly type: 'Stopped' | 'Returned' | 'Suicided';
-}
-
-/** @name FpRpcTransactionStatus */
-export interface FpRpcTransactionStatus extends Struct {
- readonly transactionHash: H256;
- readonly transactionIndex: u32;
- readonly from: H160;
- readonly to: Option<H160>;
- readonly contractAddress: Option<H160>;
- readonly logs: Vec<EthereumLog>;
- readonly logsBloom: EthbloomBloom;
-}
-
-/** @name FrameSupportDispatchDispatchClass */
-export interface FrameSupportDispatchDispatchClass extends Enum {
- readonly isNormal: boolean;
- readonly isOperational: boolean;
- readonly isMandatory: boolean;
- readonly type: 'Normal' | 'Operational' | 'Mandatory';
-}
-
-/** @name FrameSupportDispatchDispatchInfo */
-export interface FrameSupportDispatchDispatchInfo extends Struct {
- readonly weight: SpWeightsWeightV2Weight;
- readonly class: FrameSupportDispatchDispatchClass;
- readonly paysFee: FrameSupportDispatchPays;
-}
-
-/** @name FrameSupportDispatchPays */
-export interface FrameSupportDispatchPays extends Enum {
- readonly isYes: boolean;
- readonly isNo: boolean;
- readonly type: 'Yes' | 'No';
-}
-
-/** @name FrameSupportDispatchPerDispatchClassU32 */
-export interface FrameSupportDispatchPerDispatchClassU32 extends Struct {
- readonly normal: u32;
- readonly operational: u32;
- readonly mandatory: u32;
-}
-
-/** @name FrameSupportDispatchPerDispatchClassWeight */
-export interface FrameSupportDispatchPerDispatchClassWeight extends Struct {
- readonly normal: SpWeightsWeightV2Weight;
- readonly operational: SpWeightsWeightV2Weight;
- readonly mandatory: SpWeightsWeightV2Weight;
-}
-
-/** @name FrameSupportDispatchPerDispatchClassWeightsPerClass */
-export interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct {
- readonly normal: FrameSystemLimitsWeightsPerClass;
- readonly operational: FrameSystemLimitsWeightsPerClass;
- readonly mandatory: FrameSystemLimitsWeightsPerClass;
-}
-
-/** @name FrameSupportDispatchRawOrigin */
-export interface FrameSupportDispatchRawOrigin extends Enum {
- readonly isRoot: boolean;
- readonly isSigned: boolean;
- readonly asSigned: AccountId32;
- readonly isNone: boolean;
- readonly type: 'Root' | 'Signed' | 'None';
-}
-
-/** @name FrameSupportPalletId */
-export interface FrameSupportPalletId extends U8aFixed {}
-
-/** @name FrameSupportPreimagesBounded */
-export interface FrameSupportPreimagesBounded extends Enum {
- readonly isLegacy: boolean;
- readonly asLegacy: {
- readonly hash_: H256;
- } & Struct;
- readonly isInline: boolean;
- readonly asInline: Bytes;
- readonly isLookup: boolean;
- readonly asLookup: {
- readonly hash_: H256;
- readonly len: u32;
- } & Struct;
- readonly type: 'Legacy' | 'Inline' | 'Lookup';
-}
-
-/** @name FrameSupportScheduleDispatchTime */
-export interface FrameSupportScheduleDispatchTime extends Enum {
- readonly isAt: boolean;
- readonly asAt: u32;
- readonly isAfter: boolean;
- readonly asAfter: u32;
- readonly type: 'At' | 'After';
-}
-
-/** @name FrameSupportTokensMiscBalanceStatus */
-export interface FrameSupportTokensMiscBalanceStatus extends Enum {
- readonly isFree: boolean;
- readonly isReserved: boolean;
- readonly type: 'Free' | 'Reserved';
-}
-
-/** @name FrameSystemAccountInfo */
-export interface FrameSystemAccountInfo extends Struct {
- readonly nonce: u32;
- readonly consumers: u32;
- readonly providers: u32;
- readonly sufficients: u32;
- readonly data: PalletBalancesAccountData;
-}
-
-/** @name FrameSystemCall */
-export interface FrameSystemCall extends Enum {
- readonly isRemark: boolean;
- readonly asRemark: {
- readonly remark: Bytes;
- } & Struct;
- readonly isSetHeapPages: boolean;
- readonly asSetHeapPages: {
- readonly pages: u64;
- } & Struct;
- readonly isSetCode: boolean;
- readonly asSetCode: {
- readonly code: Bytes;
- } & Struct;
- readonly isSetCodeWithoutChecks: boolean;
- readonly asSetCodeWithoutChecks: {
- readonly code: Bytes;
- } & Struct;
- readonly isSetStorage: boolean;
- readonly asSetStorage: {
- readonly items: Vec<ITuple<[Bytes, Bytes]>>;
- } & Struct;
- readonly isKillStorage: boolean;
- readonly asKillStorage: {
- readonly keys_: Vec<Bytes>;
- } & Struct;
- readonly isKillPrefix: boolean;
- readonly asKillPrefix: {
- readonly prefix: Bytes;
- readonly subkeys: u32;
- } & Struct;
- readonly isRemarkWithEvent: boolean;
- readonly asRemarkWithEvent: {
- readonly remark: Bytes;
- } & Struct;
- readonly type: 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
-}
-
-/** @name FrameSystemError */
-export interface FrameSystemError extends Enum {
- readonly isInvalidSpecName: boolean;
- readonly isSpecVersionNeedsToIncrease: boolean;
- readonly isFailedToExtractRuntimeVersion: boolean;
- readonly isNonDefaultComposite: boolean;
- readonly isNonZeroRefCount: boolean;
- readonly isCallFiltered: boolean;
- readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
-}
-
-/** @name FrameSystemEvent */
-export interface FrameSystemEvent extends Enum {
- readonly isExtrinsicSuccess: boolean;
- readonly asExtrinsicSuccess: {
- readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
- } & Struct;
- readonly isExtrinsicFailed: boolean;
- readonly asExtrinsicFailed: {
- readonly dispatchError: SpRuntimeDispatchError;
- readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
- } & Struct;
- readonly isCodeUpdated: boolean;
- readonly isNewAccount: boolean;
- readonly asNewAccount: {
- readonly account: AccountId32;
- } & Struct;
- readonly isKilledAccount: boolean;
- readonly asKilledAccount: {
- readonly account: AccountId32;
- } & Struct;
- readonly isRemarked: boolean;
- readonly asRemarked: {
- readonly sender: AccountId32;
- readonly hash_: H256;
- } & Struct;
- readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked';
-}
-
-/** @name FrameSystemEventRecord */
-export interface FrameSystemEventRecord extends Struct {
- readonly phase: FrameSystemPhase;
- readonly event: Event;
- readonly topics: Vec<H256>;
-}
-
-/** @name FrameSystemExtensionsCheckGenesis */
-export interface FrameSystemExtensionsCheckGenesis extends Null {}
-
-/** @name FrameSystemExtensionsCheckNonce */
-export interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
-
-/** @name FrameSystemExtensionsCheckSpecVersion */
-export interface FrameSystemExtensionsCheckSpecVersion extends Null {}
-
-/** @name FrameSystemExtensionsCheckTxVersion */
-export interface FrameSystemExtensionsCheckTxVersion extends Null {}
-
-/** @name FrameSystemExtensionsCheckWeight */
-export interface FrameSystemExtensionsCheckWeight extends Null {}
-
-/** @name FrameSystemLastRuntimeUpgradeInfo */
-export interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
- readonly specVersion: Compact<u32>;
- readonly specName: Text;
-}
-
-/** @name FrameSystemLimitsBlockLength */
-export interface FrameSystemLimitsBlockLength extends Struct {
- readonly max: FrameSupportDispatchPerDispatchClassU32;
-}
-
-/** @name FrameSystemLimitsBlockWeights */
-export interface FrameSystemLimitsBlockWeights extends Struct {
- readonly baseBlock: SpWeightsWeightV2Weight;
- readonly maxBlock: SpWeightsWeightV2Weight;
- readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
-}
-
-/** @name FrameSystemLimitsWeightsPerClass */
-export interface FrameSystemLimitsWeightsPerClass extends Struct {
- readonly baseExtrinsic: SpWeightsWeightV2Weight;
- readonly maxExtrinsic: Option<SpWeightsWeightV2Weight>;
- readonly maxTotal: Option<SpWeightsWeightV2Weight>;
- readonly reserved: Option<SpWeightsWeightV2Weight>;
-}
-
-/** @name FrameSystemPhase */
-export interface FrameSystemPhase extends Enum {
- readonly isApplyExtrinsic: boolean;
- readonly asApplyExtrinsic: u32;
- readonly isFinalization: boolean;
- readonly isInitialization: boolean;
- readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
-}
-
-/** @name OpalRuntimeOriginCaller */
-export interface OpalRuntimeOriginCaller extends Enum {
- readonly isSystem: boolean;
- readonly asSystem: FrameSupportDispatchRawOrigin;
- readonly isVoid: boolean;
- readonly asVoid: SpCoreVoid;
- readonly isCouncil: boolean;
- readonly asCouncil: PalletCollectiveRawOrigin;
- readonly isTechnicalCommittee: boolean;
- readonly asTechnicalCommittee: PalletCollectiveRawOrigin;
- readonly isPolkadotXcm: boolean;
- readonly asPolkadotXcm: PalletXcmOrigin;
- readonly isCumulusXcm: boolean;
- readonly asCumulusXcm: CumulusPalletXcmOrigin;
- readonly isOrigins: boolean;
- readonly asOrigins: PalletGovOriginsOrigin;
- readonly isEthereum: boolean;
- readonly asEthereum: PalletEthereumRawOrigin;
- readonly type: 'System' | 'Void' | 'Council' | 'TechnicalCommittee' | 'PolkadotXcm' | 'CumulusXcm' | 'Origins' | 'Ethereum';
-}
-
-/** @name OpalRuntimeRuntime */
-export interface OpalRuntimeRuntime extends Null {}
-
-/** @name OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls */
-export interface OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls extends Null {}
-
-/** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance */
-export interface OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance extends Null {}
-
-/** @name OpalRuntimeRuntimeCommonSessionKeys */
-export interface OpalRuntimeRuntimeCommonSessionKeys extends Struct {
- readonly aura: SpConsensusAuraSr25519AppSr25519Public;
-}
-
-/** @name OpalRuntimeRuntimeHoldReason */
-export interface OpalRuntimeRuntimeHoldReason extends Enum {
- readonly isCollatorSelection: boolean;
- readonly asCollatorSelection: PalletCollatorSelectionHoldReason;
- readonly type: 'CollatorSelection';
-}
-
-/** @name OrmlTokensAccountData */
-export interface OrmlTokensAccountData extends Struct {
- readonly free: u128;
- readonly reserved: u128;
- readonly frozen: u128;
-}
-
-/** @name OrmlTokensBalanceLock */
-export interface OrmlTokensBalanceLock extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
-}
-
-/** @name OrmlTokensModuleCall */
-export interface OrmlTokensModuleCall extends Enum {
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: Compact<u128>;
- } & Struct;
- readonly isTransferAll: boolean;
- readonly asTransferAll: {
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly keepAlive: bool;
- } & Struct;
- readonly isTransferKeepAlive: boolean;
- readonly asTransferKeepAlive: {
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: Compact<u128>;
- } & Struct;
- readonly isForceTransfer: boolean;
- readonly asForceTransfer: {
- readonly source: MultiAddress;
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: Compact<u128>;
- } & Struct;
- readonly isSetBalance: boolean;
- readonly asSetBalance: {
- readonly who: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly newFree: Compact<u128>;
- readonly newReserved: Compact<u128>;
- } & Struct;
- readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance';
-}
-
-/** @name OrmlTokensModuleError */
-export interface OrmlTokensModuleError extends Enum {
- readonly isBalanceTooLow: boolean;
- readonly isAmountIntoBalanceFailed: boolean;
- readonly isLiquidityRestrictions: boolean;
- readonly isMaxLocksExceeded: boolean;
- readonly isKeepAlive: boolean;
- readonly isExistentialDeposit: boolean;
- readonly isDeadAccount: boolean;
- readonly isTooManyReserves: boolean;
- readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves';
-}
-
-/** @name OrmlTokensModuleEvent */
-export interface OrmlTokensModuleEvent extends Enum {
- readonly isEndowed: boolean;
- readonly asEndowed: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDustLost: boolean;
- readonly asDustLost: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isReserved: boolean;
- readonly asReserved: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnreserved: boolean;
- readonly asUnreserved: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isReserveRepatriated: boolean;
- readonly asReserveRepatriated: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- readonly status: FrameSupportTokensMiscBalanceStatus;
- } & Struct;
- readonly isBalanceSet: boolean;
- readonly asBalanceSet: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly free: u128;
- readonly reserved: u128;
- } & Struct;
- readonly isTotalIssuanceSet: boolean;
- readonly asTotalIssuanceSet: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- } & Struct;
- readonly isWithdrawn: boolean;
- readonly asWithdrawn: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isSlashed: boolean;
- readonly asSlashed: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly freeAmount: u128;
- readonly reservedAmount: u128;
- } & Struct;
- readonly isDeposited: boolean;
- readonly asDeposited: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isLockSet: boolean;
- readonly asLockSet: {
- readonly lockId: U8aFixed;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isLockRemoved: boolean;
- readonly asLockRemoved: {
- readonly lockId: U8aFixed;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- } & Struct;
- readonly isLocked: boolean;
- readonly asLocked: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnlocked: boolean;
- readonly asUnlocked: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isIssued: boolean;
- readonly asIssued: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- } & Struct;
- readonly isRescinded: boolean;
- readonly asRescinded: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- } & Struct;
- readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'BalanceSet' | 'TotalIssuanceSet' | 'Withdrawn' | 'Slashed' | 'Deposited' | 'LockSet' | 'LockRemoved' | 'Locked' | 'Unlocked' | 'Issued' | 'Rescinded';
-}
-
-/** @name OrmlTokensReserveData */
-export interface OrmlTokensReserveData extends Struct {
- readonly id: Null;
- readonly amount: u128;
-}
-
-/** @name OrmlVestingModuleCall */
-export interface OrmlVestingModuleCall extends Enum {
- readonly isClaim: boolean;
- readonly isVestedTransfer: boolean;
- readonly asVestedTransfer: {
- readonly dest: MultiAddress;
- readonly schedule: OrmlVestingVestingSchedule;
- } & Struct;
- readonly isUpdateVestingSchedules: boolean;
- readonly asUpdateVestingSchedules: {
- readonly who: MultiAddress;
- readonly vestingSchedules: Vec<OrmlVestingVestingSchedule>;
- } & Struct;
- readonly isClaimFor: boolean;
- readonly asClaimFor: {
- readonly dest: MultiAddress;
- } & Struct;
- readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
-}
-
-/** @name OrmlVestingModuleError */
-export interface OrmlVestingModuleError extends Enum {
- readonly isZeroVestingPeriod: boolean;
- readonly isZeroVestingPeriodCount: boolean;
- readonly isInsufficientBalanceToLock: boolean;
- readonly isTooManyVestingSchedules: boolean;
- readonly isAmountLow: boolean;
- readonly isMaxVestingSchedulesExceeded: boolean;
- readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
-}
-
-/** @name OrmlVestingModuleEvent */
-export interface OrmlVestingModuleEvent extends Enum {
- readonly isVestingScheduleAdded: boolean;
- readonly asVestingScheduleAdded: {
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly vestingSchedule: OrmlVestingVestingSchedule;
- } & Struct;
- readonly isClaimed: boolean;
- readonly asClaimed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isVestingSchedulesUpdated: boolean;
- readonly asVestingSchedulesUpdated: {
- readonly who: AccountId32;
- } & Struct;
- readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated';
-}
-
-/** @name OrmlVestingVestingSchedule */
-export interface OrmlVestingVestingSchedule extends Struct {
- readonly start: u32;
- readonly period: u32;
- readonly periodCount: u32;
- readonly perPeriod: Compact<u128>;
-}
-
-/** @name OrmlXtokensModuleCall */
-export interface OrmlXtokensModuleCall extends Enum {
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMultiasset: boolean;
- readonly asTransferMultiasset: {
- readonly asset: StagingXcmVersionedMultiAsset;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferWithFee: boolean;
- readonly asTransferWithFee: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- readonly fee: u128;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMultiassetWithFee: boolean;
- readonly asTransferMultiassetWithFee: {
- readonly asset: StagingXcmVersionedMultiAsset;
- readonly fee: StagingXcmVersionedMultiAsset;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMulticurrencies: boolean;
- readonly asTransferMulticurrencies: {
- readonly currencies: Vec<ITuple<[PalletForeignAssetsAssetId, u128]>>;
- readonly feeItem: u32;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMultiassets: boolean;
- readonly asTransferMultiassets: {
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeItem: u32;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets';
-}
-
-/** @name OrmlXtokensModuleError */
-export interface OrmlXtokensModuleError extends Enum {
- readonly isAssetHasNoReserve: boolean;
- readonly isNotCrossChainTransfer: boolean;
- readonly isInvalidDest: boolean;
- readonly isNotCrossChainTransferableCurrency: boolean;
- readonly isUnweighableMessage: boolean;
- readonly isXcmExecutionFailed: boolean;
- readonly isCannotReanchor: boolean;
- readonly isInvalidAncestry: boolean;
- readonly isInvalidAsset: boolean;
- readonly isDestinationNotInvertible: boolean;
- readonly isBadVersion: boolean;
- readonly isDistinctReserveForAssetAndFee: boolean;
- readonly isZeroFee: boolean;
- readonly isZeroAmount: boolean;
- readonly isTooManyAssetsBeingSent: boolean;
- readonly isAssetIndexNonExistent: boolean;
- readonly isFeeNotEnough: boolean;
- readonly isNotSupportedMultiLocation: boolean;
- readonly isMinXcmFeeNotDefined: boolean;
- readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined';
-}
-
-/** @name OrmlXtokensModuleEvent */
-export interface OrmlXtokensModuleEvent extends Enum {
- readonly isTransferredMultiAssets: boolean;
- readonly asTransferredMultiAssets: {
- readonly sender: AccountId32;
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly fee: StagingXcmV3MultiAsset;
- readonly dest: StagingXcmV3MultiLocation;
- } & Struct;
- readonly type: 'TransferredMultiAssets';
-}
-
-/** @name PalletAppPromotionCall */
-export interface PalletAppPromotionCall extends Enum {
- readonly isSetAdminAddress: boolean;
- readonly asSetAdminAddress: {
- readonly admin: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isStake: boolean;
- readonly asStake: {
- readonly amount: u128;
- } & Struct;
- readonly isUnstakeAll: boolean;
- readonly isSponsorCollection: boolean;
- readonly asSponsorCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isStopSponsoringCollection: boolean;
- readonly asStopSponsoringCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isSponsorContract: boolean;
- readonly asSponsorContract: {
- readonly contractId: H160;
- } & Struct;
- readonly isStopSponsoringContract: boolean;
- readonly asStopSponsoringContract: {
- readonly contractId: H160;
- } & Struct;
- readonly isPayoutStakers: boolean;
- readonly asPayoutStakers: {
- readonly stakersNumber: Option<u8>;
- } & Struct;
- readonly isUnstakePartial: boolean;
- readonly asUnstakePartial: {
- readonly amount: u128;
- } & Struct;
- readonly isForceUnstake: boolean;
- readonly asForceUnstake: {
- readonly pendingBlocks: Vec<u32>;
- } & Struct;
- readonly type: 'SetAdminAddress' | 'Stake' | 'UnstakeAll' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers' | 'UnstakePartial' | 'ForceUnstake';
-}
-
-/** @name PalletAppPromotionError */
-export interface PalletAppPromotionError extends Enum {
- readonly isAdminNotSet: boolean;
- readonly isNoPermission: boolean;
- readonly isNotSufficientFunds: boolean;
- readonly isPendingForBlockOverflow: boolean;
- readonly isSponsorNotSet: boolean;
- readonly isInsufficientStakedBalance: boolean;
- readonly isInconsistencyState: boolean;
- readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'InsufficientStakedBalance' | 'InconsistencyState';
-}
-
-/** @name PalletAppPromotionEvent */
-export interface PalletAppPromotionEvent extends Enum {
- readonly isStakingRecalculation: boolean;
- readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
- readonly isStake: boolean;
- readonly asStake: ITuple<[AccountId32, u128]>;
- readonly isUnstake: boolean;
- readonly asUnstake: ITuple<[AccountId32, u128]>;
- readonly isSetAdmin: boolean;
- readonly asSetAdmin: AccountId32;
- readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
-}
-
-/** @name PalletBalancesAccountData */
-export interface PalletBalancesAccountData extends Struct {
- readonly free: u128;
- readonly reserved: u128;
- readonly frozen: u128;
- readonly flags: u128;
-}
-
-/** @name PalletBalancesBalanceLock */
-export interface PalletBalancesBalanceLock extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
- readonly reasons: PalletBalancesReasons;
-}
-
-/** @name PalletBalancesCall */
-export interface PalletBalancesCall extends Enum {
- readonly isTransferAllowDeath: boolean;
- readonly asTransferAllowDeath: {
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isSetBalanceDeprecated: boolean;
- readonly asSetBalanceDeprecated: {
- readonly who: MultiAddress;
- readonly newFree: Compact<u128>;
- readonly oldReserved: Compact<u128>;
- } & Struct;
- readonly isForceTransfer: boolean;
- readonly asForceTransfer: {
- readonly source: MultiAddress;
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isTransferKeepAlive: boolean;
- readonly asTransferKeepAlive: {
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isTransferAll: boolean;
- readonly asTransferAll: {
- readonly dest: MultiAddress;
- readonly keepAlive: bool;
- } & Struct;
- readonly isForceUnreserve: boolean;
- readonly asForceUnreserve: {
- readonly who: MultiAddress;
- readonly amount: u128;
- } & Struct;
- readonly isUpgradeAccounts: boolean;
- readonly asUpgradeAccounts: {
- readonly who: Vec<AccountId32>;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isForceSetBalance: boolean;
- readonly asForceSetBalance: {
- readonly who: MultiAddress;
- readonly newFree: Compact<u128>;
- } & Struct;
- readonly type: 'TransferAllowDeath' | 'SetBalanceDeprecated' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve' | 'UpgradeAccounts' | 'Transfer' | 'ForceSetBalance';
-}
-
-/** @name PalletBalancesError */
-export interface PalletBalancesError extends Enum {
- readonly isVestingBalance: boolean;
- readonly isLiquidityRestrictions: boolean;
- readonly isInsufficientBalance: boolean;
- readonly isExistentialDeposit: boolean;
- readonly isExpendability: boolean;
- readonly isExistingVestingSchedule: boolean;
- readonly isDeadAccount: boolean;
- readonly isTooManyReserves: boolean;
- readonly isTooManyHolds: boolean;
- readonly isTooManyFreezes: boolean;
- readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'Expendability' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves' | 'TooManyHolds' | 'TooManyFreezes';
-}
-
-/** @name PalletBalancesEvent */
-export interface PalletBalancesEvent extends Enum {
- readonly isEndowed: boolean;
- readonly asEndowed: {
- readonly account: AccountId32;
- readonly freeBalance: u128;
- } & Struct;
- readonly isDustLost: boolean;
- readonly asDustLost: {
- readonly account: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isBalanceSet: boolean;
- readonly asBalanceSet: {
- readonly who: AccountId32;
- readonly free: u128;
- } & Struct;
- readonly isReserved: boolean;
- readonly asReserved: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnreserved: boolean;
- readonly asUnreserved: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isReserveRepatriated: boolean;
- readonly asReserveRepatriated: {
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- readonly destinationStatus: FrameSupportTokensMiscBalanceStatus;
- } & Struct;
- readonly isDeposit: boolean;
- readonly asDeposit: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isWithdraw: boolean;
- readonly asWithdraw: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isSlashed: boolean;
- readonly asSlashed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isMinted: boolean;
- readonly asMinted: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isBurned: boolean;
- readonly asBurned: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isSuspended: boolean;
- readonly asSuspended: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isRestored: boolean;
- readonly asRestored: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUpgraded: boolean;
- readonly asUpgraded: {
- readonly who: AccountId32;
- } & Struct;
- readonly isIssued: boolean;
- readonly asIssued: {
- readonly amount: u128;
- } & Struct;
- readonly isRescinded: boolean;
- readonly asRescinded: {
- readonly amount: u128;
- } & Struct;
- readonly isLocked: boolean;
- readonly asLocked: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnlocked: boolean;
- readonly asUnlocked: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isFrozen: boolean;
- readonly asFrozen: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isThawed: boolean;
- readonly asThawed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'BalanceSet' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'Deposit' | 'Withdraw' | 'Slashed' | 'Minted' | 'Burned' | 'Suspended' | 'Restored' | 'Upgraded' | 'Issued' | 'Rescinded' | 'Locked' | 'Unlocked' | 'Frozen' | 'Thawed';
-}
-
-/** @name PalletBalancesIdAmount */
-export interface PalletBalancesIdAmount extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
-}
-
-/** @name PalletBalancesReasons */
-export interface PalletBalancesReasons extends Enum {
- readonly isFee: boolean;
- readonly isMisc: boolean;
- readonly isAll: boolean;
- readonly type: 'Fee' | 'Misc' | 'All';
-}
-
-/** @name PalletBalancesReserveData */
-export interface PalletBalancesReserveData extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
-}
-
-/** @name PalletCollatorSelectionCall */
-export interface PalletCollatorSelectionCall extends Enum {
- readonly isAddInvulnerable: boolean;
- readonly asAddInvulnerable: {
- readonly new_: AccountId32;
- } & Struct;
- readonly isRemoveInvulnerable: boolean;
- readonly asRemoveInvulnerable: {
- readonly who: AccountId32;
- } & Struct;
- readonly isGetLicense: boolean;
- readonly isOnboard: boolean;
- readonly isOffboard: boolean;
- readonly isReleaseLicense: boolean;
- readonly isForceReleaseLicense: boolean;
- readonly asForceReleaseLicense: {
- readonly who: AccountId32;
- } & Struct;
- readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceReleaseLicense';
-}
-
-/** @name PalletCollatorSelectionError */
-export interface PalletCollatorSelectionError extends Enum {
- readonly isTooManyCandidates: boolean;
- readonly isUnknown: boolean;
- readonly isPermission: boolean;
- readonly isAlreadyHoldingLicense: boolean;
- readonly isNoLicense: boolean;
- readonly isAlreadyCandidate: boolean;
- readonly isNotCandidate: boolean;
- readonly isTooManyInvulnerables: boolean;
- readonly isTooFewInvulnerables: boolean;
- readonly isAlreadyInvulnerable: boolean;
- readonly isNotInvulnerable: boolean;
- readonly isNoAssociatedValidatorId: boolean;
- readonly isValidatorNotRegistered: boolean;
- readonly type: 'TooManyCandidates' | 'Unknown' | 'Permission' | 'AlreadyHoldingLicense' | 'NoLicense' | 'AlreadyCandidate' | 'NotCandidate' | 'TooManyInvulnerables' | 'TooFewInvulnerables' | 'AlreadyInvulnerable' | 'NotInvulnerable' | 'NoAssociatedValidatorId' | 'ValidatorNotRegistered';
-}
-
-/** @name PalletCollatorSelectionEvent */
-export interface PalletCollatorSelectionEvent extends Enum {
- readonly isInvulnerableAdded: boolean;
- readonly asInvulnerableAdded: {
- readonly invulnerable: AccountId32;
- } & Struct;
- readonly isInvulnerableRemoved: boolean;
- readonly asInvulnerableRemoved: {
- readonly invulnerable: AccountId32;
- } & Struct;
- readonly isLicenseObtained: boolean;
- readonly asLicenseObtained: {
- readonly accountId: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isLicenseReleased: boolean;
- readonly asLicenseReleased: {
- readonly accountId: AccountId32;
- readonly depositReturned: u128;
- } & Struct;
- readonly isCandidateAdded: boolean;
- readonly asCandidateAdded: {
- readonly accountId: AccountId32;
- } & Struct;
- readonly isCandidateRemoved: boolean;
- readonly asCandidateRemoved: {
- readonly accountId: AccountId32;
- } & Struct;
- readonly type: 'InvulnerableAdded' | 'InvulnerableRemoved' | 'LicenseObtained' | 'LicenseReleased' | 'CandidateAdded' | 'CandidateRemoved';
-}
-
-/** @name PalletCollatorSelectionHoldReason */
-export interface PalletCollatorSelectionHoldReason extends Enum {
- readonly isLicenseBond: boolean;
- readonly type: 'LicenseBond';
-}
-
-/** @name PalletCollectiveCall */
-export interface PalletCollectiveCall extends Enum {
- readonly isSetMembers: boolean;
- readonly asSetMembers: {
- readonly newMembers: Vec<AccountId32>;
- readonly prime: Option<AccountId32>;
- readonly oldCount: u32;
- } & Struct;
- readonly isExecute: boolean;
- readonly asExecute: {
- readonly proposal: Call;
- readonly lengthBound: Compact<u32>;
- } & Struct;
- readonly isPropose: boolean;
- readonly asPropose: {
- readonly threshold: Compact<u32>;
- readonly proposal: Call;
- readonly lengthBound: Compact<u32>;
- } & Struct;
- readonly isVote: boolean;
- readonly asVote: {
- readonly proposal: H256;
- readonly index: Compact<u32>;
- readonly approve: bool;
- } & Struct;
- readonly isDisapproveProposal: boolean;
- readonly asDisapproveProposal: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isClose: boolean;
- readonly asClose: {
- readonly proposalHash: H256;
- readonly index: Compact<u32>;
- readonly proposalWeightBound: SpWeightsWeightV2Weight;
- readonly lengthBound: Compact<u32>;
- } & Struct;
- readonly type: 'SetMembers' | 'Execute' | 'Propose' | 'Vote' | 'DisapproveProposal' | 'Close';
-}
-
-/** @name PalletCollectiveError */
-export interface PalletCollectiveError extends Enum {
- readonly isNotMember: boolean;
- readonly isDuplicateProposal: boolean;
- readonly isProposalMissing: boolean;
- readonly isWrongIndex: boolean;
- readonly isDuplicateVote: boolean;
- readonly isAlreadyInitialized: boolean;
- readonly isTooEarly: boolean;
- readonly isTooManyProposals: boolean;
- readonly isWrongProposalWeight: boolean;
- readonly isWrongProposalLength: boolean;
- readonly isPrimeAccountNotMember: boolean;
- readonly type: 'NotMember' | 'DuplicateProposal' | 'ProposalMissing' | 'WrongIndex' | 'DuplicateVote' | 'AlreadyInitialized' | 'TooEarly' | 'TooManyProposals' | 'WrongProposalWeight' | 'WrongProposalLength' | 'PrimeAccountNotMember';
-}
-
-/** @name PalletCollectiveEvent */
-export interface PalletCollectiveEvent extends Enum {
- readonly isProposed: boolean;
- readonly asProposed: {
- readonly account: AccountId32;
- readonly proposalIndex: u32;
- readonly proposalHash: H256;
- readonly threshold: u32;
- } & Struct;
- readonly isVoted: boolean;
- readonly asVoted: {
- readonly account: AccountId32;
- readonly proposalHash: H256;
- readonly voted: bool;
- readonly yes: u32;
- readonly no: u32;
- } & Struct;
- readonly isApproved: boolean;
- readonly asApproved: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isDisapproved: boolean;
- readonly asDisapproved: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isExecuted: boolean;
- readonly asExecuted: {
- readonly proposalHash: H256;
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isMemberExecuted: boolean;
- readonly asMemberExecuted: {
- readonly proposalHash: H256;
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isClosed: boolean;
- readonly asClosed: {
- readonly proposalHash: H256;
- readonly yes: u32;
- readonly no: u32;
- } & Struct;
- readonly type: 'Proposed' | 'Voted' | 'Approved' | 'Disapproved' | 'Executed' | 'MemberExecuted' | 'Closed';
-}
-
-/** @name PalletCollectiveRawOrigin */
-export interface PalletCollectiveRawOrigin extends Enum {
- readonly isMembers: boolean;
- readonly asMembers: ITuple<[u32, u32]>;
- readonly isMember: boolean;
- readonly asMember: AccountId32;
- readonly isPhantom: boolean;
- readonly type: 'Members' | 'Member' | 'Phantom';
-}
-
-/** @name PalletCollectiveVotes */
-export interface PalletCollectiveVotes extends Struct {
- readonly index: u32;
- readonly threshold: u32;
- readonly ayes: Vec<AccountId32>;
- readonly nays: Vec<AccountId32>;
- readonly end: u32;
-}
-
-/** @name PalletCommonError */
-export interface PalletCommonError extends Enum {
- readonly isCollectionNotFound: boolean;
- readonly isMustBeTokenOwner: boolean;
- readonly isNoPermission: boolean;
- readonly isCantDestroyNotEmptyCollection: boolean;
- readonly isPublicMintingNotAllowed: boolean;
- readonly isAddressNotInAllowlist: boolean;
- readonly isCollectionNameLimitExceeded: boolean;
- readonly isCollectionDescriptionLimitExceeded: boolean;
- readonly isCollectionTokenPrefixLimitExceeded: boolean;
- readonly isTotalCollectionsLimitExceeded: boolean;
- readonly isCollectionAdminCountExceeded: boolean;
- readonly isCollectionLimitBoundsExceeded: boolean;
- readonly isOwnerPermissionsCantBeReverted: boolean;
- readonly isTransferNotAllowed: boolean;
- readonly isAccountTokenLimitExceeded: boolean;
- readonly isCollectionTokenLimitExceeded: boolean;
- readonly isMetadataFlagFrozen: boolean;
- readonly isTokenNotFound: boolean;
- readonly isTokenValueTooLow: boolean;
- readonly isApprovedValueTooLow: boolean;
- readonly isCantApproveMoreThanOwned: boolean;
- readonly isAddressIsNotEthMirror: boolean;
- readonly isAddressIsZero: boolean;
- readonly isUnsupportedOperation: boolean;
- readonly isNotSufficientFounds: boolean;
- readonly isUserIsNotAllowedToNest: boolean;
- readonly isSourceCollectionIsNotAllowedToNest: boolean;
- readonly isCollectionFieldSizeExceeded: boolean;
- readonly isNoSpaceForProperty: boolean;
- readonly isPropertyLimitReached: boolean;
- readonly isPropertyKeyIsTooLong: boolean;
- readonly isInvalidCharacterInPropertyKey: boolean;
- readonly isEmptyPropertyKey: boolean;
- readonly isCollectionIsExternal: boolean;
- readonly isCollectionIsInternal: boolean;
- readonly isConfirmSponsorshipFail: boolean;
- readonly isUserIsNotCollectionAdmin: boolean;
- readonly isFungibleItemsHaveNoId: boolean;
- readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsNotEthMirror' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin' | 'FungibleItemsHaveNoId';
-}
-
-/** @name PalletCommonEvent */
-export interface PalletCommonEvent extends Enum {
- readonly isCollectionCreated: boolean;
- readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
- readonly isCollectionDestroyed: boolean;
- readonly asCollectionDestroyed: u32;
- readonly isItemCreated: boolean;
- readonly asItemCreated: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isItemDestroyed: boolean;
- readonly asItemDestroyed: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isTransfer: boolean;
- readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isApproved: boolean;
- readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isApprovedForAll: boolean;
- readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
- readonly isCollectionPropertySet: boolean;
- readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
- readonly isCollectionPropertyDeleted: boolean;
- readonly asCollectionPropertyDeleted: ITuple<[u32, Bytes]>;
- readonly isTokenPropertySet: boolean;
- readonly asTokenPropertySet: ITuple<[u32, u32, Bytes]>;
- readonly isTokenPropertyDeleted: boolean;
- readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
- readonly isPropertyPermissionSet: boolean;
- readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
- readonly isAllowListAddressAdded: boolean;
- readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isAllowListAddressRemoved: boolean;
- readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isCollectionAdminAdded: boolean;
- readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isCollectionAdminRemoved: boolean;
- readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isCollectionLimitSet: boolean;
- readonly asCollectionLimitSet: u32;
- readonly isCollectionOwnerChanged: boolean;
- readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>;
- readonly isCollectionPermissionSet: boolean;
- readonly asCollectionPermissionSet: u32;
- readonly isCollectionSponsorSet: boolean;
- readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
- readonly isSponsorshipConfirmed: boolean;
- readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
- readonly isCollectionSponsorRemoved: boolean;
- readonly asCollectionSponsorRemoved: u32;
- readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved';
-}
-
-/** @name PalletConfigurationAppPromotionConfiguration */
-export interface PalletConfigurationAppPromotionConfiguration extends Struct {
- readonly recalculationInterval: Option<u32>;
- readonly pendingInterval: Option<u32>;
- readonly intervalIncome: Option<Perbill>;
- readonly maxStakersPerCalculation: Option<u8>;
-}
-
-/** @name PalletConfigurationCall */
-export interface PalletConfigurationCall extends Enum {
- readonly isSetWeightToFeeCoefficientOverride: boolean;
- readonly asSetWeightToFeeCoefficientOverride: {
- readonly coeff: Option<u64>;
- } & Struct;
- readonly isSetMinGasPriceOverride: boolean;
- readonly asSetMinGasPriceOverride: {
- readonly coeff: Option<u64>;
- } & Struct;
- readonly isSetAppPromotionConfigurationOverride: boolean;
- readonly asSetAppPromotionConfigurationOverride: {
- readonly configuration: PalletConfigurationAppPromotionConfiguration;
- } & Struct;
- readonly isSetCollatorSelectionDesiredCollators: boolean;
- readonly asSetCollatorSelectionDesiredCollators: {
- readonly max: Option<u32>;
- } & Struct;
- readonly isSetCollatorSelectionLicenseBond: boolean;
- readonly asSetCollatorSelectionLicenseBond: {
- readonly amount: Option<u128>;
- } & Struct;
- readonly isSetCollatorSelectionKickThreshold: boolean;
- readonly asSetCollatorSelectionKickThreshold: {
- readonly threshold: Option<u32>;
- } & Struct;
- readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride' | 'SetAppPromotionConfigurationOverride' | 'SetCollatorSelectionDesiredCollators' | 'SetCollatorSelectionLicenseBond' | 'SetCollatorSelectionKickThreshold';
-}
-
-/** @name PalletConfigurationError */
-export interface PalletConfigurationError extends Enum {
- readonly isInconsistentConfiguration: boolean;
- readonly type: 'InconsistentConfiguration';
-}
-
-/** @name PalletConfigurationEvent */
-export interface PalletConfigurationEvent extends Enum {
- readonly isNewDesiredCollators: boolean;
- readonly asNewDesiredCollators: {
- readonly desiredCollators: Option<u32>;
- } & Struct;
- readonly isNewCollatorLicenseBond: boolean;
- readonly asNewCollatorLicenseBond: {
- readonly bondCost: Option<u128>;
- } & Struct;
- readonly isNewCollatorKickThreshold: boolean;
- readonly asNewCollatorKickThreshold: {
- readonly lengthInBlocks: Option<u32>;
- } & Struct;
- readonly type: 'NewDesiredCollators' | 'NewCollatorLicenseBond' | 'NewCollatorKickThreshold';
-}
-
-/** @name PalletDemocracyCall */
-export interface PalletDemocracyCall extends Enum {
- readonly isPropose: boolean;
- readonly asPropose: {
- readonly proposal: FrameSupportPreimagesBounded;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isSecond: boolean;
- readonly asSecond: {
- readonly proposal: Compact<u32>;
- } & Struct;
- readonly isVote: boolean;
- readonly asVote: {
- readonly refIndex: Compact<u32>;
- readonly vote: PalletDemocracyVoteAccountVote;
- } & Struct;
- readonly isEmergencyCancel: boolean;
- readonly asEmergencyCancel: {
- readonly refIndex: u32;
- } & Struct;
- readonly isExternalPropose: boolean;
- readonly asExternalPropose: {
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isExternalProposeMajority: boolean;
- readonly asExternalProposeMajority: {
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isExternalProposeDefault: boolean;
- readonly asExternalProposeDefault: {
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isFastTrack: boolean;
- readonly asFastTrack: {
- readonly proposalHash: H256;
- readonly votingPeriod: u32;
- readonly delay: u32;
- } & Struct;
- readonly isVetoExternal: boolean;
- readonly asVetoExternal: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isCancelReferendum: boolean;
- readonly asCancelReferendum: {
- readonly refIndex: Compact<u32>;
- } & Struct;
- readonly isDelegate: boolean;
- readonly asDelegate: {
- readonly to: MultiAddress;
- readonly conviction: PalletDemocracyConviction;
- readonly balance: u128;
- } & Struct;
- readonly isUndelegate: boolean;
- readonly isClearPublicProposals: boolean;
- readonly isUnlock: boolean;
- readonly asUnlock: {
- readonly target: MultiAddress;
- } & Struct;
- readonly isRemoveVote: boolean;
- readonly asRemoveVote: {
- readonly index: u32;
- } & Struct;
- readonly isRemoveOtherVote: boolean;
- readonly asRemoveOtherVote: {
- readonly target: MultiAddress;
- readonly index: u32;
- } & Struct;
- readonly isBlacklist: boolean;
- readonly asBlacklist: {
- readonly proposalHash: H256;
- readonly maybeRefIndex: Option<u32>;
- } & Struct;
- readonly isCancelProposal: boolean;
- readonly asCancelProposal: {
- readonly propIndex: Compact<u32>;
- } & Struct;
- readonly isSetMetadata: boolean;
- readonly asSetMetadata: {
- readonly owner: PalletDemocracyMetadataOwner;
- readonly maybeHash: Option<H256>;
- } & Struct;
- readonly type: 'Propose' | 'Second' | 'Vote' | 'EmergencyCancel' | 'ExternalPropose' | 'ExternalProposeMajority' | 'ExternalProposeDefault' | 'FastTrack' | 'VetoExternal' | 'CancelReferendum' | 'Delegate' | 'Undelegate' | 'ClearPublicProposals' | 'Unlock' | 'RemoveVote' | 'RemoveOtherVote' | 'Blacklist' | 'CancelProposal' | 'SetMetadata';
-}
-
-/** @name PalletDemocracyConviction */
-export interface PalletDemocracyConviction extends Enum {
- readonly isNone: boolean;
- readonly isLocked1x: boolean;
- readonly isLocked2x: boolean;
- readonly isLocked3x: boolean;
- readonly isLocked4x: boolean;
- readonly isLocked5x: boolean;
- readonly isLocked6x: boolean;
- readonly type: 'None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x' | 'Locked6x';
-}
-
-/** @name PalletDemocracyDelegations */
-export interface PalletDemocracyDelegations extends Struct {
- readonly votes: u128;
- readonly capital: u128;
-}
-
-/** @name PalletDemocracyError */
-export interface PalletDemocracyError extends Enum {
- readonly isValueLow: boolean;
- readonly isProposalMissing: boolean;
- readonly isAlreadyCanceled: boolean;
- readonly isDuplicateProposal: boolean;
- readonly isProposalBlacklisted: boolean;
- readonly isNotSimpleMajority: boolean;
- readonly isInvalidHash: boolean;
- readonly isNoProposal: boolean;
- readonly isAlreadyVetoed: boolean;
- readonly isReferendumInvalid: boolean;
- readonly isNoneWaiting: boolean;
- readonly isNotVoter: boolean;
- readonly isNoPermission: boolean;
- readonly isAlreadyDelegating: boolean;
- readonly isInsufficientFunds: boolean;
- readonly isNotDelegating: boolean;
- readonly isVotesExist: boolean;
- readonly isInstantNotAllowed: boolean;
- readonly isNonsense: boolean;
- readonly isWrongUpperBound: boolean;
- readonly isMaxVotesReached: boolean;
- readonly isTooMany: boolean;
- readonly isVotingPeriodLow: boolean;
- readonly isPreimageNotExist: boolean;
- readonly type: 'ValueLow' | 'ProposalMissing' | 'AlreadyCanceled' | 'DuplicateProposal' | 'ProposalBlacklisted' | 'NotSimpleMajority' | 'InvalidHash' | 'NoProposal' | 'AlreadyVetoed' | 'ReferendumInvalid' | 'NoneWaiting' | 'NotVoter' | 'NoPermission' | 'AlreadyDelegating' | 'InsufficientFunds' | 'NotDelegating' | 'VotesExist' | 'InstantNotAllowed' | 'Nonsense' | 'WrongUpperBound' | 'MaxVotesReached' | 'TooMany' | 'VotingPeriodLow' | 'PreimageNotExist';
-}
-
-/** @name PalletDemocracyEvent */
-export interface PalletDemocracyEvent extends Enum {
- readonly isProposed: boolean;
- readonly asProposed: {
- readonly proposalIndex: u32;
- readonly deposit: u128;
- } & Struct;
- readonly isTabled: boolean;
- readonly asTabled: {
- readonly proposalIndex: u32;
- readonly deposit: u128;
- } & Struct;
- readonly isExternalTabled: boolean;
- readonly isStarted: boolean;
- readonly asStarted: {
- readonly refIndex: u32;
- readonly threshold: PalletDemocracyVoteThreshold;
- } & Struct;
- readonly isPassed: boolean;
- readonly asPassed: {
- readonly refIndex: u32;
- } & Struct;
- readonly isNotPassed: boolean;
- readonly asNotPassed: {
- readonly refIndex: u32;
- } & Struct;
- readonly isCancelled: boolean;
- readonly asCancelled: {
- readonly refIndex: u32;
- } & Struct;
- readonly isDelegated: boolean;
- readonly asDelegated: {
- readonly who: AccountId32;
- readonly target: AccountId32;
- } & Struct;
- readonly isUndelegated: boolean;
- readonly asUndelegated: {
- readonly account: AccountId32;
- } & Struct;
- readonly isVetoed: boolean;
- readonly asVetoed: {
- readonly who: AccountId32;
- readonly proposalHash: H256;
- readonly until: u32;
- } & Struct;
- readonly isBlacklisted: boolean;
- readonly asBlacklisted: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isVoted: boolean;
- readonly asVoted: {
- readonly voter: AccountId32;
- readonly refIndex: u32;
- readonly vote: PalletDemocracyVoteAccountVote;
- } & Struct;
- readonly isSeconded: boolean;
- readonly asSeconded: {
- readonly seconder: AccountId32;
- readonly propIndex: u32;
- } & Struct;
- readonly isProposalCanceled: boolean;
- readonly asProposalCanceled: {
- readonly propIndex: u32;
- } & Struct;
- readonly isMetadataSet: boolean;
- readonly asMetadataSet: {
- readonly owner: PalletDemocracyMetadataOwner;
- readonly hash_: H256;
- } & Struct;
- readonly isMetadataCleared: boolean;
- readonly asMetadataCleared: {
- readonly owner: PalletDemocracyMetadataOwner;
- readonly hash_: H256;
- } & Struct;
- readonly isMetadataTransferred: boolean;
- readonly asMetadataTransferred: {
- readonly prevOwner: PalletDemocracyMetadataOwner;
- readonly owner: PalletDemocracyMetadataOwner;
- readonly hash_: H256;
- } & Struct;
- readonly type: 'Proposed' | 'Tabled' | 'ExternalTabled' | 'Started' | 'Passed' | 'NotPassed' | 'Cancelled' | 'Delegated' | 'Undelegated' | 'Vetoed' | 'Blacklisted' | 'Voted' | 'Seconded' | 'ProposalCanceled' | 'MetadataSet' | 'MetadataCleared' | 'MetadataTransferred';
-}
-
-/** @name PalletDemocracyMetadataOwner */
-export interface PalletDemocracyMetadataOwner extends Enum {
- readonly isExternal: boolean;
- readonly isProposal: boolean;
- readonly asProposal: u32;
- readonly isReferendum: boolean;
- readonly asReferendum: u32;
- readonly type: 'External' | 'Proposal' | 'Referendum';
-}
-
-/** @name PalletDemocracyReferendumInfo */
-export interface PalletDemocracyReferendumInfo extends Enum {
- readonly isOngoing: boolean;
- readonly asOngoing: PalletDemocracyReferendumStatus;
- readonly isFinished: boolean;
- readonly asFinished: {
- readonly approved: bool;
- readonly end: u32;
- } & Struct;
- readonly type: 'Ongoing' | 'Finished';
-}
-
-/** @name PalletDemocracyReferendumStatus */
-export interface PalletDemocracyReferendumStatus extends Struct {
- readonly end: u32;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly threshold: PalletDemocracyVoteThreshold;
- readonly delay: u32;
- readonly tally: PalletDemocracyTally;
-}
-
-/** @name PalletDemocracyTally */
-export interface PalletDemocracyTally extends Struct {
- readonly ayes: u128;
- readonly nays: u128;
- readonly turnout: u128;
-}
-
-/** @name PalletDemocracyVoteAccountVote */
-export interface PalletDemocracyVoteAccountVote extends Enum {
- readonly isStandard: boolean;
- readonly asStandard: {
- readonly vote: Vote;
- readonly balance: u128;
- } & Struct;
- readonly isSplit: boolean;
- readonly asSplit: {
- readonly aye: u128;
- readonly nay: u128;
- } & Struct;
- readonly type: 'Standard' | 'Split';
-}
-
-/** @name PalletDemocracyVotePriorLock */
-export interface PalletDemocracyVotePriorLock extends ITuple<[u32, u128]> {}
-
-/** @name PalletDemocracyVoteThreshold */
-export interface PalletDemocracyVoteThreshold extends Enum {
- readonly isSuperMajorityApprove: boolean;
- readonly isSuperMajorityAgainst: boolean;
- readonly isSimpleMajority: boolean;
- readonly type: 'SuperMajorityApprove' | 'SuperMajorityAgainst' | 'SimpleMajority';
-}
-
-/** @name PalletDemocracyVoteVoting */
-export interface PalletDemocracyVoteVoting extends Enum {
- readonly isDirect: boolean;
- readonly asDirect: {
- readonly votes: Vec<ITuple<[u32, PalletDemocracyVoteAccountVote]>>;
- readonly delegations: PalletDemocracyDelegations;
- readonly prior: PalletDemocracyVotePriorLock;
- } & Struct;
- readonly isDelegating: boolean;
- readonly asDelegating: {
- readonly balance: u128;
- readonly target: AccountId32;
- readonly conviction: PalletDemocracyConviction;
- readonly delegations: PalletDemocracyDelegations;
- readonly prior: PalletDemocracyVotePriorLock;
- } & Struct;
- readonly type: 'Direct' | 'Delegating';
-}
-
-/** @name PalletEthereumCall */
-export interface PalletEthereumCall extends Enum {
- readonly isTransact: boolean;
- readonly asTransact: {
- readonly transaction: EthereumTransactionTransactionV2;
- } & Struct;
- readonly type: 'Transact';
-}
-
-/** @name PalletEthereumError */
-export interface PalletEthereumError extends Enum {
- readonly isInvalidSignature: boolean;
- readonly isPreLogExists: boolean;
- readonly type: 'InvalidSignature' | 'PreLogExists';
-}
-
-/** @name PalletEthereumEvent */
-export interface PalletEthereumEvent extends Enum {
- readonly isExecuted: boolean;
- readonly asExecuted: {
- readonly from: H160;
- readonly to: H160;
- readonly transactionHash: H256;
- readonly exitReason: EvmCoreErrorExitReason;
- readonly extraData: Bytes;
- } & Struct;
- readonly type: 'Executed';
-}
-
-/** @name PalletEthereumFakeTransactionFinalizer */
-export interface PalletEthereumFakeTransactionFinalizer extends Null {}
-
-/** @name PalletEthereumRawOrigin */
-export interface PalletEthereumRawOrigin extends Enum {
- readonly isEthereumTransaction: boolean;
- readonly asEthereumTransaction: H160;
- readonly type: 'EthereumTransaction';
-}
-
-/** @name PalletEvmAccountBasicCrossAccountIdRepr */
-export interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
- readonly isSubstrate: boolean;
- readonly asSubstrate: AccountId32;
- readonly isEthereum: boolean;
- readonly asEthereum: H160;
- readonly type: 'Substrate' | 'Ethereum';
-}
-
-/** @name PalletEvmCall */
-export interface PalletEvmCall extends Enum {
- readonly isWithdraw: boolean;
- readonly asWithdraw: {
- readonly address: H160;
- readonly value: u128;
- } & Struct;
- readonly isCall: boolean;
- readonly asCall: {
- readonly source: H160;
- readonly target: H160;
- readonly input: Bytes;
- readonly value: U256;
- readonly gasLimit: u64;
- readonly maxFeePerGas: U256;
- readonly maxPriorityFeePerGas: Option<U256>;
- readonly nonce: Option<U256>;
- readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
- } & Struct;
- readonly isCreate: boolean;
- readonly asCreate: {
- readonly source: H160;
- readonly init: Bytes;
- readonly value: U256;
- readonly gasLimit: u64;
- readonly maxFeePerGas: U256;
- readonly maxPriorityFeePerGas: Option<U256>;
- readonly nonce: Option<U256>;
- readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
- } & Struct;
- readonly isCreate2: boolean;
- readonly asCreate2: {
- readonly source: H160;
- readonly init: Bytes;
- readonly salt: H256;
- readonly value: U256;
- readonly gasLimit: u64;
- readonly maxFeePerGas: U256;
- readonly maxPriorityFeePerGas: Option<U256>;
- readonly nonce: Option<U256>;
- readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
- } & Struct;
- readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
-}
-
-/** @name PalletEvmCodeMetadata */
-export interface PalletEvmCodeMetadata extends Struct {
- readonly size_: u64;
- readonly hash_: H256;
-}
-
-/** @name PalletEvmCoderSubstrateError */
-export interface PalletEvmCoderSubstrateError extends Enum {
- readonly isOutOfGas: boolean;
- readonly isOutOfFund: boolean;
- readonly type: 'OutOfGas' | 'OutOfFund';
-}
-
-/** @name PalletEvmContractHelpersCall */
-export interface PalletEvmContractHelpersCall extends Enum {
- readonly isMigrateFromSelfSponsoring: boolean;
- readonly asMigrateFromSelfSponsoring: {
- readonly addresses: Vec<H160>;
- } & Struct;
- readonly type: 'MigrateFromSelfSponsoring';
-}
-
-/** @name PalletEvmContractHelpersError */
-export interface PalletEvmContractHelpersError extends Enum {
- readonly isNoPermission: boolean;
- readonly isNoPendingSponsor: boolean;
- readonly isTooManyMethodsHaveSponsoredLimit: boolean;
- readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
-}
-
-/** @name PalletEvmContractHelpersEvent */
-export interface PalletEvmContractHelpersEvent extends Enum {
- readonly isContractSponsorSet: boolean;
- readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
- readonly isContractSponsorshipConfirmed: boolean;
- readonly asContractSponsorshipConfirmed: ITuple<[H160, AccountId32]>;
- readonly isContractSponsorRemoved: boolean;
- readonly asContractSponsorRemoved: H160;
- readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
-}
-
-/** @name PalletEvmContractHelpersSponsoringModeT */
-export interface PalletEvmContractHelpersSponsoringModeT extends Enum {
- readonly isDisabled: boolean;
- readonly isAllowlisted: boolean;
- readonly isGenerous: boolean;
- readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
-}
-
-/** @name PalletEvmError */
-export interface PalletEvmError extends Enum {
- readonly isBalanceLow: boolean;
- readonly isFeeOverflow: boolean;
- readonly isPaymentOverflow: boolean;
- readonly isWithdrawFailed: boolean;
- readonly isGasPriceTooLow: boolean;
- readonly isInvalidNonce: boolean;
- readonly isGasLimitTooLow: boolean;
- readonly isGasLimitTooHigh: boolean;
- readonly isUndefined: boolean;
- readonly isReentrancy: boolean;
- readonly isTransactionMustComeFromEOA: boolean;
- readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA';
-}
-
-/** @name PalletEvmEvent */
-export interface PalletEvmEvent extends Enum {
- readonly isLog: boolean;
- readonly asLog: {
- readonly log: EthereumLog;
- } & Struct;
- readonly isCreated: boolean;
- readonly asCreated: {
- readonly address: H160;
- } & Struct;
- readonly isCreatedFailed: boolean;
- readonly asCreatedFailed: {
- readonly address: H160;
- } & Struct;
- readonly isExecuted: boolean;
- readonly asExecuted: {
- readonly address: H160;
- } & Struct;
- readonly isExecutedFailed: boolean;
- readonly asExecutedFailed: {
- readonly address: H160;
- } & Struct;
- readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
-}
-
-/** @name PalletEvmMigrationCall */
-export interface PalletEvmMigrationCall extends Enum {
- readonly isBegin: boolean;
- readonly asBegin: {
- readonly address: H160;
- } & Struct;
- readonly isSetData: boolean;
- readonly asSetData: {
- readonly address: H160;
- readonly data: Vec<ITuple<[H256, H256]>>;
- } & Struct;
- readonly isFinish: boolean;
- readonly asFinish: {
- readonly address: H160;
- readonly code: Bytes;
- } & Struct;
- readonly isInsertEthLogs: boolean;
- readonly asInsertEthLogs: {
- readonly logs: Vec<EthereumLog>;
- } & Struct;
- readonly isInsertEvents: boolean;
- readonly asInsertEvents: {
- readonly events: Vec<Bytes>;
- } & Struct;
- readonly isRemoveRmrkData: boolean;
- readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents' | 'RemoveRmrkData';
-}
-
-/** @name PalletEvmMigrationError */
-export interface PalletEvmMigrationError extends Enum {
- readonly isAccountNotEmpty: boolean;
- readonly isAccountIsNotMigrating: boolean;
- readonly isBadEvent: boolean;
- readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
-}
-
-/** @name PalletEvmMigrationEvent */
-export interface PalletEvmMigrationEvent extends Enum {
- readonly isTestEvent: boolean;
- readonly type: 'TestEvent';
-}
-
-/** @name PalletForeignAssetsAssetId */
-export interface PalletForeignAssetsAssetId extends Enum {
- readonly isForeignAssetId: boolean;
- readonly asForeignAssetId: u32;
- readonly isNativeAssetId: boolean;
- readonly asNativeAssetId: PalletForeignAssetsNativeCurrency;
- readonly type: 'ForeignAssetId' | 'NativeAssetId';
-}
-
-/** @name PalletForeignAssetsModuleAssetMetadata */
-export interface PalletForeignAssetsModuleAssetMetadata extends Struct {
- readonly name: Bytes;
- readonly symbol: Bytes;
- readonly decimals: u8;
- readonly minimalBalance: u128;
-}
-
-/** @name PalletForeignAssetsModuleCall */
-export interface PalletForeignAssetsModuleCall extends Enum {
- readonly isRegisterForeignAsset: boolean;
- readonly asRegisterForeignAsset: {
- readonly owner: AccountId32;
- readonly location: StagingXcmVersionedMultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isUpdateForeignAsset: boolean;
- readonly asUpdateForeignAsset: {
- readonly foreignAssetId: u32;
- readonly location: StagingXcmVersionedMultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset';
-}
-
-/** @name PalletForeignAssetsModuleError */
-export interface PalletForeignAssetsModuleError extends Enum {
- readonly isBadLocation: boolean;
- readonly isMultiLocationExisted: boolean;
- readonly isAssetIdNotExists: boolean;
- readonly isAssetIdExisted: boolean;
- readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
-}
-
-/** @name PalletForeignAssetsModuleEvent */
-export interface PalletForeignAssetsModuleEvent extends Enum {
- readonly isForeignAssetRegistered: boolean;
- readonly asForeignAssetRegistered: {
- readonly assetId: u32;
- readonly assetAddress: StagingXcmV3MultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isForeignAssetUpdated: boolean;
- readonly asForeignAssetUpdated: {
- readonly assetId: u32;
- readonly assetAddress: StagingXcmV3MultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isAssetRegistered: boolean;
- readonly asAssetRegistered: {
- readonly assetId: PalletForeignAssetsAssetId;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isAssetUpdated: boolean;
- readonly asAssetUpdated: {
- readonly assetId: PalletForeignAssetsAssetId;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated';
-}
-
-/** @name PalletForeignAssetsNativeCurrency */
-export interface PalletForeignAssetsNativeCurrency extends Enum {
- readonly isHere: boolean;
- readonly isParent: boolean;
- readonly type: 'Here' | 'Parent';
-}
-
-/** @name PalletFungibleError */
-export interface PalletFungibleError extends Enum {
- readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
- readonly isFungibleItemsDontHaveData: boolean;
- readonly isFungibleDisallowsNesting: boolean;
- readonly isSettingPropertiesNotAllowed: boolean;
- readonly isSettingAllowanceForAllNotAllowed: boolean;
- readonly isFungibleTokensAreAlwaysValid: boolean;
- readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid';
-}
-
-/** @name PalletGovOriginsOrigin */
-export interface PalletGovOriginsOrigin extends Enum {
- readonly isFellowshipProposition: boolean;
- readonly type: 'FellowshipProposition';
-}
-
-/** @name PalletIdentityBitFlags */
-export interface PalletIdentityBitFlags extends Struct {
- readonly _bitLength: 64;
- readonly Display: 1;
- readonly Legal: 2;
- readonly Web: 4;
- readonly Riot: 8;
- readonly Email: 16;
- readonly PgpFingerprint: 32;
- readonly Image: 64;
- readonly Twitter: 128;
-}
-
-/** @name PalletIdentityCall */
-export interface PalletIdentityCall extends Enum {
- readonly isAddRegistrar: boolean;
- readonly asAddRegistrar: {
- readonly account: MultiAddress;
- } & Struct;
- readonly isSetIdentity: boolean;
- readonly asSetIdentity: {
- readonly info: PalletIdentityIdentityInfo;
- } & Struct;
- readonly isSetSubs: boolean;
- readonly asSetSubs: {
- readonly subs: Vec<ITuple<[AccountId32, Data]>>;
- } & Struct;
- readonly isClearIdentity: boolean;
- readonly isRequestJudgement: boolean;
- readonly asRequestJudgement: {
- readonly regIndex: Compact<u32>;
- readonly maxFee: Compact<u128>;
- } & Struct;
- readonly isCancelRequest: boolean;
- readonly asCancelRequest: {
- readonly regIndex: u32;
- } & Struct;
- readonly isSetFee: boolean;
- readonly asSetFee: {
- readonly index: Compact<u32>;
- readonly fee: Compact<u128>;
- } & Struct;
- readonly isSetAccountId: boolean;
- readonly asSetAccountId: {
- readonly index: Compact<u32>;
- readonly new_: MultiAddress;
- } & Struct;
- readonly isSetFields: boolean;
- readonly asSetFields: {
- readonly index: Compact<u32>;
- readonly fields: PalletIdentityBitFlags;
- } & Struct;
- readonly isProvideJudgement: boolean;
- readonly asProvideJudgement: {
- readonly regIndex: Compact<u32>;
- readonly target: MultiAddress;
- readonly judgement: PalletIdentityJudgement;
- readonly identity: H256;
- } & Struct;
- readonly isKillIdentity: boolean;
- readonly asKillIdentity: {
- readonly target: MultiAddress;
- } & Struct;
- readonly isAddSub: boolean;
- readonly asAddSub: {
- readonly sub: MultiAddress;
- readonly data: Data;
- } & Struct;
- readonly isRenameSub: boolean;
- readonly asRenameSub: {
- readonly sub: MultiAddress;
- readonly data: Data;
- } & Struct;
- readonly isRemoveSub: boolean;
- readonly asRemoveSub: {
- readonly sub: MultiAddress;
- } & Struct;
- readonly isQuitSub: boolean;
- readonly isForceInsertIdentities: boolean;
- readonly asForceInsertIdentities: {
- readonly identities: Vec<ITuple<[AccountId32, PalletIdentityRegistration]>>;
- } & Struct;
- readonly isForceRemoveIdentities: boolean;
- readonly asForceRemoveIdentities: {
- readonly identities: Vec<AccountId32>;
- } & Struct;
- readonly isForceSetSubs: boolean;
- readonly asForceSetSubs: {
- readonly subs: Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>>;
- } & Struct;
- readonly type: 'AddRegistrar' | 'SetIdentity' | 'SetSubs' | 'ClearIdentity' | 'RequestJudgement' | 'CancelRequest' | 'SetFee' | 'SetAccountId' | 'SetFields' | 'ProvideJudgement' | 'KillIdentity' | 'AddSub' | 'RenameSub' | 'RemoveSub' | 'QuitSub' | 'ForceInsertIdentities' | 'ForceRemoveIdentities' | 'ForceSetSubs';
-}
-
-/** @name PalletIdentityError */
-export interface PalletIdentityError extends Enum {
- readonly isTooManySubAccounts: boolean;
- readonly isNotFound: boolean;
- readonly isNotNamed: boolean;
- readonly isEmptyIndex: boolean;
- readonly isFeeChanged: boolean;
- readonly isNoIdentity: boolean;
- readonly isStickyJudgement: boolean;
- readonly isJudgementGiven: boolean;
- readonly isInvalidJudgement: boolean;
- readonly isInvalidIndex: boolean;
- readonly isInvalidTarget: boolean;
- readonly isTooManyFields: boolean;
- readonly isTooManyRegistrars: boolean;
- readonly isAlreadyClaimed: boolean;
- readonly isNotSub: boolean;
- readonly isNotOwned: boolean;
- readonly isJudgementForDifferentIdentity: boolean;
- readonly isJudgementPaymentFailed: boolean;
- readonly type: 'TooManySubAccounts' | 'NotFound' | 'NotNamed' | 'EmptyIndex' | 'FeeChanged' | 'NoIdentity' | 'StickyJudgement' | 'JudgementGiven' | 'InvalidJudgement' | 'InvalidIndex' | 'InvalidTarget' | 'TooManyFields' | 'TooManyRegistrars' | 'AlreadyClaimed' | 'NotSub' | 'NotOwned' | 'JudgementForDifferentIdentity' | 'JudgementPaymentFailed';
-}
-
-/** @name PalletIdentityEvent */
-export interface PalletIdentityEvent extends Enum {
- readonly isIdentitySet: boolean;
- readonly asIdentitySet: {
- readonly who: AccountId32;
- } & Struct;
- readonly isIdentityCleared: boolean;
- readonly asIdentityCleared: {
- readonly who: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isIdentityKilled: boolean;
- readonly asIdentityKilled: {
- readonly who: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isIdentitiesInserted: boolean;
- readonly asIdentitiesInserted: {
- readonly amount: u32;
- } & Struct;
- readonly isIdentitiesRemoved: boolean;
- readonly asIdentitiesRemoved: {
- readonly amount: u32;
- } & Struct;
- readonly isJudgementRequested: boolean;
- readonly asJudgementRequested: {
- readonly who: AccountId32;
- readonly registrarIndex: u32;
- } & Struct;
- readonly isJudgementUnrequested: boolean;
- readonly asJudgementUnrequested: {
- readonly who: AccountId32;
- readonly registrarIndex: u32;
- } & Struct;
- readonly isJudgementGiven: boolean;
- readonly asJudgementGiven: {
- readonly target: AccountId32;
- readonly registrarIndex: u32;
- } & Struct;
- readonly isRegistrarAdded: boolean;
- readonly asRegistrarAdded: {
- readonly registrarIndex: u32;
- } & Struct;
- readonly isSubIdentityAdded: boolean;
- readonly asSubIdentityAdded: {
- readonly sub: AccountId32;
- readonly main: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isSubIdentityRemoved: boolean;
- readonly asSubIdentityRemoved: {
- readonly sub: AccountId32;
- readonly main: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isSubIdentityRevoked: boolean;
- readonly asSubIdentityRevoked: {
- readonly sub: AccountId32;
- readonly main: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isSubIdentitiesInserted: boolean;
- readonly asSubIdentitiesInserted: {
- readonly amount: u32;
- } & Struct;
- readonly type: 'IdentitySet' | 'IdentityCleared' | 'IdentityKilled' | 'IdentitiesInserted' | 'IdentitiesRemoved' | 'JudgementRequested' | 'JudgementUnrequested' | 'JudgementGiven' | 'RegistrarAdded' | 'SubIdentityAdded' | 'SubIdentityRemoved' | 'SubIdentityRevoked' | 'SubIdentitiesInserted';
-}
-
-/** @name PalletIdentityIdentityField */
-export interface PalletIdentityIdentityField extends Enum {
- readonly isDisplay: boolean;
- readonly isLegal: boolean;
- readonly isWeb: boolean;
- readonly isRiot: boolean;
- readonly isEmail: boolean;
- readonly isPgpFingerprint: boolean;
- readonly isImage: boolean;
- readonly isTwitter: boolean;
- readonly type: 'Display' | 'Legal' | 'Web' | 'Riot' | 'Email' | 'PgpFingerprint' | 'Image' | 'Twitter';
-}
-
-/** @name PalletIdentityIdentityInfo */
-export interface PalletIdentityIdentityInfo extends Struct {
- readonly additional: Vec<ITuple<[Data, Data]>>;
- readonly display: Data;
- readonly legal: Data;
- readonly web: Data;
- readonly riot: Data;
- readonly email: Data;
- readonly pgpFingerprint: Option<U8aFixed>;
- readonly image: Data;
- readonly twitter: Data;
-}
-
-/** @name PalletIdentityJudgement */
-export interface PalletIdentityJudgement extends Enum {
- readonly isUnknown: boolean;
- readonly isFeePaid: boolean;
- readonly asFeePaid: u128;
- readonly isReasonable: boolean;
- readonly isKnownGood: boolean;
- readonly isOutOfDate: boolean;
- readonly isLowQuality: boolean;
- readonly isErroneous: boolean;
- readonly type: 'Unknown' | 'FeePaid' | 'Reasonable' | 'KnownGood' | 'OutOfDate' | 'LowQuality' | 'Erroneous';
-}
-
-/** @name PalletIdentityRegistrarInfo */
-export interface PalletIdentityRegistrarInfo extends Struct {
- readonly account: AccountId32;
- readonly fee: u128;
- readonly fields: PalletIdentityBitFlags;
-}
-
-/** @name PalletIdentityRegistration */
-export interface PalletIdentityRegistration extends Struct {
- readonly judgements: Vec<ITuple<[u32, PalletIdentityJudgement]>>;
- readonly deposit: u128;
- readonly info: PalletIdentityIdentityInfo;
-}
-
-/** @name PalletInflationCall */
-export interface PalletInflationCall extends Enum {
- readonly isStartInflation: boolean;
- readonly asStartInflation: {
- readonly inflationStartRelayBlock: u32;
- } & Struct;
- readonly type: 'StartInflation';
-}
-
-/** @name PalletMaintenanceCall */
-export interface PalletMaintenanceCall extends Enum {
- readonly isEnable: boolean;
- readonly isDisable: boolean;
- readonly type: 'Enable' | 'Disable';
-}
-
-/** @name PalletMaintenanceError */
-export interface PalletMaintenanceError extends Null {}
-
-/** @name PalletMaintenanceEvent */
-export interface PalletMaintenanceEvent extends Enum {
- readonly isMaintenanceEnabled: boolean;
- readonly isMaintenanceDisabled: boolean;
- readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled';
-}
-
-/** @name PalletMembershipCall */
-export interface PalletMembershipCall extends Enum {
- readonly isAddMember: boolean;
- readonly asAddMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isRemoveMember: boolean;
- readonly asRemoveMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isSwapMember: boolean;
- readonly asSwapMember: {
- readonly remove: MultiAddress;
- readonly add: MultiAddress;
- } & Struct;
- readonly isResetMembers: boolean;
- readonly asResetMembers: {
- readonly members: Vec<AccountId32>;
- } & Struct;
- readonly isChangeKey: boolean;
- readonly asChangeKey: {
- readonly new_: MultiAddress;
- } & Struct;
- readonly isSetPrime: boolean;
- readonly asSetPrime: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isClearPrime: boolean;
- readonly type: 'AddMember' | 'RemoveMember' | 'SwapMember' | 'ResetMembers' | 'ChangeKey' | 'SetPrime' | 'ClearPrime';
-}
-
-/** @name PalletMembershipError */
-export interface PalletMembershipError extends Enum {
- readonly isAlreadyMember: boolean;
- readonly isNotMember: boolean;
- readonly isTooManyMembers: boolean;
- readonly type: 'AlreadyMember' | 'NotMember' | 'TooManyMembers';
-}
-
-/** @name PalletMembershipEvent */
-export interface PalletMembershipEvent extends Enum {
- readonly isMemberAdded: boolean;
- readonly isMemberRemoved: boolean;
- readonly isMembersSwapped: boolean;
- readonly isMembersReset: boolean;
- readonly isKeyChanged: boolean;
- readonly isDummy: boolean;
- readonly type: 'MemberAdded' | 'MemberRemoved' | 'MembersSwapped' | 'MembersReset' | 'KeyChanged' | 'Dummy';
-}
-
-/** @name PalletNonfungibleError */
-export interface PalletNonfungibleError extends Enum {
- readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
- readonly isNonfungibleItemsHaveNoAmount: boolean;
- readonly isCantBurnNftWithChildren: boolean;
- readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
-}
-
-/** @name PalletNonfungibleItemData */
-export interface PalletNonfungibleItemData extends Struct {
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
-}
-
-/** @name PalletPreimageCall */
-export interface PalletPreimageCall extends Enum {
- readonly isNotePreimage: boolean;
- readonly asNotePreimage: {
- readonly bytes: Bytes;
- } & Struct;
- readonly isUnnotePreimage: boolean;
- readonly asUnnotePreimage: {
- readonly hash_: H256;
- } & Struct;
- readonly isRequestPreimage: boolean;
- readonly asRequestPreimage: {
- readonly hash_: H256;
- } & Struct;
- readonly isUnrequestPreimage: boolean;
- readonly asUnrequestPreimage: {
- readonly hash_: H256;
- } & Struct;
- readonly type: 'NotePreimage' | 'UnnotePreimage' | 'RequestPreimage' | 'UnrequestPreimage';
-}
-
-/** @name PalletPreimageError */
-export interface PalletPreimageError extends Enum {
- readonly isTooBig: boolean;
- readonly isAlreadyNoted: boolean;
- readonly isNotAuthorized: boolean;
- readonly isNotNoted: boolean;
- readonly isRequested: boolean;
- readonly isNotRequested: boolean;
- readonly type: 'TooBig' | 'AlreadyNoted' | 'NotAuthorized' | 'NotNoted' | 'Requested' | 'NotRequested';
-}
-
-/** @name PalletPreimageEvent */
-export interface PalletPreimageEvent extends Enum {
- readonly isNoted: boolean;
- readonly asNoted: {
- readonly hash_: H256;
- } & Struct;
- readonly isRequested: boolean;
- readonly asRequested: {
- readonly hash_: H256;
- } & Struct;
- readonly isCleared: boolean;
- readonly asCleared: {
- readonly hash_: H256;
- } & Struct;
- readonly type: 'Noted' | 'Requested' | 'Cleared';
-}
-
-/** @name PalletPreimageRequestStatus */
-export interface PalletPreimageRequestStatus extends Enum {
- readonly isUnrequested: boolean;
- readonly asUnrequested: {
- readonly deposit: ITuple<[AccountId32, u128]>;
- readonly len: u32;
- } & Struct;
- readonly isRequested: boolean;
- readonly asRequested: {
- readonly deposit: Option<ITuple<[AccountId32, u128]>>;
- readonly count: u32;
- readonly len: Option<u32>;
- } & Struct;
- readonly type: 'Unrequested' | 'Requested';
-}
-
-/** @name PalletRankedCollectiveCall */
-export interface PalletRankedCollectiveCall extends Enum {
- readonly isAddMember: boolean;
- readonly asAddMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isPromoteMember: boolean;
- readonly asPromoteMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isDemoteMember: boolean;
- readonly asDemoteMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isRemoveMember: boolean;
- readonly asRemoveMember: {
- readonly who: MultiAddress;
- readonly minRank: u16;
- } & Struct;
- readonly isVote: boolean;
- readonly asVote: {
- readonly poll: u32;
- readonly aye: bool;
- } & Struct;
- readonly isCleanupPoll: boolean;
- readonly asCleanupPoll: {
- readonly pollIndex: u32;
- readonly max: u32;
- } & Struct;
- readonly type: 'AddMember' | 'PromoteMember' | 'DemoteMember' | 'RemoveMember' | 'Vote' | 'CleanupPoll';
-}
-
-/** @name PalletRankedCollectiveError */
-export interface PalletRankedCollectiveError extends Enum {
- readonly isAlreadyMember: boolean;
- readonly isNotMember: boolean;
- readonly isNotPolling: boolean;
- readonly isOngoing: boolean;
- readonly isNoneRemaining: boolean;
- readonly isCorruption: boolean;
- readonly isRankTooLow: boolean;
- readonly isInvalidWitness: boolean;
- readonly isNoPermission: boolean;
- readonly type: 'AlreadyMember' | 'NotMember' | 'NotPolling' | 'Ongoing' | 'NoneRemaining' | 'Corruption' | 'RankTooLow' | 'InvalidWitness' | 'NoPermission';
-}
-
-/** @name PalletRankedCollectiveEvent */
-export interface PalletRankedCollectiveEvent extends Enum {
- readonly isMemberAdded: boolean;
- readonly asMemberAdded: {
- readonly who: AccountId32;
- } & Struct;
- readonly isRankChanged: boolean;
- readonly asRankChanged: {
- readonly who: AccountId32;
- readonly rank: u16;
- } & Struct;
- readonly isMemberRemoved: boolean;
- readonly asMemberRemoved: {
- readonly who: AccountId32;
- readonly rank: u16;
- } & Struct;
- readonly isVoted: boolean;
- readonly asVoted: {
- readonly who: AccountId32;
- readonly poll: u32;
- readonly vote: PalletRankedCollectiveVoteRecord;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly type: 'MemberAdded' | 'RankChanged' | 'MemberRemoved' | 'Voted';
-}
-
-/** @name PalletRankedCollectiveMemberRecord */
-export interface PalletRankedCollectiveMemberRecord extends Struct {
- readonly rank: u16;
-}
-
-/** @name PalletRankedCollectiveTally */
-export interface PalletRankedCollectiveTally extends Struct {
- readonly bareAyes: u32;
- readonly ayes: u32;
- readonly nays: u32;
-}
-
-/** @name PalletRankedCollectiveVoteRecord */
-export interface PalletRankedCollectiveVoteRecord extends Enum {
- readonly isAye: boolean;
- readonly asAye: u32;
- readonly isNay: boolean;
- readonly asNay: u32;
- readonly type: 'Aye' | 'Nay';
-}
-
-/** @name PalletReferendaCall */
-export interface PalletReferendaCall extends Enum {
- readonly isSubmit: boolean;
- readonly asSubmit: {
- readonly proposalOrigin: OpalRuntimeOriginCaller;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly enactmentMoment: FrameSupportScheduleDispatchTime;
- } & Struct;
- readonly isPlaceDecisionDeposit: boolean;
- readonly asPlaceDecisionDeposit: {
- readonly index: u32;
- } & Struct;
- readonly isRefundDecisionDeposit: boolean;
- readonly asRefundDecisionDeposit: {
- readonly index: u32;
- } & Struct;
- readonly isCancel: boolean;
- readonly asCancel: {
- readonly index: u32;
- } & Struct;
- readonly isKill: boolean;
- readonly asKill: {
- readonly index: u32;
- } & Struct;
- readonly isNudgeReferendum: boolean;
- readonly asNudgeReferendum: {
- readonly index: u32;
- } & Struct;
- readonly isOneFewerDeciding: boolean;
- readonly asOneFewerDeciding: {
- readonly track: u16;
- } & Struct;
- readonly isRefundSubmissionDeposit: boolean;
- readonly asRefundSubmissionDeposit: {
- readonly index: u32;
- } & Struct;
- readonly isSetMetadata: boolean;
- readonly asSetMetadata: {
- readonly index: u32;
- readonly maybeHash: Option<H256>;
- } & Struct;
- readonly type: 'Submit' | 'PlaceDecisionDeposit' | 'RefundDecisionDeposit' | 'Cancel' | 'Kill' | 'NudgeReferendum' | 'OneFewerDeciding' | 'RefundSubmissionDeposit' | 'SetMetadata';
-}
-
-/** @name PalletReferendaCurve */
-export interface PalletReferendaCurve extends Enum {
- readonly isLinearDecreasing: boolean;
- readonly asLinearDecreasing: {
- readonly length: Perbill;
- readonly floor: Perbill;
- readonly ceil: Perbill;
- } & Struct;
- readonly isSteppedDecreasing: boolean;
- readonly asSteppedDecreasing: {
- readonly begin: Perbill;
- readonly end: Perbill;
- readonly step: Perbill;
- readonly period: Perbill;
- } & Struct;
- readonly isReciprocal: boolean;
- readonly asReciprocal: {
- readonly factor: i64;
- readonly xOffset: i64;
- readonly yOffset: i64;
- } & Struct;
- readonly type: 'LinearDecreasing' | 'SteppedDecreasing' | 'Reciprocal';
-}
-
-/** @name PalletReferendaDecidingStatus */
-export interface PalletReferendaDecidingStatus extends Struct {
- readonly since: u32;
- readonly confirming: Option<u32>;
-}
-
-/** @name PalletReferendaDeposit */
-export interface PalletReferendaDeposit extends Struct {
- readonly who: AccountId32;
- readonly amount: u128;
-}
-
-/** @name PalletReferendaError */
-export interface PalletReferendaError extends Enum {
- readonly isNotOngoing: boolean;
- readonly isHasDeposit: boolean;
- readonly isBadTrack: boolean;
- readonly isFull: boolean;
- readonly isQueueEmpty: boolean;
- readonly isBadReferendum: boolean;
- readonly isNothingToDo: boolean;
- readonly isNoTrack: boolean;
- readonly isUnfinished: boolean;
- readonly isNoPermission: boolean;
- readonly isNoDeposit: boolean;
- readonly isBadStatus: boolean;
- readonly isPreimageNotExist: boolean;
- readonly type: 'NotOngoing' | 'HasDeposit' | 'BadTrack' | 'Full' | 'QueueEmpty' | 'BadReferendum' | 'NothingToDo' | 'NoTrack' | 'Unfinished' | 'NoPermission' | 'NoDeposit' | 'BadStatus' | 'PreimageNotExist';
-}
-
-/** @name PalletReferendaEvent */
-export interface PalletReferendaEvent extends Enum {
- readonly isSubmitted: boolean;
- readonly asSubmitted: {
- readonly index: u32;
- readonly track: u16;
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isDecisionDepositPlaced: boolean;
- readonly asDecisionDepositPlaced: {
- readonly index: u32;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDecisionDepositRefunded: boolean;
- readonly asDecisionDepositRefunded: {
- readonly index: u32;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDepositSlashed: boolean;
- readonly asDepositSlashed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDecisionStarted: boolean;
- readonly asDecisionStarted: {
- readonly index: u32;
- readonly track: u16;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isConfirmStarted: boolean;
- readonly asConfirmStarted: {
- readonly index: u32;
- } & Struct;
- readonly isConfirmAborted: boolean;
- readonly asConfirmAborted: {
- readonly index: u32;
- } & Struct;
- readonly isConfirmed: boolean;
- readonly asConfirmed: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isApproved: boolean;
- readonly asApproved: {
- readonly index: u32;
- } & Struct;
- readonly isRejected: boolean;
- readonly asRejected: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isTimedOut: boolean;
- readonly asTimedOut: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isCancelled: boolean;
- readonly asCancelled: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isKilled: boolean;
- readonly asKilled: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isSubmissionDepositRefunded: boolean;
- readonly asSubmissionDepositRefunded: {
- readonly index: u32;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isMetadataSet: boolean;
- readonly asMetadataSet: {
- readonly index: u32;
- readonly hash_: H256;
- } & Struct;
- readonly isMetadataCleared: boolean;
- readonly asMetadataCleared: {
- readonly index: u32;
- readonly hash_: H256;
- } & Struct;
- readonly type: 'Submitted' | 'DecisionDepositPlaced' | 'DecisionDepositRefunded' | 'DepositSlashed' | 'DecisionStarted' | 'ConfirmStarted' | 'ConfirmAborted' | 'Confirmed' | 'Approved' | 'Rejected' | 'TimedOut' | 'Cancelled' | 'Killed' | 'SubmissionDepositRefunded' | 'MetadataSet' | 'MetadataCleared';
-}
-
-/** @name PalletReferendaReferendumInfo */
-export interface PalletReferendaReferendumInfo extends Enum {
- readonly isOngoing: boolean;
- readonly asOngoing: PalletReferendaReferendumStatus;
- readonly isApproved: boolean;
- readonly asApproved: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isRejected: boolean;
- readonly asRejected: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isCancelled: boolean;
- readonly asCancelled: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isTimedOut: boolean;
- readonly asTimedOut: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isKilled: boolean;
- readonly asKilled: u32;
- readonly type: 'Ongoing' | 'Approved' | 'Rejected' | 'Cancelled' | 'TimedOut' | 'Killed';
-}
-
-/** @name PalletReferendaReferendumStatus */
-export interface PalletReferendaReferendumStatus extends Struct {
- readonly track: u16;
- readonly origin: OpalRuntimeOriginCaller;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly enactment: FrameSupportScheduleDispatchTime;
- readonly submitted: u32;
- readonly submissionDeposit: PalletReferendaDeposit;
- readonly decisionDeposit: Option<PalletReferendaDeposit>;
- readonly deciding: Option<PalletReferendaDecidingStatus>;
- readonly tally: PalletRankedCollectiveTally;
- readonly inQueue: bool;
- readonly alarm: Option<ITuple<[u32, ITuple<[u32, u32]>]>>;
-}
-
-/** @name PalletReferendaTrackInfo */
-export interface PalletReferendaTrackInfo extends Struct {
- readonly name: Text;
- readonly maxDeciding: u32;
- readonly decisionDeposit: u128;
- readonly preparePeriod: u32;
- readonly decisionPeriod: u32;
- readonly confirmPeriod: u32;
- readonly minEnactmentPeriod: u32;
- readonly minApproval: PalletReferendaCurve;
- readonly minSupport: PalletReferendaCurve;
-}
-
-/** @name PalletRefungibleError */
-export interface PalletRefungibleError extends Enum {
- readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
- readonly isWrongRefungiblePieces: boolean;
- readonly isRepartitionWhileNotOwningAllPieces: boolean;
- readonly isRefungibleDisallowsNesting: boolean;
- readonly isSettingPropertiesNotAllowed: boolean;
- readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
-}
-
-/** @name PalletSchedulerCall */
-export interface PalletSchedulerCall extends Enum {
- readonly isSchedule: boolean;
- readonly asSchedule: {
- readonly when: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly isCancel: boolean;
- readonly asCancel: {
- readonly when: u32;
- readonly index: u32;
- } & Struct;
- readonly isScheduleNamed: boolean;
- readonly asScheduleNamed: {
- readonly id: U8aFixed;
- readonly when: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly isCancelNamed: boolean;
- readonly asCancelNamed: {
- readonly id: U8aFixed;
- } & Struct;
- readonly isScheduleAfter: boolean;
- readonly asScheduleAfter: {
- readonly after: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly isScheduleNamedAfter: boolean;
- readonly asScheduleNamedAfter: {
- readonly id: U8aFixed;
- readonly after: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter';
-}
-
-/** @name PalletSchedulerError */
-export interface PalletSchedulerError extends Enum {
- readonly isFailedToSchedule: boolean;
- readonly isNotFound: boolean;
- readonly isTargetBlockNumberInPast: boolean;
- readonly isRescheduleNoChange: boolean;
- readonly isNamed: boolean;
- readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange' | 'Named';
-}
-
-/** @name PalletSchedulerEvent */
-export interface PalletSchedulerEvent extends Enum {
- readonly isScheduled: boolean;
- readonly asScheduled: {
- readonly when: u32;
- readonly index: u32;
- } & Struct;
- readonly isCanceled: boolean;
- readonly asCanceled: {
- readonly when: u32;
- readonly index: u32;
- } & Struct;
- readonly isDispatched: boolean;
- readonly asDispatched: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isCallUnavailable: boolean;
- readonly asCallUnavailable: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- } & Struct;
- readonly isPeriodicFailed: boolean;
- readonly asPeriodicFailed: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- } & Struct;
- readonly isPermanentlyOverweight: boolean;
- readonly asPermanentlyOverweight: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- } & Struct;
- readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'CallUnavailable' | 'PeriodicFailed' | 'PermanentlyOverweight';
-}
-
-/** @name PalletSchedulerScheduled */
-export interface PalletSchedulerScheduled extends Struct {
- readonly maybeId: Option<U8aFixed>;
- readonly priority: u8;
- readonly call: FrameSupportPreimagesBounded;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly origin: OpalRuntimeOriginCaller;
-}
-
-/** @name PalletSessionCall */
-export interface PalletSessionCall extends Enum {
- readonly isSetKeys: boolean;
- readonly asSetKeys: {
- readonly keys_: OpalRuntimeRuntimeCommonSessionKeys;
- readonly proof: Bytes;
- } & Struct;
- readonly isPurgeKeys: boolean;
- readonly type: 'SetKeys' | 'PurgeKeys';
-}
-
-/** @name PalletSessionError */
-export interface PalletSessionError extends Enum {
- readonly isInvalidProof: boolean;
- readonly isNoAssociatedValidatorId: boolean;
- readonly isDuplicatedKey: boolean;
- readonly isNoKeys: boolean;
- readonly isNoAccount: boolean;
- readonly type: 'InvalidProof' | 'NoAssociatedValidatorId' | 'DuplicatedKey' | 'NoKeys' | 'NoAccount';
-}
-
-/** @name PalletSessionEvent */
-export interface PalletSessionEvent extends Enum {
- readonly isNewSession: boolean;
- readonly asNewSession: {
- readonly sessionIndex: u32;
- } & Struct;
- readonly type: 'NewSession';
-}
-
-/** @name PalletStateTrieMigrationCall */
-export interface PalletStateTrieMigrationCall extends Enum {
- readonly isControlAutoMigration: boolean;
- readonly asControlAutoMigration: {
- readonly maybeConfig: Option<PalletStateTrieMigrationMigrationLimits>;
- } & Struct;
- readonly isContinueMigrate: boolean;
- readonly asContinueMigrate: {
- readonly limits: PalletStateTrieMigrationMigrationLimits;
- readonly realSizeUpper: u32;
- readonly witnessTask: PalletStateTrieMigrationMigrationTask;
- } & Struct;
- readonly isMigrateCustomTop: boolean;
- readonly asMigrateCustomTop: {
- readonly keys_: Vec<Bytes>;
- readonly witnessSize: u32;
- } & Struct;
- readonly isMigrateCustomChild: boolean;
- readonly asMigrateCustomChild: {
- readonly root: Bytes;
- readonly childKeys: Vec<Bytes>;
- readonly totalSize: u32;
- } & Struct;
- readonly isSetSignedMaxLimits: boolean;
- readonly asSetSignedMaxLimits: {
- readonly limits: PalletStateTrieMigrationMigrationLimits;
- } & Struct;
- readonly isForceSetProgress: boolean;
- readonly asForceSetProgress: {
- readonly progressTop: PalletStateTrieMigrationProgress;
- readonly progressChild: PalletStateTrieMigrationProgress;
- } & Struct;
- readonly type: 'ControlAutoMigration' | 'ContinueMigrate' | 'MigrateCustomTop' | 'MigrateCustomChild' | 'SetSignedMaxLimits' | 'ForceSetProgress';
-}
-
-/** @name PalletStateTrieMigrationError */
-export interface PalletStateTrieMigrationError extends Enum {
- readonly isMaxSignedLimits: boolean;
- readonly isKeyTooLong: boolean;
- readonly isNotEnoughFunds: boolean;
- readonly isBadWitness: boolean;
- readonly isSignedMigrationNotAllowed: boolean;
- readonly isBadChildRoot: boolean;
- readonly type: 'MaxSignedLimits' | 'KeyTooLong' | 'NotEnoughFunds' | 'BadWitness' | 'SignedMigrationNotAllowed' | 'BadChildRoot';
-}
-
-/** @name PalletStateTrieMigrationEvent */
-export interface PalletStateTrieMigrationEvent extends Enum {
- readonly isMigrated: boolean;
- readonly asMigrated: {
- readonly top: u32;
- readonly child: u32;
- readonly compute: PalletStateTrieMigrationMigrationCompute;
- } & Struct;
- readonly isSlashed: boolean;
- readonly asSlashed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isAutoMigrationFinished: boolean;
- readonly isHalted: boolean;
- readonly asHalted: {
- readonly error: PalletStateTrieMigrationError;
- } & Struct;
- readonly type: 'Migrated' | 'Slashed' | 'AutoMigrationFinished' | 'Halted';
-}
-
-/** @name PalletStateTrieMigrationMigrationCompute */
-export interface PalletStateTrieMigrationMigrationCompute extends Enum {
- readonly isSigned: boolean;
- readonly isAuto: boolean;
- readonly type: 'Signed' | 'Auto';
-}
-
-/** @name PalletStateTrieMigrationMigrationLimits */
-export interface PalletStateTrieMigrationMigrationLimits extends Struct {
- readonly size_: u32;
- readonly item: u32;
-}
-
-/** @name PalletStateTrieMigrationMigrationTask */
-export interface PalletStateTrieMigrationMigrationTask extends Struct {
- readonly progressTop: PalletStateTrieMigrationProgress;
- readonly progressChild: PalletStateTrieMigrationProgress;
- readonly size_: u32;
- readonly topItems: u32;
- readonly childItems: u32;
-}
-
-/** @name PalletStateTrieMigrationProgress */
-export interface PalletStateTrieMigrationProgress extends Enum {
- readonly isToStart: boolean;
- readonly isLastKey: boolean;
- readonly asLastKey: Bytes;
- readonly isComplete: boolean;
- readonly type: 'ToStart' | 'LastKey' | 'Complete';
-}
-
-/** @name PalletStructureCall */
-export interface PalletStructureCall extends Null {}
-
-/** @name PalletStructureError */
-export interface PalletStructureError extends Enum {
- readonly isOuroborosDetected: boolean;
- readonly isDepthLimit: boolean;
- readonly isBreadthLimit: boolean;
- readonly isTokenNotFound: boolean;
- readonly isCantNestTokenUnderCollection: boolean;
- readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound' | 'CantNestTokenUnderCollection';
-}
-
-/** @name PalletStructureEvent */
-export interface PalletStructureEvent extends Enum {
- readonly isExecuted: boolean;
- readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
- readonly type: 'Executed';
-}
-
-/** @name PalletSudoCall */
-export interface PalletSudoCall extends Enum {
- readonly isSudo: boolean;
- readonly asSudo: {
- readonly call: Call;
- } & Struct;
- readonly isSudoUncheckedWeight: boolean;
- readonly asSudoUncheckedWeight: {
- readonly call: Call;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isSetKey: boolean;
- readonly asSetKey: {
- readonly new_: MultiAddress;
- } & Struct;
- readonly isSudoAs: boolean;
- readonly asSudoAs: {
- readonly who: MultiAddress;
- readonly call: Call;
- } & Struct;
- readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
-}
-
-/** @name PalletSudoError */
-export interface PalletSudoError extends Enum {
- readonly isRequireSudo: boolean;
- readonly type: 'RequireSudo';
-}
-
-/** @name PalletSudoEvent */
-export interface PalletSudoEvent extends Enum {
- readonly isSudid: boolean;
- readonly asSudid: {
- readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isKeyChanged: boolean;
- readonly asKeyChanged: {
- readonly oldSudoer: Option<AccountId32>;
- } & Struct;
- readonly isSudoAsDone: boolean;
- readonly asSudoAsDone: {
- readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone';
-}
-
-/** @name PalletTemplateTransactionPaymentChargeTransactionPayment */
-export interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
-
-/** @name PalletTestUtilsCall */
-export interface PalletTestUtilsCall extends Enum {
- readonly isEnable: boolean;
- readonly isSetTestValue: boolean;
- readonly asSetTestValue: {
- readonly value: u32;
- } & Struct;
- readonly isSetTestValueAndRollback: boolean;
- readonly asSetTestValueAndRollback: {
- readonly value: u32;
- } & Struct;
- readonly isIncTestValue: boolean;
- readonly isJustTakeFee: boolean;
- readonly isBatchAll: boolean;
- readonly asBatchAll: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'JustTakeFee' | 'BatchAll';
-}
-
-/** @name PalletTestUtilsError */
-export interface PalletTestUtilsError extends Enum {
- readonly isTestPalletDisabled: boolean;
- readonly isTriggerRollback: boolean;
- readonly type: 'TestPalletDisabled' | 'TriggerRollback';
-}
-
-/** @name PalletTestUtilsEvent */
-export interface PalletTestUtilsEvent extends Enum {
- readonly isValueIsSet: boolean;
- readonly isShouldRollback: boolean;
- readonly isBatchCompleted: boolean;
- readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
-}
-
-/** @name PalletTimestampCall */
-export interface PalletTimestampCall extends Enum {
- readonly isSet: boolean;
- readonly asSet: {
- readonly now: Compact<u64>;
- } & Struct;
- readonly type: 'Set';
-}
-
-/** @name PalletTransactionPaymentEvent */
-export interface PalletTransactionPaymentEvent extends Enum {
- readonly isTransactionFeePaid: boolean;
- readonly asTransactionFeePaid: {
- readonly who: AccountId32;
- readonly actualFee: u128;
- readonly tip: u128;
- } & Struct;
- readonly type: 'TransactionFeePaid';
-}
-
-/** @name PalletTransactionPaymentReleases */
-export interface PalletTransactionPaymentReleases extends Enum {
- readonly isV1Ancient: boolean;
- readonly isV2: boolean;
- readonly type: 'V1Ancient' | 'V2';
-}
-
-/** @name PalletTreasuryCall */
-export interface PalletTreasuryCall extends Enum {
- readonly isProposeSpend: boolean;
- readonly asProposeSpend: {
- readonly value: Compact<u128>;
- readonly beneficiary: MultiAddress;
- } & Struct;
- readonly isRejectProposal: boolean;
- readonly asRejectProposal: {
- readonly proposalId: Compact<u32>;
- } & Struct;
- readonly isApproveProposal: boolean;
- readonly asApproveProposal: {
- readonly proposalId: Compact<u32>;
- } & Struct;
- readonly isSpend: boolean;
- readonly asSpend: {
- readonly amount: Compact<u128>;
- readonly beneficiary: MultiAddress;
- } & Struct;
- readonly isRemoveApproval: boolean;
- readonly asRemoveApproval: {
- readonly proposalId: Compact<u32>;
- } & Struct;
- readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
-}
-
-/** @name PalletTreasuryError */
-export interface PalletTreasuryError extends Enum {
- readonly isInsufficientProposersBalance: boolean;
- readonly isInvalidIndex: boolean;
- readonly isTooManyApprovals: boolean;
- readonly isInsufficientPermission: boolean;
- readonly isProposalNotApproved: boolean;
- readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
-}
-
-/** @name PalletTreasuryEvent */
-export interface PalletTreasuryEvent extends Enum {
- readonly isProposed: boolean;
- readonly asProposed: {
- readonly proposalIndex: u32;
- } & Struct;
- readonly isSpending: boolean;
- readonly asSpending: {
- readonly budgetRemaining: u128;
- } & Struct;
- readonly isAwarded: boolean;
- readonly asAwarded: {
- readonly proposalIndex: u32;
- readonly award: u128;
- readonly account: AccountId32;
- } & Struct;
- readonly isRejected: boolean;
- readonly asRejected: {
- readonly proposalIndex: u32;
- readonly slashed: u128;
- } & Struct;
- readonly isBurnt: boolean;
- readonly asBurnt: {
- readonly burntFunds: u128;
- } & Struct;
- readonly isRollover: boolean;
- readonly asRollover: {
- readonly rolloverBalance: u128;
- } & Struct;
- readonly isDeposit: boolean;
- readonly asDeposit: {
- readonly value: u128;
- } & Struct;
- readonly isSpendApproved: boolean;
- readonly asSpendApproved: {
- readonly proposalIndex: u32;
- readonly amount: u128;
- readonly beneficiary: AccountId32;
- } & Struct;
- readonly isUpdatedInactive: boolean;
- readonly asUpdatedInactive: {
- readonly reactivated: u128;
- readonly deactivated: u128;
- } & Struct;
- readonly type: 'Proposed' | 'Spending' | 'Awarded' | 'Rejected' | 'Burnt' | 'Rollover' | 'Deposit' | 'SpendApproved' | 'UpdatedInactive';
-}
-
-/** @name PalletTreasuryProposal */
-export interface PalletTreasuryProposal extends Struct {
- readonly proposer: AccountId32;
- readonly value: u128;
- readonly beneficiary: AccountId32;
- readonly bond: u128;
-}
-
-/** @name PalletUniqueCall */
-export interface PalletUniqueCall extends Enum {
- readonly isCreateCollection: boolean;
- readonly asCreateCollection: {
- readonly collectionName: Vec<u16>;
- readonly collectionDescription: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly mode: UpDataStructsCollectionMode;
- } & Struct;
- readonly isCreateCollectionEx: boolean;
- readonly asCreateCollectionEx: {
- readonly data: UpDataStructsCreateCollectionData;
- } & Struct;
- readonly isDestroyCollection: boolean;
- readonly asDestroyCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isAddToAllowList: boolean;
- readonly asAddToAllowList: {
- readonly collectionId: u32;
- readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isRemoveFromAllowList: boolean;
- readonly asRemoveFromAllowList: {
- readonly collectionId: u32;
- readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isChangeCollectionOwner: boolean;
- readonly asChangeCollectionOwner: {
- readonly collectionId: u32;
- readonly newOwner: AccountId32;
- } & Struct;
- readonly isAddCollectionAdmin: boolean;
- readonly asAddCollectionAdmin: {
- readonly collectionId: u32;
- readonly newAdminId: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isRemoveCollectionAdmin: boolean;
- readonly asRemoveCollectionAdmin: {
- readonly collectionId: u32;
- readonly accountId: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isSetCollectionSponsor: boolean;
- readonly asSetCollectionSponsor: {
- readonly collectionId: u32;
- readonly newSponsor: AccountId32;
- } & Struct;
- readonly isConfirmSponsorship: boolean;
- readonly asConfirmSponsorship: {
- readonly collectionId: u32;
- } & Struct;
- readonly isRemoveCollectionSponsor: boolean;
- readonly asRemoveCollectionSponsor: {
- readonly collectionId: u32;
- } & Struct;
- readonly isCreateItem: boolean;
- readonly asCreateItem: {
- readonly collectionId: u32;
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly data: UpDataStructsCreateItemData;
- } & Struct;
- readonly isCreateMultipleItems: boolean;
- readonly asCreateMultipleItems: {
- readonly collectionId: u32;
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly itemsData: Vec<UpDataStructsCreateItemData>;
- } & Struct;
- readonly isSetCollectionProperties: boolean;
- readonly asSetCollectionProperties: {
- readonly collectionId: u32;
- readonly properties: Vec<UpDataStructsProperty>;
- } & Struct;
- readonly isDeleteCollectionProperties: boolean;
- readonly asDeleteCollectionProperties: {
- readonly collectionId: u32;
- readonly propertyKeys: Vec<Bytes>;
- } & Struct;
- readonly isSetTokenProperties: boolean;
- readonly asSetTokenProperties: {
- readonly collectionId: u32;
- readonly tokenId: u32;
- readonly properties: Vec<UpDataStructsProperty>;
- } & Struct;
- readonly isDeleteTokenProperties: boolean;
- readonly asDeleteTokenProperties: {
- readonly collectionId: u32;
- readonly tokenId: u32;
- readonly propertyKeys: Vec<Bytes>;
- } & Struct;
- readonly isSetTokenPropertyPermissions: boolean;
- readonly asSetTokenPropertyPermissions: {
- readonly collectionId: u32;
- readonly propertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
- } & Struct;
- readonly isCreateMultipleItemsEx: boolean;
- readonly asCreateMultipleItemsEx: {
- readonly collectionId: u32;
- readonly data: UpDataStructsCreateItemExData;
- } & Struct;
- readonly isSetTransfersEnabledFlag: boolean;
- readonly asSetTransfersEnabledFlag: {
- readonly collectionId: u32;
- readonly value: bool;
- } & Struct;
- readonly isBurnItem: boolean;
- readonly asBurnItem: {
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isBurnFrom: boolean;
- readonly asBurnFrom: {
- readonly collectionId: u32;
- readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isApprove: boolean;
- readonly asApprove: {
- readonly spender: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly amount: u128;
- } & Struct;
- readonly isApproveFrom: boolean;
- readonly asApproveFrom: {
- readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly to: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly amount: u128;
- } & Struct;
- readonly isTransferFrom: boolean;
- readonly asTransferFrom: {
- readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isSetCollectionLimits: boolean;
- readonly asSetCollectionLimits: {
- readonly collectionId: u32;
- readonly newLimit: UpDataStructsCollectionLimits;
- } & Struct;
- readonly isSetCollectionPermissions: boolean;
- readonly asSetCollectionPermissions: {
- readonly collectionId: u32;
- readonly newPermission: UpDataStructsCollectionPermissions;
- } & Struct;
- readonly isRepartition: boolean;
- readonly asRepartition: {
- readonly collectionId: u32;
- readonly tokenId: u32;
- readonly amount: u128;
- } & Struct;
- readonly isSetAllowanceForAll: boolean;
- readonly asSetAllowanceForAll: {
- readonly collectionId: u32;
- readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly approve: bool;
- } & Struct;
- readonly isForceRepairCollection: boolean;
- readonly asForceRepairCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isForceRepairItem: boolean;
- readonly asForceRepairItem: {
- readonly collectionId: u32;
- readonly itemId: u32;
- } & Struct;
- readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'ApproveFrom' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem';
-}
-
-/** @name PalletUniqueError */
-export interface PalletUniqueError extends Enum {
- readonly isCollectionDecimalPointLimitExceeded: boolean;
- readonly isEmptyArgument: boolean;
- readonly isRepartitionCalledOnNonRefungibleCollection: boolean;
- readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
-}
-
-/** @name PalletUtilityCall */
-export interface PalletUtilityCall extends Enum {
- readonly isBatch: boolean;
- readonly asBatch: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly isAsDerivative: boolean;
- readonly asAsDerivative: {
- readonly index: u16;
- readonly call: Call;
- } & Struct;
- readonly isBatchAll: boolean;
- readonly asBatchAll: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly isDispatchAs: boolean;
- readonly asDispatchAs: {
- readonly asOrigin: OpalRuntimeOriginCaller;
- readonly call: Call;
- } & Struct;
- readonly isForceBatch: boolean;
- readonly asForceBatch: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly isWithWeight: boolean;
- readonly asWithWeight: {
- readonly call: Call;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'Batch' | 'AsDerivative' | 'BatchAll' | 'DispatchAs' | 'ForceBatch' | 'WithWeight';
-}
-
-/** @name PalletUtilityError */
-export interface PalletUtilityError extends Enum {
- readonly isTooManyCalls: boolean;
- readonly type: 'TooManyCalls';
-}
-
-/** @name PalletUtilityEvent */
-export interface PalletUtilityEvent extends Enum {
- readonly isBatchInterrupted: boolean;
- readonly asBatchInterrupted: {
- readonly index: u32;
- readonly error: SpRuntimeDispatchError;
- } & Struct;
- readonly isBatchCompleted: boolean;
- readonly isBatchCompletedWithErrors: boolean;
- readonly isItemCompleted: boolean;
- readonly isItemFailed: boolean;
- readonly asItemFailed: {
- readonly error: SpRuntimeDispatchError;
- } & Struct;
- readonly isDispatchedAs: boolean;
- readonly asDispatchedAs: {
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly type: 'BatchInterrupted' | 'BatchCompleted' | 'BatchCompletedWithErrors' | 'ItemCompleted' | 'ItemFailed' | 'DispatchedAs';
-}
-
-/** @name PalletXcmCall */
-export interface PalletXcmCall extends Enum {
- readonly isSend: boolean;
- readonly asSend: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly message: StagingXcmVersionedXcm;
- } & Struct;
- readonly isTeleportAssets: boolean;
- readonly asTeleportAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- } & Struct;
- readonly isReserveTransferAssets: boolean;
- readonly asReserveTransferAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- } & Struct;
- readonly isExecute: boolean;
- readonly asExecute: {
- readonly message: StagingXcmVersionedXcm;
- readonly maxWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isForceXcmVersion: boolean;
- readonly asForceXcmVersion: {
- readonly location: StagingXcmV3MultiLocation;
- readonly version: u32;
- } & Struct;
- readonly isForceDefaultXcmVersion: boolean;
- readonly asForceDefaultXcmVersion: {
- readonly maybeXcmVersion: Option<u32>;
- } & Struct;
- readonly isForceSubscribeVersionNotify: boolean;
- readonly asForceSubscribeVersionNotify: {
- readonly location: StagingXcmVersionedMultiLocation;
- } & Struct;
- readonly isForceUnsubscribeVersionNotify: boolean;
- readonly asForceUnsubscribeVersionNotify: {
- readonly location: StagingXcmVersionedMultiLocation;
- } & Struct;
- readonly isLimitedReserveTransferAssets: boolean;
- readonly asLimitedReserveTransferAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- readonly weightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isLimitedTeleportAssets: boolean;
- readonly asLimitedTeleportAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- readonly weightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isForceSuspension: boolean;
- readonly asForceSuspension: {
- readonly suspended: bool;
- } & Struct;
- readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets' | 'ForceSuspension';
-}
-
-/** @name PalletXcmError */
-export interface PalletXcmError extends Enum {
- readonly isUnreachable: boolean;
- readonly isSendFailure: boolean;
- readonly isFiltered: boolean;
- readonly isUnweighableMessage: boolean;
- readonly isDestinationNotInvertible: boolean;
- readonly isEmpty: boolean;
- readonly isCannotReanchor: boolean;
- readonly isTooManyAssets: boolean;
- readonly isInvalidOrigin: boolean;
- readonly isBadVersion: boolean;
- readonly isBadLocation: boolean;
- readonly isNoSubscription: boolean;
- readonly isAlreadySubscribed: boolean;
- readonly isInvalidAsset: boolean;
- readonly isLowBalance: boolean;
- readonly isTooManyLocks: boolean;
- readonly isAccountNotSovereign: boolean;
- readonly isFeesNotMet: boolean;
- readonly isLockNotFound: boolean;
- readonly isInUse: boolean;
- readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed' | 'InvalidAsset' | 'LowBalance' | 'TooManyLocks' | 'AccountNotSovereign' | 'FeesNotMet' | 'LockNotFound' | 'InUse';
-}
-
-/** @name PalletXcmEvent */
-export interface PalletXcmEvent extends Enum {
- readonly isAttempted: boolean;
- readonly asAttempted: {
- readonly outcome: StagingXcmV3TraitsOutcome;
- } & Struct;
- readonly isSent: boolean;
- readonly asSent: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly destination: StagingXcmV3MultiLocation;
- readonly message: StagingXcmV3Xcm;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isUnexpectedResponse: boolean;
- readonly asUnexpectedResponse: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isResponseReady: boolean;
- readonly asResponseReady: {
- readonly queryId: u64;
- readonly response: StagingXcmV3Response;
- } & Struct;
- readonly isNotified: boolean;
- readonly asNotified: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- } & Struct;
- readonly isNotifyOverweight: boolean;
- readonly asNotifyOverweight: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- readonly actualWeight: SpWeightsWeightV2Weight;
- readonly maxBudgetedWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isNotifyDispatchError: boolean;
- readonly asNotifyDispatchError: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- } & Struct;
- readonly isNotifyDecodeFailed: boolean;
- readonly asNotifyDecodeFailed: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- } & Struct;
- readonly isInvalidResponder: boolean;
- readonly asInvalidResponder: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- readonly expectedLocation: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly isInvalidResponderVersion: boolean;
- readonly asInvalidResponderVersion: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isResponseTaken: boolean;
- readonly asResponseTaken: {
- readonly queryId: u64;
- } & Struct;
- readonly isAssetsTrapped: boolean;
- readonly asAssetsTrapped: {
- readonly hash_: H256;
- readonly origin: StagingXcmV3MultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- } & Struct;
- readonly isVersionChangeNotified: boolean;
- readonly asVersionChangeNotified: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly result: u32;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isSupportedVersionChanged: boolean;
- readonly asSupportedVersionChanged: {
- readonly location: StagingXcmV3MultiLocation;
- readonly version: u32;
- } & Struct;
- readonly isNotifyTargetSendFail: boolean;
- readonly asNotifyTargetSendFail: {
- readonly location: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- readonly error: StagingXcmV3TraitsError;
- } & Struct;
- readonly isNotifyTargetMigrationFail: boolean;
- readonly asNotifyTargetMigrationFail: {
- readonly location: StagingXcmVersionedMultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isInvalidQuerierVersion: boolean;
- readonly asInvalidQuerierVersion: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isInvalidQuerier: boolean;
- readonly asInvalidQuerier: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- readonly expectedQuerier: StagingXcmV3MultiLocation;
- readonly maybeActualQuerier: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly isVersionNotifyStarted: boolean;
- readonly asVersionNotifyStarted: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isVersionNotifyRequested: boolean;
- readonly asVersionNotifyRequested: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isVersionNotifyUnrequested: boolean;
- readonly asVersionNotifyUnrequested: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isFeesPaid: boolean;
- readonly asFeesPaid: {
- readonly paying: StagingXcmV3MultiLocation;
- readonly fees: StagingXcmV3MultiassetMultiAssets;
- } & Struct;
- readonly isAssetsClaimed: boolean;
- readonly asAssetsClaimed: {
- readonly hash_: H256;
- readonly origin: StagingXcmV3MultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- } & Struct;
- readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail' | 'InvalidQuerierVersion' | 'InvalidQuerier' | 'VersionNotifyStarted' | 'VersionNotifyRequested' | 'VersionNotifyUnrequested' | 'FeesPaid' | 'AssetsClaimed';
-}
-
-/** @name PalletXcmOrigin */
-export interface PalletXcmOrigin extends Enum {
- readonly isXcm: boolean;
- readonly asXcm: StagingXcmV3MultiLocation;
- readonly isResponse: boolean;
- readonly asResponse: StagingXcmV3MultiLocation;
- readonly type: 'Xcm' | 'Response';
-}
-
-/** @name PalletXcmQueryStatus */
-export interface PalletXcmQueryStatus extends Enum {
- readonly isPending: boolean;
- readonly asPending: {
- readonly responder: StagingXcmVersionedMultiLocation;
- readonly maybeMatchQuerier: Option<StagingXcmVersionedMultiLocation>;
- readonly maybeNotify: Option<ITuple<[u8, u8]>>;
- readonly timeout: u32;
- } & Struct;
- readonly isVersionNotifier: boolean;
- readonly asVersionNotifier: {
- readonly origin: StagingXcmVersionedMultiLocation;
- readonly isActive: bool;
- } & Struct;
- readonly isReady: boolean;
- readonly asReady: {
- readonly response: StagingXcmVersionedResponse;
- readonly at: u32;
- } & Struct;
- readonly type: 'Pending' | 'VersionNotifier' | 'Ready';
-}
-
-/** @name PalletXcmRemoteLockedFungibleRecord */
-export interface PalletXcmRemoteLockedFungibleRecord extends Struct {
- readonly amount: u128;
- readonly owner: StagingXcmVersionedMultiLocation;
- readonly locker: StagingXcmVersionedMultiLocation;
- readonly consumers: Vec<ITuple<[Null, u128]>>;
-}
-
-/** @name PalletXcmVersionMigrationStage */
-export interface PalletXcmVersionMigrationStage extends Enum {
- readonly isMigrateSupportedVersion: boolean;
- readonly isMigrateVersionNotifiers: boolean;
- readonly isNotifyCurrentTargets: boolean;
- readonly asNotifyCurrentTargets: Option<Bytes>;
- readonly isMigrateAndNotifyOldTargets: boolean;
- readonly type: 'MigrateSupportedVersion' | 'MigrateVersionNotifiers' | 'NotifyCurrentTargets' | 'MigrateAndNotifyOldTargets';
-}
-
-/** @name ParachainInfoCall */
-export interface ParachainInfoCall extends Null {}
-
-/** @name PhantomTypeUpDataStructs */
-export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, UpPovEstimateRpcPovInfo]>> {}
-
-/** @name PolkadotCorePrimitivesInboundDownwardMessage */
-export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
- readonly sentAt: u32;
- readonly msg: Bytes;
-}
-
-/** @name PolkadotCorePrimitivesInboundHrmpMessage */
-export interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
- readonly sentAt: u32;
- readonly data: Bytes;
-}
-
-/** @name PolkadotCorePrimitivesOutboundHrmpMessage */
-export interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
- readonly recipient: u32;
- readonly data: Bytes;
-}
-
-/** @name PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat */
-export interface PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat extends Enum {
- readonly isConcatenatedVersionedXcm: boolean;
- readonly isConcatenatedEncodedBlob: boolean;
- readonly isSignals: boolean;
- readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
-}
-
-/** @name PolkadotPrimitivesV5AbridgedHostConfiguration */
-export interface PolkadotPrimitivesV5AbridgedHostConfiguration extends Struct {
- readonly maxCodeSize: u32;
- readonly maxHeadDataSize: u32;
- readonly maxUpwardQueueCount: u32;
- readonly maxUpwardQueueSize: u32;
- readonly maxUpwardMessageSize: u32;
- readonly maxUpwardMessageNumPerCandidate: u32;
- readonly hrmpMaxMessageNumPerCandidate: u32;
- readonly validationUpgradeCooldown: u32;
- readonly validationUpgradeDelay: u32;
- readonly asyncBackingParams: PolkadotPrimitivesVstagingAsyncBackingParams;
-}
-
-/** @name PolkadotPrimitivesV5AbridgedHrmpChannel */
-export interface PolkadotPrimitivesV5AbridgedHrmpChannel extends Struct {
- readonly maxCapacity: u32;
- readonly maxTotalSize: u32;
- readonly maxMessageSize: u32;
- readonly msgCount: u32;
- readonly totalSize: u32;
- readonly mqcHead: Option<H256>;
-}
-
-/** @name PolkadotPrimitivesV5PersistedValidationData */
-export interface PolkadotPrimitivesV5PersistedValidationData extends Struct {
- readonly parentHead: Bytes;
- readonly relayParentNumber: u32;
- readonly relayParentStorageRoot: H256;
- readonly maxPovSize: u32;
-}
-
-/** @name PolkadotPrimitivesV5UpgradeGoAhead */
-export interface PolkadotPrimitivesV5UpgradeGoAhead extends Enum {
- readonly isAbort: boolean;
- readonly isGoAhead: boolean;
- readonly type: 'Abort' | 'GoAhead';
-}
-
-/** @name PolkadotPrimitivesV5UpgradeRestriction */
-export interface PolkadotPrimitivesV5UpgradeRestriction extends Enum {
- readonly isPresent: boolean;
- readonly type: 'Present';
-}
-
-/** @name PolkadotPrimitivesVstagingAsyncBackingParams */
-export interface PolkadotPrimitivesVstagingAsyncBackingParams extends Struct {
- readonly maxCandidateDepth: u32;
- readonly allowedAncestryLen: u32;
-}
-
-/** @name SpArithmeticArithmeticError */
-export interface SpArithmeticArithmeticError extends Enum {
- readonly isUnderflow: boolean;
- readonly isOverflow: boolean;
- readonly isDivisionByZero: boolean;
- readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero';
-}
-
-/** @name SpConsensusAuraSr25519AppSr25519Public */
-export interface SpConsensusAuraSr25519AppSr25519Public extends SpCoreSr25519Public {}
-
-/** @name SpCoreCryptoKeyTypeId */
-export interface SpCoreCryptoKeyTypeId extends U8aFixed {}
-
-/** @name SpCoreEcdsaSignature */
-export interface SpCoreEcdsaSignature extends U8aFixed {}
-
-/** @name SpCoreEd25519Signature */
-export interface SpCoreEd25519Signature extends U8aFixed {}
-
-/** @name SpCoreSr25519Public */
-export interface SpCoreSr25519Public extends U8aFixed {}
-
-/** @name SpCoreSr25519Signature */
-export interface SpCoreSr25519Signature extends U8aFixed {}
-
-/** @name SpCoreVoid */
-export interface SpCoreVoid extends Null {}
-
-/** @name SpRuntimeDigest */
-export interface SpRuntimeDigest extends Struct {
- readonly logs: Vec<SpRuntimeDigestDigestItem>;
-}
-
-/** @name SpRuntimeDigestDigestItem */
-export interface SpRuntimeDigestDigestItem extends Enum {
- readonly isOther: boolean;
- readonly asOther: Bytes;
- readonly isConsensus: boolean;
- readonly asConsensus: ITuple<[U8aFixed, Bytes]>;
- readonly isSeal: boolean;
- readonly asSeal: ITuple<[U8aFixed, Bytes]>;
- readonly isPreRuntime: boolean;
- readonly asPreRuntime: ITuple<[U8aFixed, Bytes]>;
- readonly isRuntimeEnvironmentUpdated: boolean;
- readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated';
-}
-
-/** @name SpRuntimeDispatchError */
-export interface SpRuntimeDispatchError extends Enum {
- readonly isOther: boolean;
- readonly isCannotLookup: boolean;
- readonly isBadOrigin: boolean;
- readonly isModule: boolean;
- readonly asModule: SpRuntimeModuleError;
- readonly isConsumerRemaining: boolean;
- readonly isNoProviders: boolean;
- readonly isTooManyConsumers: boolean;
- readonly isToken: boolean;
- readonly asToken: SpRuntimeTokenError;
- readonly isArithmetic: boolean;
- readonly asArithmetic: SpArithmeticArithmeticError;
- readonly isTransactional: boolean;
- readonly asTransactional: SpRuntimeTransactionalError;
- readonly isExhausted: boolean;
- readonly isCorruption: boolean;
- readonly isUnavailable: boolean;
- readonly isRootNotAllowed: boolean;
- readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional' | 'Exhausted' | 'Corruption' | 'Unavailable' | 'RootNotAllowed';
-}
-
-/** @name SpRuntimeModuleError */
-export interface SpRuntimeModuleError extends Struct {
- readonly index: u8;
- readonly error: U8aFixed;
-}
-
-/** @name SpRuntimeMultiSignature */
-export interface SpRuntimeMultiSignature extends Enum {
- readonly isEd25519: boolean;
- readonly asEd25519: SpCoreEd25519Signature;
- readonly isSr25519: boolean;
- readonly asSr25519: SpCoreSr25519Signature;
- readonly isEcdsa: boolean;
- readonly asEcdsa: SpCoreEcdsaSignature;
- readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
-}
-
-/** @name SpRuntimeTokenError */
-export interface SpRuntimeTokenError extends Enum {
- readonly isFundsUnavailable: boolean;
- readonly isOnlyProvider: boolean;
- readonly isBelowMinimum: boolean;
- readonly isCannotCreate: boolean;
- readonly isUnknownAsset: boolean;
- readonly isFrozen: boolean;
- readonly isUnsupported: boolean;
- readonly isCannotCreateHold: boolean;
- readonly isNotExpendable: boolean;
- readonly isBlocked: boolean;
- readonly type: 'FundsUnavailable' | 'OnlyProvider' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported' | 'CannotCreateHold' | 'NotExpendable' | 'Blocked';
-}
-
-/** @name SpRuntimeTransactionalError */
-export interface SpRuntimeTransactionalError extends Enum {
- readonly isLimitReached: boolean;
- readonly isNoLayer: boolean;
- readonly type: 'LimitReached' | 'NoLayer';
-}
-
-/** @name SpRuntimeTransactionValidityInvalidTransaction */
-export interface SpRuntimeTransactionValidityInvalidTransaction extends Enum {
- readonly isCall: boolean;
- readonly isPayment: boolean;
- readonly isFuture: boolean;
- readonly isStale: boolean;
- readonly isBadProof: boolean;
- readonly isAncientBirthBlock: boolean;
- readonly isExhaustsResources: boolean;
- readonly isCustom: boolean;
- readonly asCustom: u8;
- readonly isBadMandatory: boolean;
- readonly isMandatoryValidation: boolean;
- readonly isBadSigner: boolean;
- readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner';
-}
-
-/** @name SpRuntimeTransactionValidityTransactionValidityError */
-export interface SpRuntimeTransactionValidityTransactionValidityError extends Enum {
- readonly isInvalid: boolean;
- readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction;
- readonly isUnknown: boolean;
- readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction;
- readonly type: 'Invalid' | 'Unknown';
-}
-
-/** @name SpRuntimeTransactionValidityUnknownTransaction */
-export interface SpRuntimeTransactionValidityUnknownTransaction extends Enum {
- readonly isCannotLookup: boolean;
- readonly isNoUnsignedValidator: boolean;
- readonly isCustom: boolean;
- readonly asCustom: u8;
- readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom';
-}
-
-/** @name SpTrieStorageProof */
-export interface SpTrieStorageProof extends Struct {
- readonly trieNodes: BTreeSet<Bytes>;
-}
-
-/** @name SpVersionRuntimeVersion */
-export interface SpVersionRuntimeVersion extends Struct {
- readonly specName: Text;
- readonly implName: Text;
- readonly authoringVersion: u32;
- readonly specVersion: u32;
- readonly implVersion: u32;
- readonly apis: Vec<ITuple<[U8aFixed, u32]>>;
- readonly transactionVersion: u32;
- readonly stateVersion: u8;
-}
-
-/** @name SpWeightsRuntimeDbWeight */
-export interface SpWeightsRuntimeDbWeight extends Struct {
- readonly read: u64;
- readonly write: u64;
-}
-
-/** @name SpWeightsWeightV2Weight */
-export interface SpWeightsWeightV2Weight extends Struct {
- readonly refTime: Compact<u64>;
- readonly proofSize: Compact<u64>;
-}
-
-/** @name StagingXcmDoubleEncoded */
-export interface StagingXcmDoubleEncoded extends Struct {
- readonly encoded: Bytes;
-}
-
-/** @name StagingXcmV2BodyId */
-export interface StagingXcmV2BodyId extends Enum {
- readonly isUnit: boolean;
- readonly isNamed: boolean;
- readonly asNamed: Bytes;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u32>;
- readonly isExecutive: boolean;
- readonly isTechnical: boolean;
- readonly isLegislative: boolean;
- readonly isJudicial: boolean;
- readonly isDefense: boolean;
- readonly isAdministration: boolean;
- readonly isTreasury: boolean;
- readonly type: 'Unit' | 'Named' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
-}
-
-/** @name StagingXcmV2BodyPart */
-export interface StagingXcmV2BodyPart extends Enum {
- readonly isVoice: boolean;
- readonly isMembers: boolean;
- readonly asMembers: {
- readonly count: Compact<u32>;
- } & Struct;
- readonly isFraction: boolean;
- readonly asFraction: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isAtLeastProportion: boolean;
- readonly asAtLeastProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isMoreThanProportion: boolean;
- readonly asMoreThanProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
-}
-
-/** @name StagingXcmV2Instruction */
-export interface StagingXcmV2Instruction extends Enum {
- readonly isWithdrawAsset: boolean;
- readonly asWithdrawAsset: StagingXcmV2MultiassetMultiAssets;
- readonly isReserveAssetDeposited: boolean;
- readonly asReserveAssetDeposited: StagingXcmV2MultiassetMultiAssets;
- readonly isReceiveTeleportedAsset: boolean;
- readonly asReceiveTeleportedAsset: StagingXcmV2MultiassetMultiAssets;
- readonly isQueryResponse: boolean;
- readonly asQueryResponse: {
- readonly queryId: Compact<u64>;
- readonly response: StagingXcmV2Response;
- readonly maxWeight: Compact<u64>;
- } & Struct;
- readonly isTransferAsset: boolean;
- readonly asTransferAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssets;
- readonly beneficiary: StagingXcmV2MultiLocation;
- } & Struct;
- readonly isTransferReserveAsset: boolean;
- readonly asTransferReserveAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssets;
- readonly dest: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isTransact: boolean;
- readonly asTransact: {
- readonly originType: StagingXcmV2OriginKind;
- readonly requireWeightAtMost: Compact<u64>;
- readonly call: StagingXcmDoubleEncoded;
- } & Struct;
- readonly isHrmpNewChannelOpenRequest: boolean;
- readonly asHrmpNewChannelOpenRequest: {
- readonly sender: Compact<u32>;
- readonly maxMessageSize: Compact<u32>;
- readonly maxCapacity: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelAccepted: boolean;
- readonly asHrmpChannelAccepted: {
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelClosing: boolean;
- readonly asHrmpChannelClosing: {
- readonly initiator: Compact<u32>;
- readonly sender: Compact<u32>;
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isClearOrigin: boolean;
- readonly isDescendOrigin: boolean;
- readonly asDescendOrigin: StagingXcmV2MultilocationJunctions;
- readonly isReportError: boolean;
- readonly asReportError: {
- readonly queryId: Compact<u64>;
- readonly dest: StagingXcmV2MultiLocation;
- readonly maxResponseWeight: Compact<u64>;
- } & Struct;
- readonly isDepositAsset: boolean;
- readonly asDepositAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly maxAssets: Compact<u32>;
- readonly beneficiary: StagingXcmV2MultiLocation;
- } & Struct;
- readonly isDepositReserveAsset: boolean;
- readonly asDepositReserveAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly maxAssets: Compact<u32>;
- readonly dest: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isExchangeAsset: boolean;
- readonly asExchangeAsset: {
- readonly give: StagingXcmV2MultiassetMultiAssetFilter;
- readonly receive: StagingXcmV2MultiassetMultiAssets;
- } & Struct;
- readonly isInitiateReserveWithdraw: boolean;
- readonly asInitiateReserveWithdraw: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly reserve: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isInitiateTeleport: boolean;
- readonly asInitiateTeleport: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly dest: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isQueryHolding: boolean;
- readonly asQueryHolding: {
- readonly queryId: Compact<u64>;
- readonly dest: StagingXcmV2MultiLocation;
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly maxResponseWeight: Compact<u64>;
- } & Struct;
- readonly isBuyExecution: boolean;
- readonly asBuyExecution: {
- readonly fees: StagingXcmV2MultiAsset;
- readonly weightLimit: StagingXcmV2WeightLimit;
- } & Struct;
- readonly isRefundSurplus: boolean;
- readonly isSetErrorHandler: boolean;
- readonly asSetErrorHandler: StagingXcmV2Xcm;
- readonly isSetAppendix: boolean;
- readonly asSetAppendix: StagingXcmV2Xcm;
- readonly isClearError: boolean;
- readonly isClaimAsset: boolean;
- readonly asClaimAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssets;
- readonly ticket: StagingXcmV2MultiLocation;
- } & Struct;
- readonly isTrap: boolean;
- readonly asTrap: Compact<u64>;
- readonly isSubscribeVersion: boolean;
- readonly asSubscribeVersion: {
- readonly queryId: Compact<u64>;
- readonly maxResponseWeight: Compact<u64>;
- } & Struct;
- readonly isUnsubscribeVersion: boolean;
- readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion';
-}
-
-/** @name StagingXcmV2Junction */
-export interface StagingXcmV2Junction extends Enum {
- readonly isParachain: boolean;
- readonly asParachain: Compact<u32>;
- readonly isAccountId32: boolean;
- readonly asAccountId32: {
- readonly network: StagingXcmV2NetworkId;
- readonly id: U8aFixed;
- } & Struct;
- readonly isAccountIndex64: boolean;
- readonly asAccountIndex64: {
- readonly network: StagingXcmV2NetworkId;
- readonly index: Compact<u64>;
- } & Struct;
- readonly isAccountKey20: boolean;
- readonly asAccountKey20: {
- readonly network: StagingXcmV2NetworkId;
- readonly key: U8aFixed;
- } & Struct;
- readonly isPalletInstance: boolean;
- readonly asPalletInstance: u8;
- readonly isGeneralIndex: boolean;
- readonly asGeneralIndex: Compact<u128>;
- readonly isGeneralKey: boolean;
- readonly asGeneralKey: Bytes;
- readonly isOnlyChild: boolean;
- readonly isPlurality: boolean;
- readonly asPlurality: {
- readonly id: StagingXcmV2BodyId;
- readonly part: StagingXcmV2BodyPart;
- } & Struct;
- readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality';
-}
-
-/** @name StagingXcmV2MultiAsset */
-export interface StagingXcmV2MultiAsset extends Struct {
- readonly id: StagingXcmV2MultiassetAssetId;
- readonly fun: StagingXcmV2MultiassetFungibility;
-}
-
-/** @name StagingXcmV2MultiassetAssetId */
-export interface StagingXcmV2MultiassetAssetId extends Enum {
- readonly isConcrete: boolean;
- readonly asConcrete: StagingXcmV2MultiLocation;
- readonly isAbstract: boolean;
- readonly asAbstract: Bytes;
- readonly type: 'Concrete' | 'Abstract';
-}
-
-/** @name StagingXcmV2MultiassetAssetInstance */
-export interface StagingXcmV2MultiassetAssetInstance extends Enum {
- readonly isUndefined: boolean;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u128>;
- readonly isArray4: boolean;
- readonly asArray4: U8aFixed;
- readonly isArray8: boolean;
- readonly asArray8: U8aFixed;
- readonly isArray16: boolean;
- readonly asArray16: U8aFixed;
- readonly isArray32: boolean;
- readonly asArray32: U8aFixed;
- readonly isBlob: boolean;
- readonly asBlob: Bytes;
- readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32' | 'Blob';
-}
-
-/** @name StagingXcmV2MultiassetFungibility */
-export interface StagingXcmV2MultiassetFungibility extends Enum {
- readonly isFungible: boolean;
- readonly asFungible: Compact<u128>;
- readonly isNonFungible: boolean;
- readonly asNonFungible: StagingXcmV2MultiassetAssetInstance;
- readonly type: 'Fungible' | 'NonFungible';
-}
-
-/** @name StagingXcmV2MultiassetMultiAssetFilter */
-export interface StagingXcmV2MultiassetMultiAssetFilter extends Enum {
- readonly isDefinite: boolean;
- readonly asDefinite: StagingXcmV2MultiassetMultiAssets;
- readonly isWild: boolean;
- readonly asWild: StagingXcmV2MultiassetWildMultiAsset;
- readonly type: 'Definite' | 'Wild';
-}
-
-/** @name StagingXcmV2MultiassetMultiAssets */
-export interface StagingXcmV2MultiassetMultiAssets extends Vec<StagingXcmV2MultiAsset> {}
-
-/** @name StagingXcmV2MultiassetWildFungibility */
-export interface StagingXcmV2MultiassetWildFungibility extends Enum {
- readonly isFungible: boolean;
- readonly isNonFungible: boolean;
- readonly type: 'Fungible' | 'NonFungible';
-}
-
-/** @name StagingXcmV2MultiassetWildMultiAsset */
-export interface StagingXcmV2MultiassetWildMultiAsset extends Enum {
- readonly isAll: boolean;
- readonly isAllOf: boolean;
- readonly asAllOf: {
- readonly id: StagingXcmV2MultiassetAssetId;
- readonly fun: StagingXcmV2MultiassetWildFungibility;
- } & Struct;
- readonly type: 'All' | 'AllOf';
-}
-
-/** @name StagingXcmV2MultiLocation */
-export interface StagingXcmV2MultiLocation extends Struct {
- readonly parents: u8;
- readonly interior: StagingXcmV2MultilocationJunctions;
-}
-
-/** @name StagingXcmV2MultilocationJunctions */
-export interface StagingXcmV2MultilocationJunctions extends Enum {
- readonly isHere: boolean;
- readonly isX1: boolean;
- readonly asX1: StagingXcmV2Junction;
- readonly isX2: boolean;
- readonly asX2: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX3: boolean;
- readonly asX3: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX4: boolean;
- readonly asX4: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX5: boolean;
- readonly asX5: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX6: boolean;
- readonly asX6: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX7: boolean;
- readonly asX7: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX8: boolean;
- readonly asX8: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
-}
-
-/** @name StagingXcmV2NetworkId */
-export interface StagingXcmV2NetworkId extends Enum {
- readonly isAny: boolean;
- readonly isNamed: boolean;
- readonly asNamed: Bytes;
- readonly isPolkadot: boolean;
- readonly isKusama: boolean;
- readonly type: 'Any' | 'Named' | 'Polkadot' | 'Kusama';
-}
-
-/** @name StagingXcmV2OriginKind */
-export interface StagingXcmV2OriginKind extends Enum {
- readonly isNative: boolean;
- readonly isSovereignAccount: boolean;
- readonly isSuperuser: boolean;
- readonly isXcm: boolean;
- readonly type: 'Native' | 'SovereignAccount' | 'Superuser' | 'Xcm';
-}
-
-/** @name StagingXcmV2Response */
-export interface StagingXcmV2Response extends Enum {
- readonly isNull: boolean;
- readonly isAssets: boolean;
- readonly asAssets: StagingXcmV2MultiassetMultiAssets;
- readonly isExecutionResult: boolean;
- readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV2TraitsError]>>;
- readonly isVersion: boolean;
- readonly asVersion: u32;
- readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version';
-}
-
-/** @name StagingXcmV2TraitsError */
-export interface StagingXcmV2TraitsError extends Enum {
- readonly isOverflow: boolean;
- readonly isUnimplemented: boolean;
- readonly isUntrustedReserveLocation: boolean;
- readonly isUntrustedTeleportLocation: boolean;
- readonly isMultiLocationFull: boolean;
- readonly isMultiLocationNotInvertible: boolean;
- readonly isBadOrigin: boolean;
- readonly isInvalidLocation: boolean;
- readonly isAssetNotFound: boolean;
- readonly isFailedToTransactAsset: boolean;
- readonly isNotWithdrawable: boolean;
- readonly isLocationCannotHold: boolean;
- readonly isExceedsMaxMessageSize: boolean;
- readonly isDestinationUnsupported: boolean;
- readonly isTransport: boolean;
- readonly isUnroutable: boolean;
- readonly isUnknownClaim: boolean;
- readonly isFailedToDecode: boolean;
- readonly isMaxWeightInvalid: boolean;
- readonly isNotHoldingFees: boolean;
- readonly isTooExpensive: boolean;
- readonly isTrap: boolean;
- readonly asTrap: u64;
- readonly isUnhandledXcmVersion: boolean;
- readonly isWeightLimitReached: boolean;
- readonly asWeightLimitReached: u64;
- readonly isBarrier: boolean;
- readonly isWeightNotComputable: boolean;
- readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'MultiLocationFull' | 'MultiLocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable';
-}
-
-/** @name StagingXcmV2WeightLimit */
-export interface StagingXcmV2WeightLimit extends Enum {
- readonly isUnlimited: boolean;
- readonly isLimited: boolean;
- readonly asLimited: Compact<u64>;
- readonly type: 'Unlimited' | 'Limited';
-}
-
-/** @name StagingXcmV2Xcm */
-export interface StagingXcmV2Xcm extends Vec<StagingXcmV2Instruction> {}
-
-/** @name StagingXcmV3Instruction */
-export interface StagingXcmV3Instruction extends Enum {
- readonly isWithdrawAsset: boolean;
- readonly asWithdrawAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isReserveAssetDeposited: boolean;
- readonly asReserveAssetDeposited: StagingXcmV3MultiassetMultiAssets;
- readonly isReceiveTeleportedAsset: boolean;
- readonly asReceiveTeleportedAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isQueryResponse: boolean;
- readonly asQueryResponse: {
- readonly queryId: Compact<u64>;
- readonly response: StagingXcmV3Response;
- readonly maxWeight: SpWeightsWeightV2Weight;
- readonly querier: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly isTransferAsset: boolean;
- readonly asTransferAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly beneficiary: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isTransferReserveAsset: boolean;
- readonly asTransferReserveAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly dest: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isTransact: boolean;
- readonly asTransact: {
- readonly originKind: StagingXcmV2OriginKind;
- readonly requireWeightAtMost: SpWeightsWeightV2Weight;
- readonly call: StagingXcmDoubleEncoded;
- } & Struct;
- readonly isHrmpNewChannelOpenRequest: boolean;
- readonly asHrmpNewChannelOpenRequest: {
- readonly sender: Compact<u32>;
- readonly maxMessageSize: Compact<u32>;
- readonly maxCapacity: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelAccepted: boolean;
- readonly asHrmpChannelAccepted: {
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelClosing: boolean;
- readonly asHrmpChannelClosing: {
- readonly initiator: Compact<u32>;
- readonly sender: Compact<u32>;
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isClearOrigin: boolean;
- readonly isDescendOrigin: boolean;
- readonly asDescendOrigin: StagingXcmV3Junctions;
- readonly isReportError: boolean;
- readonly asReportError: StagingXcmV3QueryResponseInfo;
- readonly isDepositAsset: boolean;
- readonly asDepositAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly beneficiary: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isDepositReserveAsset: boolean;
- readonly asDepositReserveAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly dest: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isExchangeAsset: boolean;
- readonly asExchangeAsset: {
- readonly give: StagingXcmV3MultiassetMultiAssetFilter;
- readonly want: StagingXcmV3MultiassetMultiAssets;
- readonly maximal: bool;
- } & Struct;
- readonly isInitiateReserveWithdraw: boolean;
- readonly asInitiateReserveWithdraw: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly reserve: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isInitiateTeleport: boolean;
- readonly asInitiateTeleport: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly dest: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isReportHolding: boolean;
- readonly asReportHolding: {
- readonly responseInfo: StagingXcmV3QueryResponseInfo;
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- } & Struct;
- readonly isBuyExecution: boolean;
- readonly asBuyExecution: {
- readonly fees: StagingXcmV3MultiAsset;
- readonly weightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isRefundSurplus: boolean;
- readonly isSetErrorHandler: boolean;
- readonly asSetErrorHandler: StagingXcmV3Xcm;
- readonly isSetAppendix: boolean;
- readonly asSetAppendix: StagingXcmV3Xcm;
- readonly isClearError: boolean;
- readonly isClaimAsset: boolean;
- readonly asClaimAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly ticket: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isTrap: boolean;
- readonly asTrap: Compact<u64>;
- readonly isSubscribeVersion: boolean;
- readonly asSubscribeVersion: {
- readonly queryId: Compact<u64>;
- readonly maxResponseWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isUnsubscribeVersion: boolean;
- readonly isBurnAsset: boolean;
- readonly asBurnAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isExpectAsset: boolean;
- readonly asExpectAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isExpectOrigin: boolean;
- readonly asExpectOrigin: Option<StagingXcmV3MultiLocation>;
- readonly isExpectError: boolean;
- readonly asExpectError: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
- readonly isExpectTransactStatus: boolean;
- readonly asExpectTransactStatus: StagingXcmV3MaybeErrorCode;
- readonly isQueryPallet: boolean;
- readonly asQueryPallet: {
- readonly moduleName: Bytes;
- readonly responseInfo: StagingXcmV3QueryResponseInfo;
- } & Struct;
- readonly isExpectPallet: boolean;
- readonly asExpectPallet: {
- readonly index: Compact<u32>;
- readonly name: Bytes;
- readonly moduleName: Bytes;
- readonly crateMajor: Compact<u32>;
- readonly minCrateMinor: Compact<u32>;
- } & Struct;
- readonly isReportTransactStatus: boolean;
- readonly asReportTransactStatus: StagingXcmV3QueryResponseInfo;
- readonly isClearTransactStatus: boolean;
- readonly isUniversalOrigin: boolean;
- readonly asUniversalOrigin: StagingXcmV3Junction;
- readonly isExportMessage: boolean;
- readonly asExportMessage: {
- readonly network: StagingXcmV3JunctionNetworkId;
- readonly destination: StagingXcmV3Junctions;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isLockAsset: boolean;
- readonly asLockAsset: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly unlocker: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isUnlockAsset: boolean;
- readonly asUnlockAsset: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly target: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isNoteUnlockable: boolean;
- readonly asNoteUnlockable: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly owner: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isRequestUnlock: boolean;
- readonly asRequestUnlock: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly locker: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isSetFeesMode: boolean;
- readonly asSetFeesMode: {
- readonly jitWithdraw: bool;
- } & Struct;
- readonly isSetTopic: boolean;
- readonly asSetTopic: U8aFixed;
- readonly isClearTopic: boolean;
- readonly isAliasOrigin: boolean;
- readonly asAliasOrigin: StagingXcmV3MultiLocation;
- readonly isUnpaidExecution: boolean;
- readonly asUnpaidExecution: {
- readonly weightLimit: StagingXcmV3WeightLimit;
- readonly checkOrigin: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'ReportHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion' | 'BurnAsset' | 'ExpectAsset' | 'ExpectOrigin' | 'ExpectError' | 'ExpectTransactStatus' | 'QueryPallet' | 'ExpectPallet' | 'ReportTransactStatus' | 'ClearTransactStatus' | 'UniversalOrigin' | 'ExportMessage' | 'LockAsset' | 'UnlockAsset' | 'NoteUnlockable' | 'RequestUnlock' | 'SetFeesMode' | 'SetTopic' | 'ClearTopic' | 'AliasOrigin' | 'UnpaidExecution';
-}
-
-/** @name StagingXcmV3Junction */
-export interface StagingXcmV3Junction extends Enum {
- readonly isParachain: boolean;
- readonly asParachain: Compact<u32>;
- readonly isAccountId32: boolean;
- readonly asAccountId32: {
- readonly network: Option<StagingXcmV3JunctionNetworkId>;
- readonly id: U8aFixed;
- } & Struct;
- readonly isAccountIndex64: boolean;
- readonly asAccountIndex64: {
- readonly network: Option<StagingXcmV3JunctionNetworkId>;
- readonly index: Compact<u64>;
- } & Struct;
- readonly isAccountKey20: boolean;
- readonly asAccountKey20: {
- readonly network: Option<StagingXcmV3JunctionNetworkId>;
- readonly key: U8aFixed;
- } & Struct;
- readonly isPalletInstance: boolean;
- readonly asPalletInstance: u8;
- readonly isGeneralIndex: boolean;
- readonly asGeneralIndex: Compact<u128>;
- readonly isGeneralKey: boolean;
- readonly asGeneralKey: {
- readonly length: u8;
- readonly data: U8aFixed;
- } & Struct;
- readonly isOnlyChild: boolean;
- readonly isPlurality: boolean;
- readonly asPlurality: {
- readonly id: StagingXcmV3JunctionBodyId;
- readonly part: StagingXcmV3JunctionBodyPart;
- } & Struct;
- readonly isGlobalConsensus: boolean;
- readonly asGlobalConsensus: StagingXcmV3JunctionNetworkId;
- readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality' | 'GlobalConsensus';
-}
-
-/** @name StagingXcmV3JunctionBodyId */
-export interface StagingXcmV3JunctionBodyId extends Enum {
- readonly isUnit: boolean;
- readonly isMoniker: boolean;
- readonly asMoniker: U8aFixed;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u32>;
- readonly isExecutive: boolean;
- readonly isTechnical: boolean;
- readonly isLegislative: boolean;
- readonly isJudicial: boolean;
- readonly isDefense: boolean;
- readonly isAdministration: boolean;
- readonly isTreasury: boolean;
- readonly type: 'Unit' | 'Moniker' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
-}
-
-/** @name StagingXcmV3JunctionBodyPart */
-export interface StagingXcmV3JunctionBodyPart extends Enum {
- readonly isVoice: boolean;
- readonly isMembers: boolean;
- readonly asMembers: {
- readonly count: Compact<u32>;
- } & Struct;
- readonly isFraction: boolean;
- readonly asFraction: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isAtLeastProportion: boolean;
- readonly asAtLeastProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isMoreThanProportion: boolean;
- readonly asMoreThanProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
-}
-
-/** @name StagingXcmV3JunctionNetworkId */
-export interface StagingXcmV3JunctionNetworkId extends Enum {
- readonly isByGenesis: boolean;
- readonly asByGenesis: U8aFixed;
- readonly isByFork: boolean;
- readonly asByFork: {
- readonly blockNumber: u64;
- readonly blockHash: U8aFixed;
- } & Struct;
- readonly isPolkadot: boolean;
- readonly isKusama: boolean;
- readonly isWestend: boolean;
- readonly isRococo: boolean;
- readonly isWococo: boolean;
- readonly isEthereum: boolean;
- readonly asEthereum: {
- readonly chainId: Compact<u64>;
- } & Struct;
- readonly isBitcoinCore: boolean;
- readonly isBitcoinCash: boolean;
- readonly type: 'ByGenesis' | 'ByFork' | 'Polkadot' | 'Kusama' | 'Westend' | 'Rococo' | 'Wococo' | 'Ethereum' | 'BitcoinCore' | 'BitcoinCash';
-}
-
-/** @name StagingXcmV3Junctions */
-export interface StagingXcmV3Junctions extends Enum {
- readonly isHere: boolean;
- readonly isX1: boolean;
- readonly asX1: StagingXcmV3Junction;
- readonly isX2: boolean;
- readonly asX2: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX3: boolean;
- readonly asX3: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX4: boolean;
- readonly asX4: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX5: boolean;
- readonly asX5: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX6: boolean;
- readonly asX6: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX7: boolean;
- readonly asX7: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX8: boolean;
- readonly asX8: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
-}
-
-/** @name StagingXcmV3MaybeErrorCode */
-export interface StagingXcmV3MaybeErrorCode extends Enum {
- readonly isSuccess: boolean;
- readonly isError: boolean;
- readonly asError: Bytes;
- readonly isTruncatedError: boolean;
- readonly asTruncatedError: Bytes;
- readonly type: 'Success' | 'Error' | 'TruncatedError';
-}
-
-/** @name StagingXcmV3MultiAsset */
-export interface StagingXcmV3MultiAsset extends Struct {
- readonly id: StagingXcmV3MultiassetAssetId;
- readonly fun: StagingXcmV3MultiassetFungibility;
-}
-
-/** @name StagingXcmV3MultiassetAssetId */
-export interface StagingXcmV3MultiassetAssetId extends Enum {
- readonly isConcrete: boolean;
- readonly asConcrete: StagingXcmV3MultiLocation;
- readonly isAbstract: boolean;
- readonly asAbstract: U8aFixed;
- readonly type: 'Concrete' | 'Abstract';
-}
-
-/** @name StagingXcmV3MultiassetAssetInstance */
-export interface StagingXcmV3MultiassetAssetInstance extends Enum {
- readonly isUndefined: boolean;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u128>;
- readonly isArray4: boolean;
- readonly asArray4: U8aFixed;
- readonly isArray8: boolean;
- readonly asArray8: U8aFixed;
- readonly isArray16: boolean;
- readonly asArray16: U8aFixed;
- readonly isArray32: boolean;
- readonly asArray32: U8aFixed;
- readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32';
-}
-
-/** @name StagingXcmV3MultiassetFungibility */
-export interface StagingXcmV3MultiassetFungibility extends Enum {
- readonly isFungible: boolean;
- readonly asFungible: Compact<u128>;
- readonly isNonFungible: boolean;
- readonly asNonFungible: StagingXcmV3MultiassetAssetInstance;
- readonly type: 'Fungible' | 'NonFungible';
-}
-
-/** @name StagingXcmV3MultiassetMultiAssetFilter */
-export interface StagingXcmV3MultiassetMultiAssetFilter extends Enum {
- readonly isDefinite: boolean;
- readonly asDefinite: StagingXcmV3MultiassetMultiAssets;
- readonly isWild: boolean;
- readonly asWild: StagingXcmV3MultiassetWildMultiAsset;
- readonly type: 'Definite' | 'Wild';
-}
-
-/** @name StagingXcmV3MultiassetMultiAssets */
-export interface StagingXcmV3MultiassetMultiAssets extends Vec<StagingXcmV3MultiAsset> {}
-
-/** @name StagingXcmV3MultiassetWildFungibility */
-export interface StagingXcmV3MultiassetWildFungibility extends Enum {
- readonly isFungible: boolean;
- readonly isNonFungible: boolean;
- readonly type: 'Fungible' | 'NonFungible';
-}
-
-/** @name StagingXcmV3MultiassetWildMultiAsset */
-export interface StagingXcmV3MultiassetWildMultiAsset extends Enum {
- readonly isAll: boolean;
- readonly isAllOf: boolean;
- readonly asAllOf: {
- readonly id: StagingXcmV3MultiassetAssetId;
- readonly fun: StagingXcmV3MultiassetWildFungibility;
- } & Struct;
- readonly isAllCounted: boolean;
- readonly asAllCounted: Compact<u32>;
- readonly isAllOfCounted: boolean;
- readonly asAllOfCounted: {
- readonly id: StagingXcmV3MultiassetAssetId;
- readonly fun: StagingXcmV3MultiassetWildFungibility;
- readonly count: Compact<u32>;
- } & Struct;
- readonly type: 'All' | 'AllOf' | 'AllCounted' | 'AllOfCounted';
-}
-
-/** @name StagingXcmV3MultiLocation */
-export interface StagingXcmV3MultiLocation extends Struct {
- readonly parents: u8;
- readonly interior: StagingXcmV3Junctions;
-}
-
-/** @name StagingXcmV3PalletInfo */
-export interface StagingXcmV3PalletInfo extends Struct {
- readonly index: Compact<u32>;
- readonly name: Bytes;
- readonly moduleName: Bytes;
- readonly major: Compact<u32>;
- readonly minor: Compact<u32>;
- readonly patch: Compact<u32>;
-}
-
-/** @name StagingXcmV3QueryResponseInfo */
-export interface StagingXcmV3QueryResponseInfo extends Struct {
- readonly destination: StagingXcmV3MultiLocation;
- readonly queryId: Compact<u64>;
- readonly maxWeight: SpWeightsWeightV2Weight;
-}
-
-/** @name StagingXcmV3Response */
-export interface StagingXcmV3Response extends Enum {
- readonly isNull: boolean;
- readonly isAssets: boolean;
- readonly asAssets: StagingXcmV3MultiassetMultiAssets;
- readonly isExecutionResult: boolean;
- readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
- readonly isVersion: boolean;
- readonly asVersion: u32;
- readonly isPalletsInfo: boolean;
- readonly asPalletsInfo: Vec<StagingXcmV3PalletInfo>;
- readonly isDispatchResult: boolean;
- readonly asDispatchResult: StagingXcmV3MaybeErrorCode;
- readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version' | 'PalletsInfo' | 'DispatchResult';
-}
-
-/** @name StagingXcmV3TraitsError */
-export interface StagingXcmV3TraitsError extends Enum {
- readonly isOverflow: boolean;
- readonly isUnimplemented: boolean;
- readonly isUntrustedReserveLocation: boolean;
- readonly isUntrustedTeleportLocation: boolean;
- readonly isLocationFull: boolean;
- readonly isLocationNotInvertible: boolean;
- readonly isBadOrigin: boolean;
- readonly isInvalidLocation: boolean;
- readonly isAssetNotFound: boolean;
- readonly isFailedToTransactAsset: boolean;
- readonly isNotWithdrawable: boolean;
- readonly isLocationCannotHold: boolean;
- readonly isExceedsMaxMessageSize: boolean;
- readonly isDestinationUnsupported: boolean;
- readonly isTransport: boolean;
- readonly isUnroutable: boolean;
- readonly isUnknownClaim: boolean;
- readonly isFailedToDecode: boolean;
- readonly isMaxWeightInvalid: boolean;
- readonly isNotHoldingFees: boolean;
- readonly isTooExpensive: boolean;
- readonly isTrap: boolean;
- readonly asTrap: u64;
- readonly isExpectationFalse: boolean;
- readonly isPalletNotFound: boolean;
- readonly isNameMismatch: boolean;
- readonly isVersionIncompatible: boolean;
- readonly isHoldingWouldOverflow: boolean;
- readonly isExportError: boolean;
- readonly isReanchorFailed: boolean;
- readonly isNoDeal: boolean;
- readonly isFeesNotMet: boolean;
- readonly isLockError: boolean;
- readonly isNoPermission: boolean;
- readonly isUnanchored: boolean;
- readonly isNotDepositable: boolean;
- readonly isUnhandledXcmVersion: boolean;
- readonly isWeightLimitReached: boolean;
- readonly asWeightLimitReached: SpWeightsWeightV2Weight;
- readonly isBarrier: boolean;
- readonly isWeightNotComputable: boolean;
- readonly isExceedsStackLimit: boolean;
- readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'LocationFull' | 'LocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'ExpectationFalse' | 'PalletNotFound' | 'NameMismatch' | 'VersionIncompatible' | 'HoldingWouldOverflow' | 'ExportError' | 'ReanchorFailed' | 'NoDeal' | 'FeesNotMet' | 'LockError' | 'NoPermission' | 'Unanchored' | 'NotDepositable' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable' | 'ExceedsStackLimit';
-}
-
-/** @name StagingXcmV3TraitsOutcome */
-export interface StagingXcmV3TraitsOutcome extends Enum {
- readonly isComplete: boolean;
- readonly asComplete: SpWeightsWeightV2Weight;
- readonly isIncomplete: boolean;
- readonly asIncomplete: ITuple<[SpWeightsWeightV2Weight, StagingXcmV3TraitsError]>;
- readonly isError: boolean;
- readonly asError: StagingXcmV3TraitsError;
- readonly type: 'Complete' | 'Incomplete' | 'Error';
-}
-
-/** @name StagingXcmV3WeightLimit */
-export interface StagingXcmV3WeightLimit extends Enum {
- readonly isUnlimited: boolean;
- readonly isLimited: boolean;
- readonly asLimited: SpWeightsWeightV2Weight;
- readonly type: 'Unlimited' | 'Limited';
-}
-
-/** @name StagingXcmV3Xcm */
-export interface StagingXcmV3Xcm extends Vec<StagingXcmV3Instruction> {}
-
-/** @name StagingXcmVersionedAssetId */
-export interface StagingXcmVersionedAssetId extends Enum {
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiassetAssetId;
- readonly type: 'V3';
-}
-
-/** @name StagingXcmVersionedMultiAsset */
-export interface StagingXcmVersionedMultiAsset extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2MultiAsset;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiAsset;
- readonly type: 'V2' | 'V3';
-}
-
-/** @name StagingXcmVersionedMultiAssets */
-export interface StagingXcmVersionedMultiAssets extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2MultiassetMultiAssets;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiassetMultiAssets;
- readonly type: 'V2' | 'V3';
-}
-
-/** @name StagingXcmVersionedMultiLocation */
-export interface StagingXcmVersionedMultiLocation extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2MultiLocation;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiLocation;
- readonly type: 'V2' | 'V3';
-}
-
-/** @name StagingXcmVersionedResponse */
-export interface StagingXcmVersionedResponse extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2Response;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3Response;
- readonly type: 'V2' | 'V3';
-}
-
-/** @name StagingXcmVersionedXcm */
-export interface StagingXcmVersionedXcm extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2Xcm;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3Xcm;
- readonly type: 'V2' | 'V3';
-}
-
-/** @name UpDataStructsAccessMode */
-export interface UpDataStructsAccessMode extends Enum {
- readonly isNormal: boolean;
- readonly isAllowList: boolean;
- readonly type: 'Normal' | 'AllowList';
-}
-
-/** @name UpDataStructsCollection */
-export interface UpDataStructsCollection extends Struct {
- readonly owner: AccountId32;
- readonly mode: UpDataStructsCollectionMode;
- readonly name: Vec<u16>;
- readonly description: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
- readonly limits: UpDataStructsCollectionLimits;
- readonly permissions: UpDataStructsCollectionPermissions;
- readonly flags: U8aFixed;
-}
-
-/** @name UpDataStructsCollectionLimits */
-export interface UpDataStructsCollectionLimits extends Struct {
- readonly accountTokenOwnershipLimit: Option<u32>;
- readonly sponsoredDataSize: Option<u32>;
- readonly sponsoredDataRateLimit: Option<UpDataStructsSponsoringRateLimit>;
- readonly tokenLimit: Option<u32>;
- readonly sponsorTransferTimeout: Option<u32>;
- readonly sponsorApproveTimeout: Option<u32>;
- readonly ownerCanTransfer: Option<bool>;
- readonly ownerCanDestroy: Option<bool>;
- readonly transfersEnabled: Option<bool>;
-}
-
-/** @name UpDataStructsCollectionMode */
-export interface UpDataStructsCollectionMode extends Enum {
- readonly isNft: boolean;
- readonly isFungible: boolean;
- readonly asFungible: u8;
- readonly isReFungible: boolean;
- readonly type: 'Nft' | 'Fungible' | 'ReFungible';
-}
-
-/** @name UpDataStructsCollectionPermissions */
-export interface UpDataStructsCollectionPermissions extends Struct {
- readonly access: Option<UpDataStructsAccessMode>;
- readonly mintMode: Option<bool>;
- readonly nesting: Option<UpDataStructsNestingPermissions>;
-}
-
-/** @name UpDataStructsCollectionStats */
-export interface UpDataStructsCollectionStats extends Struct {
- readonly created: u32;
- readonly destroyed: u32;
- readonly alive: u32;
-}
-
-/** @name UpDataStructsCreateCollectionData */
-export interface UpDataStructsCreateCollectionData extends Struct {
- readonly mode: UpDataStructsCollectionMode;
- readonly access: Option<UpDataStructsAccessMode>;
- readonly name: Vec<u16>;
- readonly description: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly limits: Option<UpDataStructsCollectionLimits>;
- readonly permissions: Option<UpDataStructsCollectionPermissions>;
- readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
- readonly properties: Vec<UpDataStructsProperty>;
- readonly adminList: Vec<PalletEvmAccountBasicCrossAccountIdRepr>;
- readonly pendingSponsor: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
- readonly flags: U8aFixed;
-}
-
-/** @name UpDataStructsCreateFungibleData */
-export interface UpDataStructsCreateFungibleData extends Struct {
- readonly value: u128;
-}
-
-/** @name UpDataStructsCreateItemData */
-export interface UpDataStructsCreateItemData extends Enum {
- readonly isNft: boolean;
- readonly asNft: UpDataStructsCreateNftData;
- readonly isFungible: boolean;
- readonly asFungible: UpDataStructsCreateFungibleData;
- readonly isReFungible: boolean;
- readonly asReFungible: UpDataStructsCreateReFungibleData;
- readonly type: 'Nft' | 'Fungible' | 'ReFungible';
-}
-
-/** @name UpDataStructsCreateItemExData */
-export interface UpDataStructsCreateItemExData extends Enum {
- readonly isNft: boolean;
- readonly asNft: Vec<UpDataStructsCreateNftExData>;
- readonly isFungible: boolean;
- readonly asFungible: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr,u128>;
- readonly isRefungibleMultipleItems: boolean;
- readonly asRefungibleMultipleItems: Vec<UpDataStructsCreateRefungibleExSingleOwner>;
- readonly isRefungibleMultipleOwners: boolean;
- readonly asRefungibleMultipleOwners: UpDataStructsCreateRefungibleExMultipleOwners;
- readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
-}
-
-/** @name UpDataStructsCreateNftData */
-export interface UpDataStructsCreateNftData extends Struct {
- readonly properties: Vec<UpDataStructsProperty>;
-}
-
-/** @name UpDataStructsCreateNftExData */
-export interface UpDataStructsCreateNftExData extends Struct {
- readonly properties: Vec<UpDataStructsProperty>;
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
-}
-
-/** @name UpDataStructsCreateReFungibleData */
-export interface UpDataStructsCreateReFungibleData extends Struct {
- readonly pieces: u128;
- readonly properties: Vec<UpDataStructsProperty>;
-}
-
-/** @name UpDataStructsCreateRefungibleExMultipleOwners */
-export interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
- readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
- readonly properties: Vec<UpDataStructsProperty>;
-}
-
-/** @name UpDataStructsCreateRefungibleExSingleOwner */
-export interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
- readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly pieces: u128;
- readonly properties: Vec<UpDataStructsProperty>;
-}
-
-/** @name UpDataStructsNestingPermissions */
-export interface UpDataStructsNestingPermissions extends Struct {
- readonly tokenOwner: bool;
- readonly collectionAdmin: bool;
- readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
-}
-
-/** @name UpDataStructsOwnerRestrictedSet */
-export interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
-
-/** @name UpDataStructsProperties */
-export interface UpDataStructsProperties extends Struct {
- readonly map: UpDataStructsPropertiesMapBoundedVec;
- readonly consumedSpace: u32;
- readonly reserved: u32;
-}
-
-/** @name UpDataStructsPropertiesMapBoundedVec */
-export interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
-
-/** @name UpDataStructsPropertiesMapPropertyPermission */
-export interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
-
-/** @name UpDataStructsProperty */
-export interface UpDataStructsProperty extends Struct {
- readonly key: Bytes;
- readonly value: Bytes;
-}
-
-/** @name UpDataStructsPropertyKeyPermission */
-export interface UpDataStructsPropertyKeyPermission extends Struct {
- readonly key: Bytes;
- readonly permission: UpDataStructsPropertyPermission;
-}
-
-/** @name UpDataStructsPropertyPermission */
-export interface UpDataStructsPropertyPermission extends Struct {
- readonly mutable: bool;
- readonly collectionAdmin: bool;
- readonly tokenOwner: bool;
-}
-
-/** @name UpDataStructsPropertyScope */
-export interface UpDataStructsPropertyScope extends Enum {
- readonly isNone: boolean;
- readonly isRmrk: boolean;
- readonly type: 'None' | 'Rmrk';
-}
-
-/** @name UpDataStructsRpcCollection */
-export interface UpDataStructsRpcCollection extends Struct {
- readonly owner: AccountId32;
- readonly mode: UpDataStructsCollectionMode;
- readonly name: Vec<u16>;
- readonly description: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
- readonly limits: UpDataStructsCollectionLimits;
- readonly permissions: UpDataStructsCollectionPermissions;
- readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
- readonly properties: Vec<UpDataStructsProperty>;
- readonly readOnly: bool;
- readonly flags: UpDataStructsRpcCollectionFlags;
-}
-
-/** @name UpDataStructsRpcCollectionFlags */
-export interface UpDataStructsRpcCollectionFlags extends Struct {
- readonly foreign: bool;
- readonly erc721metadata: bool;
-}
-
-/** @name UpDataStructsSponsoringRateLimit */
-export interface UpDataStructsSponsoringRateLimit extends Enum {
- readonly isSponsoringDisabled: boolean;
- readonly isBlocks: boolean;
- readonly asBlocks: u32;
- readonly type: 'SponsoringDisabled' | 'Blocks';
-}
-
-/** @name UpDataStructsSponsorshipStateAccountId32 */
-export interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
- readonly isDisabled: boolean;
- readonly isUnconfirmed: boolean;
- readonly asUnconfirmed: AccountId32;
- readonly isConfirmed: boolean;
- readonly asConfirmed: AccountId32;
- readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
-}
-
-/** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr */
-export interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
- readonly isDisabled: boolean;
- readonly isUnconfirmed: boolean;
- readonly asUnconfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly isConfirmed: boolean;
- readonly asConfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
-}
-
-/** @name UpDataStructsTokenChild */
-export interface UpDataStructsTokenChild extends Struct {
- readonly token: u32;
- readonly collection: u32;
-}
-
-/** @name UpDataStructsTokenData */
-export interface UpDataStructsTokenData extends Struct {
- readonly properties: Vec<UpDataStructsProperty>;
- readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
- readonly pieces: u128;
-}
-
-/** @name UpPovEstimateRpcPovInfo */
-export interface UpPovEstimateRpcPovInfo extends Struct {
- readonly proofSize: u64;
- readonly compactProofSize: u64;
- readonly compressedProofSize: u64;
- readonly results: Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>;
- readonly keyValues: Vec<UpPovEstimateRpcTrieKeyValue>;
-}
-
-/** @name UpPovEstimateRpcTrieKeyValue */
-export interface UpPovEstimateRpcTrieKeyValue extends Struct {
- readonly key: Bytes;
- readonly value: Bytes;
-}
-
-export type PHANTOM_DEFAULT = 'default';
js-packages/types/src/definitions.tsdiffbeforeafterboth--- a/js-packages/types/src/definitions.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-export {default as unique} from './unique/definitions.js';
-export {default as appPromotion} from './appPromotion/definitions.js';
-export {default as povinfo} from './povinfo/definitions.js';
-export {default as default} from './default/definitions.js';
js-packages/types/src/index.tsdiffbeforeafterboth--- a/js-packages/types/src/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './types.js';
js-packages/types/src/lookup.tsdiffbeforeafterboth--- a/js-packages/types/src/lookup.ts
+++ /dev/null
@@ -1,5165 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-/* eslint-disable sort-keys */
-
-export default {
- /**
- * Lookup3: frame_system::AccountInfo<Nonce, pallet_balances::types::AccountData<Balance>>
- **/
- FrameSystemAccountInfo: {
- nonce: 'u32',
- consumers: 'u32',
- providers: 'u32',
- sufficients: 'u32',
- data: 'PalletBalancesAccountData'
- },
- /**
- * Lookup5: pallet_balances::types::AccountData<Balance>
- **/
- PalletBalancesAccountData: {
- free: 'u128',
- reserved: 'u128',
- frozen: 'u128',
- flags: 'u128'
- },
- /**
- * Lookup8: frame_support::dispatch::PerDispatchClass<sp_weights::weight_v2::Weight>
- **/
- FrameSupportDispatchPerDispatchClassWeight: {
- normal: 'SpWeightsWeightV2Weight',
- operational: 'SpWeightsWeightV2Weight',
- mandatory: 'SpWeightsWeightV2Weight'
- },
- /**
- * Lookup9: sp_weights::weight_v2::Weight
- **/
- SpWeightsWeightV2Weight: {
- refTime: 'Compact<u64>',
- proofSize: 'Compact<u64>'
- },
- /**
- * Lookup14: sp_runtime::generic::digest::Digest
- **/
- SpRuntimeDigest: {
- logs: 'Vec<SpRuntimeDigestDigestItem>'
- },
- /**
- * Lookup16: sp_runtime::generic::digest::DigestItem
- **/
- SpRuntimeDigestDigestItem: {
- _enum: {
- Other: 'Bytes',
- __Unused1: 'Null',
- __Unused2: 'Null',
- __Unused3: 'Null',
- Consensus: '([u8;4],Bytes)',
- Seal: '([u8;4],Bytes)',
- PreRuntime: '([u8;4],Bytes)',
- __Unused7: 'Null',
- RuntimeEnvironmentUpdated: 'Null'
- }
- },
- /**
- * Lookup19: frame_system::EventRecord<opal_runtime::RuntimeEvent, primitive_types::H256>
- **/
- FrameSystemEventRecord: {
- phase: 'FrameSystemPhase',
- event: 'Event',
- topics: 'Vec<H256>'
- },
- /**
- * Lookup21: frame_system::pallet::Event<T>
- **/
- FrameSystemEvent: {
- _enum: {
- ExtrinsicSuccess: {
- dispatchInfo: 'FrameSupportDispatchDispatchInfo',
- },
- ExtrinsicFailed: {
- dispatchError: 'SpRuntimeDispatchError',
- dispatchInfo: 'FrameSupportDispatchDispatchInfo',
- },
- CodeUpdated: 'Null',
- NewAccount: {
- account: 'AccountId32',
- },
- KilledAccount: {
- account: 'AccountId32',
- },
- Remarked: {
- _alias: {
- hash_: 'hash',
- },
- sender: 'AccountId32',
- hash_: 'H256'
- }
- }
- },
- /**
- * Lookup22: frame_support::dispatch::DispatchInfo
- **/
- FrameSupportDispatchDispatchInfo: {
- weight: 'SpWeightsWeightV2Weight',
- class: 'FrameSupportDispatchDispatchClass',
- paysFee: 'FrameSupportDispatchPays'
- },
- /**
- * Lookup23: frame_support::dispatch::DispatchClass
- **/
- FrameSupportDispatchDispatchClass: {
- _enum: ['Normal', 'Operational', 'Mandatory']
- },
- /**
- * Lookup24: frame_support::dispatch::Pays
- **/
- FrameSupportDispatchPays: {
- _enum: ['Yes', 'No']
- },
- /**
- * Lookup25: sp_runtime::DispatchError
- **/
- SpRuntimeDispatchError: {
- _enum: {
- Other: 'Null',
- CannotLookup: 'Null',
- BadOrigin: 'Null',
- Module: 'SpRuntimeModuleError',
- ConsumerRemaining: 'Null',
- NoProviders: 'Null',
- TooManyConsumers: 'Null',
- Token: 'SpRuntimeTokenError',
- Arithmetic: 'SpArithmeticArithmeticError',
- Transactional: 'SpRuntimeTransactionalError',
- Exhausted: 'Null',
- Corruption: 'Null',
- Unavailable: 'Null',
- RootNotAllowed: 'Null'
- }
- },
- /**
- * Lookup26: sp_runtime::ModuleError
- **/
- SpRuntimeModuleError: {
- index: 'u8',
- error: '[u8;4]'
- },
- /**
- * Lookup27: sp_runtime::TokenError
- **/
- SpRuntimeTokenError: {
- _enum: ['FundsUnavailable', 'OnlyProvider', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported', 'CannotCreateHold', 'NotExpendable', 'Blocked']
- },
- /**
- * Lookup28: sp_arithmetic::ArithmeticError
- **/
- SpArithmeticArithmeticError: {
- _enum: ['Underflow', 'Overflow', 'DivisionByZero']
- },
- /**
- * Lookup29: sp_runtime::TransactionalError
- **/
- SpRuntimeTransactionalError: {
- _enum: ['LimitReached', 'NoLayer']
- },
- /**
- * Lookup30: pallet_state_trie_migration::pallet::Event<T>
- **/
- PalletStateTrieMigrationEvent: {
- _enum: {
- Migrated: {
- top: 'u32',
- child: 'u32',
- compute: 'PalletStateTrieMigrationMigrationCompute',
- },
- Slashed: {
- who: 'AccountId32',
- amount: 'u128',
- },
- AutoMigrationFinished: 'Null',
- Halted: {
- error: 'PalletStateTrieMigrationError'
- }
- }
- },
- /**
- * Lookup31: pallet_state_trie_migration::pallet::MigrationCompute
- **/
- PalletStateTrieMigrationMigrationCompute: {
- _enum: ['Signed', 'Auto']
- },
- /**
- * Lookup32: pallet_state_trie_migration::pallet::Error<T>
- **/
- PalletStateTrieMigrationError: {
- _enum: ['MaxSignedLimits', 'KeyTooLong', 'NotEnoughFunds', 'BadWitness', 'SignedMigrationNotAllowed', 'BadChildRoot']
- },
- /**
- * Lookup33: cumulus_pallet_parachain_system::pallet::Event<T>
- **/
- CumulusPalletParachainSystemEvent: {
- _enum: {
- ValidationFunctionStored: 'Null',
- ValidationFunctionApplied: {
- relayChainBlockNum: 'u32',
- },
- ValidationFunctionDiscarded: 'Null',
- UpgradeAuthorized: {
- codeHash: 'H256',
- },
- DownwardMessagesReceived: {
- count: 'u32',
- },
- DownwardMessagesProcessed: {
- weightUsed: 'SpWeightsWeightV2Weight',
- dmqHead: 'H256',
- },
- UpwardMessageSent: {
- messageHash: 'Option<[u8;32]>'
- }
- }
- },
- /**
- * Lookup35: pallet_collator_selection::pallet::Event<T>
- **/
- PalletCollatorSelectionEvent: {
- _enum: {
- InvulnerableAdded: {
- invulnerable: 'AccountId32',
- },
- InvulnerableRemoved: {
- invulnerable: 'AccountId32',
- },
- LicenseObtained: {
- accountId: 'AccountId32',
- deposit: 'u128',
- },
- LicenseReleased: {
- accountId: 'AccountId32',
- depositReturned: 'u128',
- },
- CandidateAdded: {
- accountId: 'AccountId32',
- },
- CandidateRemoved: {
- accountId: 'AccountId32'
- }
- }
- },
- /**
- * Lookup36: pallet_session::pallet::Event
- **/
- PalletSessionEvent: {
- _enum: {
- NewSession: {
- sessionIndex: 'u32'
- }
- }
- },
- /**
- * Lookup37: pallet_balances::pallet::Event<T, I>
- **/
- PalletBalancesEvent: {
- _enum: {
- Endowed: {
- account: 'AccountId32',
- freeBalance: 'u128',
- },
- DustLost: {
- account: 'AccountId32',
- amount: 'u128',
- },
- Transfer: {
- from: 'AccountId32',
- to: 'AccountId32',
- amount: 'u128',
- },
- BalanceSet: {
- who: 'AccountId32',
- free: 'u128',
- },
- Reserved: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Unreserved: {
- who: 'AccountId32',
- amount: 'u128',
- },
- ReserveRepatriated: {
- from: 'AccountId32',
- to: 'AccountId32',
- amount: 'u128',
- destinationStatus: 'FrameSupportTokensMiscBalanceStatus',
- },
- Deposit: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Withdraw: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Slashed: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Minted: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Burned: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Suspended: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Restored: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Upgraded: {
- who: 'AccountId32',
- },
- Issued: {
- amount: 'u128',
- },
- Rescinded: {
- amount: 'u128',
- },
- Locked: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Unlocked: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Frozen: {
- who: 'AccountId32',
- amount: 'u128',
- },
- Thawed: {
- who: 'AccountId32',
- amount: 'u128'
- }
- }
- },
- /**
- * Lookup38: frame_support::traits::tokens::misc::BalanceStatus
- **/
- FrameSupportTokensMiscBalanceStatus: {
- _enum: ['Free', 'Reserved']
- },
- /**
- * Lookup39: pallet_transaction_payment::pallet::Event<T>
- **/
- PalletTransactionPaymentEvent: {
- _enum: {
- TransactionFeePaid: {
- who: 'AccountId32',
- actualFee: 'u128',
- tip: 'u128'
- }
- }
- },
- /**
- * Lookup40: pallet_treasury::pallet::Event<T, I>
- **/
- PalletTreasuryEvent: {
- _enum: {
- Proposed: {
- proposalIndex: 'u32',
- },
- Spending: {
- budgetRemaining: 'u128',
- },
- Awarded: {
- proposalIndex: 'u32',
- award: 'u128',
- account: 'AccountId32',
- },
- Rejected: {
- proposalIndex: 'u32',
- slashed: 'u128',
- },
- Burnt: {
- burntFunds: 'u128',
- },
- Rollover: {
- rolloverBalance: 'u128',
- },
- Deposit: {
- value: 'u128',
- },
- SpendApproved: {
- proposalIndex: 'u32',
- amount: 'u128',
- beneficiary: 'AccountId32',
- },
- UpdatedInactive: {
- reactivated: 'u128',
- deactivated: 'u128'
- }
- }
- },
- /**
- * Lookup41: pallet_sudo::pallet::Event<T>
- **/
- PalletSudoEvent: {
- _enum: {
- Sudid: {
- sudoResult: 'Result<Null, SpRuntimeDispatchError>',
- },
- KeyChanged: {
- oldSudoer: 'Option<AccountId32>',
- },
- SudoAsDone: {
- sudoResult: 'Result<Null, SpRuntimeDispatchError>'
- }
- }
- },
- /**
- * Lookup45: orml_vesting::module::Event<T>
- **/
- OrmlVestingModuleEvent: {
- _enum: {
- VestingScheduleAdded: {
- from: 'AccountId32',
- to: 'AccountId32',
- vestingSchedule: 'OrmlVestingVestingSchedule',
- },
- Claimed: {
- who: 'AccountId32',
- amount: 'u128',
- },
- VestingSchedulesUpdated: {
- who: 'AccountId32'
- }
- }
- },
- /**
- * Lookup46: orml_vesting::VestingSchedule<BlockNumber, Balance>
- **/
- OrmlVestingVestingSchedule: {
- start: 'u32',
- period: 'u32',
- periodCount: 'u32',
- perPeriod: 'Compact<u128>'
- },
- /**
- * Lookup48: orml_xtokens::module::Event<T>
- **/
- OrmlXtokensModuleEvent: {
- _enum: {
- TransferredMultiAssets: {
- sender: 'AccountId32',
- assets: 'StagingXcmV3MultiassetMultiAssets',
- fee: 'StagingXcmV3MultiAsset',
- dest: 'StagingXcmV3MultiLocation'
- }
- }
- },
- /**
- * Lookup49: staging_xcm::v3::multiasset::MultiAssets
- **/
- StagingXcmV3MultiassetMultiAssets: 'Vec<StagingXcmV3MultiAsset>',
- /**
- * Lookup51: staging_xcm::v3::multiasset::MultiAsset
- **/
- StagingXcmV3MultiAsset: {
- id: 'StagingXcmV3MultiassetAssetId',
- fun: 'StagingXcmV3MultiassetFungibility'
- },
- /**
- * Lookup52: staging_xcm::v3::multiasset::AssetId
- **/
- StagingXcmV3MultiassetAssetId: {
- _enum: {
- Concrete: 'StagingXcmV3MultiLocation',
- Abstract: '[u8;32]'
- }
- },
- /**
- * Lookup53: staging_xcm::v3::multilocation::MultiLocation
- **/
- StagingXcmV3MultiLocation: {
- parents: 'u8',
- interior: 'StagingXcmV3Junctions'
- },
- /**
- * Lookup54: staging_xcm::v3::junctions::Junctions
- **/
- StagingXcmV3Junctions: {
- _enum: {
- Here: 'Null',
- X1: 'StagingXcmV3Junction',
- X2: '(StagingXcmV3Junction,StagingXcmV3Junction)',
- X3: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
- X4: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
- X5: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
- X6: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
- X7: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)',
- X8: '(StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction,StagingXcmV3Junction)'
- }
- },
- /**
- * Lookup55: staging_xcm::v3::junction::Junction
- **/
- StagingXcmV3Junction: {
- _enum: {
- Parachain: 'Compact<u32>',
- AccountId32: {
- network: 'Option<StagingXcmV3JunctionNetworkId>',
- id: '[u8;32]',
- },
- AccountIndex64: {
- network: 'Option<StagingXcmV3JunctionNetworkId>',
- index: 'Compact<u64>',
- },
- AccountKey20: {
- network: 'Option<StagingXcmV3JunctionNetworkId>',
- key: '[u8;20]',
- },
- PalletInstance: 'u8',
- GeneralIndex: 'Compact<u128>',
- GeneralKey: {
- length: 'u8',
- data: '[u8;32]',
- },
- OnlyChild: 'Null',
- Plurality: {
- id: 'StagingXcmV3JunctionBodyId',
- part: 'StagingXcmV3JunctionBodyPart',
- },
- GlobalConsensus: 'StagingXcmV3JunctionNetworkId'
- }
- },
- /**
- * Lookup58: staging_xcm::v3::junction::NetworkId
- **/
- StagingXcmV3JunctionNetworkId: {
- _enum: {
- ByGenesis: '[u8;32]',
- ByFork: {
- blockNumber: 'u64',
- blockHash: '[u8;32]',
- },
- Polkadot: 'Null',
- Kusama: 'Null',
- Westend: 'Null',
- Rococo: 'Null',
- Wococo: 'Null',
- Ethereum: {
- chainId: 'Compact<u64>',
- },
- BitcoinCore: 'Null',
- BitcoinCash: 'Null'
- }
- },
- /**
- * Lookup60: staging_xcm::v3::junction::BodyId
- **/
- StagingXcmV3JunctionBodyId: {
- _enum: {
- Unit: 'Null',
- Moniker: '[u8;4]',
- Index: 'Compact<u32>',
- Executive: 'Null',
- Technical: 'Null',
- Legislative: 'Null',
- Judicial: 'Null',
- Defense: 'Null',
- Administration: 'Null',
- Treasury: 'Null'
- }
- },
- /**
- * Lookup61: staging_xcm::v3::junction::BodyPart
- **/
- StagingXcmV3JunctionBodyPart: {
- _enum: {
- Voice: 'Null',
- Members: {
- count: 'Compact<u32>',
- },
- Fraction: {
- nom: 'Compact<u32>',
- denom: 'Compact<u32>',
- },
- AtLeastProportion: {
- nom: 'Compact<u32>',
- denom: 'Compact<u32>',
- },
- MoreThanProportion: {
- nom: 'Compact<u32>',
- denom: 'Compact<u32>'
- }
- }
- },
- /**
- * Lookup62: staging_xcm::v3::multiasset::Fungibility
- **/
- StagingXcmV3MultiassetFungibility: {
- _enum: {
- Fungible: 'Compact<u128>',
- NonFungible: 'StagingXcmV3MultiassetAssetInstance'
- }
- },
- /**
- * Lookup63: staging_xcm::v3::multiasset::AssetInstance
- **/
- StagingXcmV3MultiassetAssetInstance: {
- _enum: {
- Undefined: 'Null',
- Index: 'Compact<u128>',
- Array4: '[u8;4]',
- Array8: '[u8;8]',
- Array16: '[u8;16]',
- Array32: '[u8;32]'
- }
- },
- /**
- * Lookup66: orml_tokens::module::Event<T>
- **/
- OrmlTokensModuleEvent: {
- _enum: {
- Endowed: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- DustLost: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- Transfer: {
- currencyId: 'PalletForeignAssetsAssetId',
- from: 'AccountId32',
- to: 'AccountId32',
- amount: 'u128',
- },
- Reserved: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- Unreserved: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- ReserveRepatriated: {
- currencyId: 'PalletForeignAssetsAssetId',
- from: 'AccountId32',
- to: 'AccountId32',
- amount: 'u128',
- status: 'FrameSupportTokensMiscBalanceStatus',
- },
- BalanceSet: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- free: 'u128',
- reserved: 'u128',
- },
- TotalIssuanceSet: {
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'u128',
- },
- Withdrawn: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- Slashed: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- freeAmount: 'u128',
- reservedAmount: 'u128',
- },
- Deposited: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- LockSet: {
- lockId: '[u8;8]',
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- LockRemoved: {
- lockId: '[u8;8]',
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- },
- Locked: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- Unlocked: {
- currencyId: 'PalletForeignAssetsAssetId',
- who: 'AccountId32',
- amount: 'u128',
- },
- Issued: {
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'u128',
- },
- Rescinded: {
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'u128'
- }
- }
- },
- /**
- * Lookup67: pallet_foreign_assets::AssetId
- **/
- PalletForeignAssetsAssetId: {
- _enum: {
- ForeignAssetId: 'u32',
- NativeAssetId: 'PalletForeignAssetsNativeCurrency'
- }
- },
- /**
- * Lookup68: pallet_foreign_assets::NativeCurrency
- **/
- PalletForeignAssetsNativeCurrency: {
- _enum: ['Here', 'Parent']
- },
- /**
- * Lookup69: pallet_identity::pallet::Event<T>
- **/
- PalletIdentityEvent: {
- _enum: {
- IdentitySet: {
- who: 'AccountId32',
- },
- IdentityCleared: {
- who: 'AccountId32',
- deposit: 'u128',
- },
- IdentityKilled: {
- who: 'AccountId32',
- deposit: 'u128',
- },
- IdentitiesInserted: {
- amount: 'u32',
- },
- IdentitiesRemoved: {
- amount: 'u32',
- },
- JudgementRequested: {
- who: 'AccountId32',
- registrarIndex: 'u32',
- },
- JudgementUnrequested: {
- who: 'AccountId32',
- registrarIndex: 'u32',
- },
- JudgementGiven: {
- target: 'AccountId32',
- registrarIndex: 'u32',
- },
- RegistrarAdded: {
- registrarIndex: 'u32',
- },
- SubIdentityAdded: {
- sub: 'AccountId32',
- main: 'AccountId32',
- deposit: 'u128',
- },
- SubIdentityRemoved: {
- sub: 'AccountId32',
- main: 'AccountId32',
- deposit: 'u128',
- },
- SubIdentityRevoked: {
- sub: 'AccountId32',
- main: 'AccountId32',
- deposit: 'u128',
- },
- SubIdentitiesInserted: {
- amount: 'u32'
- }
- }
- },
- /**
- * Lookup70: pallet_preimage::pallet::Event<T>
- **/
- PalletPreimageEvent: {
- _enum: {
- Noted: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- },
- Requested: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- },
- Cleared: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256'
- }
- }
- },
- /**
- * Lookup71: pallet_democracy::pallet::Event<T>
- **/
- PalletDemocracyEvent: {
- _enum: {
- Proposed: {
- proposalIndex: 'u32',
- deposit: 'u128',
- },
- Tabled: {
- proposalIndex: 'u32',
- deposit: 'u128',
- },
- ExternalTabled: 'Null',
- Started: {
- refIndex: 'u32',
- threshold: 'PalletDemocracyVoteThreshold',
- },
- Passed: {
- refIndex: 'u32',
- },
- NotPassed: {
- refIndex: 'u32',
- },
- Cancelled: {
- refIndex: 'u32',
- },
- Delegated: {
- who: 'AccountId32',
- target: 'AccountId32',
- },
- Undelegated: {
- account: 'AccountId32',
- },
- Vetoed: {
- who: 'AccountId32',
- proposalHash: 'H256',
- until: 'u32',
- },
- Blacklisted: {
- proposalHash: 'H256',
- },
- Voted: {
- voter: 'AccountId32',
- refIndex: 'u32',
- vote: 'PalletDemocracyVoteAccountVote',
- },
- Seconded: {
- seconder: 'AccountId32',
- propIndex: 'u32',
- },
- ProposalCanceled: {
- propIndex: 'u32',
- },
- MetadataSet: {
- _alias: {
- hash_: 'hash',
- },
- owner: 'PalletDemocracyMetadataOwner',
- hash_: 'H256',
- },
- MetadataCleared: {
- _alias: {
- hash_: 'hash',
- },
- owner: 'PalletDemocracyMetadataOwner',
- hash_: 'H256',
- },
- MetadataTransferred: {
- _alias: {
- hash_: 'hash',
- },
- prevOwner: 'PalletDemocracyMetadataOwner',
- owner: 'PalletDemocracyMetadataOwner',
- hash_: 'H256'
- }
- }
- },
- /**
- * Lookup72: pallet_democracy::vote_threshold::VoteThreshold
- **/
- PalletDemocracyVoteThreshold: {
- _enum: ['SuperMajorityApprove', 'SuperMajorityAgainst', 'SimpleMajority']
- },
- /**
- * Lookup73: pallet_democracy::vote::AccountVote<Balance>
- **/
- PalletDemocracyVoteAccountVote: {
- _enum: {
- Standard: {
- vote: 'Vote',
- balance: 'u128',
- },
- Split: {
- aye: 'u128',
- nay: 'u128'
- }
- }
- },
- /**
- * Lookup75: pallet_democracy::types::MetadataOwner
- **/
- PalletDemocracyMetadataOwner: {
- _enum: {
- External: 'Null',
- Proposal: 'u32',
- Referendum: 'u32'
- }
- },
- /**
- * Lookup76: pallet_collective::pallet::Event<T, I>
- **/
- PalletCollectiveEvent: {
- _enum: {
- Proposed: {
- account: 'AccountId32',
- proposalIndex: 'u32',
- proposalHash: 'H256',
- threshold: 'u32',
- },
- Voted: {
- account: 'AccountId32',
- proposalHash: 'H256',
- voted: 'bool',
- yes: 'u32',
- no: 'u32',
- },
- Approved: {
- proposalHash: 'H256',
- },
- Disapproved: {
- proposalHash: 'H256',
- },
- Executed: {
- proposalHash: 'H256',
- result: 'Result<Null, SpRuntimeDispatchError>',
- },
- MemberExecuted: {
- proposalHash: 'H256',
- result: 'Result<Null, SpRuntimeDispatchError>',
- },
- Closed: {
- proposalHash: 'H256',
- yes: 'u32',
- no: 'u32'
- }
- }
- },
- /**
- * Lookup79: pallet_membership::pallet::Event<T, I>
- **/
- PalletMembershipEvent: {
- _enum: ['MemberAdded', 'MemberRemoved', 'MembersSwapped', 'MembersReset', 'KeyChanged', 'Dummy']
- },
- /**
- * Lookup81: pallet_ranked_collective::pallet::Event<T, I>
- **/
- PalletRankedCollectiveEvent: {
- _enum: {
- MemberAdded: {
- who: 'AccountId32',
- },
- RankChanged: {
- who: 'AccountId32',
- rank: 'u16',
- },
- MemberRemoved: {
- who: 'AccountId32',
- rank: 'u16',
- },
- Voted: {
- who: 'AccountId32',
- poll: 'u32',
- vote: 'PalletRankedCollectiveVoteRecord',
- tally: 'PalletRankedCollectiveTally'
- }
- }
- },
- /**
- * Lookup83: pallet_ranked_collective::VoteRecord
- **/
- PalletRankedCollectiveVoteRecord: {
- _enum: {
- Aye: 'u32',
- Nay: 'u32'
- }
- },
- /**
- * Lookup84: pallet_ranked_collective::Tally<T, I, M>
- **/
- PalletRankedCollectiveTally: {
- bareAyes: 'u32',
- ayes: 'u32',
- nays: 'u32'
- },
- /**
- * Lookup85: pallet_referenda::pallet::Event<T, I>
- **/
- PalletReferendaEvent: {
- _enum: {
- Submitted: {
- index: 'u32',
- track: 'u16',
- proposal: 'FrameSupportPreimagesBounded',
- },
- DecisionDepositPlaced: {
- index: 'u32',
- who: 'AccountId32',
- amount: 'u128',
- },
- DecisionDepositRefunded: {
- index: 'u32',
- who: 'AccountId32',
- amount: 'u128',
- },
- DepositSlashed: {
- who: 'AccountId32',
- amount: 'u128',
- },
- DecisionStarted: {
- index: 'u32',
- track: 'u16',
- proposal: 'FrameSupportPreimagesBounded',
- tally: 'PalletRankedCollectiveTally',
- },
- ConfirmStarted: {
- index: 'u32',
- },
- ConfirmAborted: {
- index: 'u32',
- },
- Confirmed: {
- index: 'u32',
- tally: 'PalletRankedCollectiveTally',
- },
- Approved: {
- index: 'u32',
- },
- Rejected: {
- index: 'u32',
- tally: 'PalletRankedCollectiveTally',
- },
- TimedOut: {
- index: 'u32',
- tally: 'PalletRankedCollectiveTally',
- },
- Cancelled: {
- index: 'u32',
- tally: 'PalletRankedCollectiveTally',
- },
- Killed: {
- index: 'u32',
- tally: 'PalletRankedCollectiveTally',
- },
- SubmissionDepositRefunded: {
- index: 'u32',
- who: 'AccountId32',
- amount: 'u128',
- },
- MetadataSet: {
- _alias: {
- hash_: 'hash',
- },
- index: 'u32',
- hash_: 'H256',
- },
- MetadataCleared: {
- _alias: {
- hash_: 'hash',
- },
- index: 'u32',
- hash_: 'H256'
- }
- }
- },
- /**
- * Lookup86: frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>
- **/
- FrameSupportPreimagesBounded: {
- _enum: {
- Legacy: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- },
- Inline: 'Bytes',
- Lookup: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- len: 'u32'
- }
- }
- },
- /**
- * Lookup88: frame_system::pallet::Call<T>
- **/
- FrameSystemCall: {
- _enum: {
- remark: {
- remark: 'Bytes',
- },
- set_heap_pages: {
- pages: 'u64',
- },
- set_code: {
- code: 'Bytes',
- },
- set_code_without_checks: {
- code: 'Bytes',
- },
- set_storage: {
- items: 'Vec<(Bytes,Bytes)>',
- },
- kill_storage: {
- _alias: {
- keys_: 'keys',
- },
- keys_: 'Vec<Bytes>',
- },
- kill_prefix: {
- prefix: 'Bytes',
- subkeys: 'u32',
- },
- remark_with_event: {
- remark: 'Bytes'
- }
- }
- },
- /**
- * Lookup92: pallet_state_trie_migration::pallet::Call<T>
- **/
- PalletStateTrieMigrationCall: {
- _enum: {
- control_auto_migration: {
- maybeConfig: 'Option<PalletStateTrieMigrationMigrationLimits>',
- },
- continue_migrate: {
- limits: 'PalletStateTrieMigrationMigrationLimits',
- realSizeUpper: 'u32',
- witnessTask: 'PalletStateTrieMigrationMigrationTask',
- },
- migrate_custom_top: {
- _alias: {
- keys_: 'keys',
- },
- keys_: 'Vec<Bytes>',
- witnessSize: 'u32',
- },
- migrate_custom_child: {
- root: 'Bytes',
- childKeys: 'Vec<Bytes>',
- totalSize: 'u32',
- },
- set_signed_max_limits: {
- limits: 'PalletStateTrieMigrationMigrationLimits',
- },
- force_set_progress: {
- progressTop: 'PalletStateTrieMigrationProgress',
- progressChild: 'PalletStateTrieMigrationProgress'
- }
- }
- },
- /**
- * Lookup94: pallet_state_trie_migration::pallet::MigrationLimits
- **/
- PalletStateTrieMigrationMigrationLimits: {
- _alias: {
- size_: 'size'
- },
- size_: 'u32',
- item: 'u32'
- },
- /**
- * Lookup95: pallet_state_trie_migration::pallet::MigrationTask<T>
- **/
- PalletStateTrieMigrationMigrationTask: {
- _alias: {
- size_: 'size'
- },
- progressTop: 'PalletStateTrieMigrationProgress',
- progressChild: 'PalletStateTrieMigrationProgress',
- size_: 'u32',
- topItems: 'u32',
- childItems: 'u32'
- },
- /**
- * Lookup96: pallet_state_trie_migration::pallet::Progress<MaxKeyLen>
- **/
- PalletStateTrieMigrationProgress: {
- _enum: {
- ToStart: 'Null',
- LastKey: 'Bytes',
- Complete: 'Null'
- }
- },
- /**
- * Lookup98: cumulus_pallet_parachain_system::pallet::Call<T>
- **/
- CumulusPalletParachainSystemCall: {
- _enum: {
- set_validation_data: {
- data: 'CumulusPrimitivesParachainInherentParachainInherentData',
- },
- sudo_send_upward_message: {
- message: 'Bytes',
- },
- authorize_upgrade: {
- codeHash: 'H256',
- checkVersion: 'bool',
- },
- enact_authorized_upgrade: {
- code: 'Bytes'
- }
- }
- },
- /**
- * Lookup99: cumulus_primitives_parachain_inherent::ParachainInherentData
- **/
- CumulusPrimitivesParachainInherentParachainInherentData: {
- validationData: 'PolkadotPrimitivesV5PersistedValidationData',
- relayChainState: 'SpTrieStorageProof',
- downwardMessages: 'Vec<PolkadotCorePrimitivesInboundDownwardMessage>',
- horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'
- },
- /**
- * Lookup100: polkadot_primitives::v5::PersistedValidationData<primitive_types::H256, N>
- **/
- PolkadotPrimitivesV5PersistedValidationData: {
- parentHead: 'Bytes',
- relayParentNumber: 'u32',
- relayParentStorageRoot: 'H256',
- maxPovSize: 'u32'
- },
- /**
- * Lookup102: sp_trie::storage_proof::StorageProof
- **/
- SpTrieStorageProof: {
- trieNodes: 'BTreeSet<Bytes>'
- },
- /**
- * Lookup105: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
- **/
- PolkadotCorePrimitivesInboundDownwardMessage: {
- sentAt: 'u32',
- msg: 'Bytes'
- },
- /**
- * Lookup109: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
- **/
- PolkadotCorePrimitivesInboundHrmpMessage: {
- sentAt: 'u32',
- data: 'Bytes'
- },
- /**
- * Lookup112: parachain_info::pallet::Call<T>
- **/
- ParachainInfoCall: 'Null',
- /**
- * Lookup113: pallet_collator_selection::pallet::Call<T>
- **/
- PalletCollatorSelectionCall: {
- _enum: {
- add_invulnerable: {
- _alias: {
- new_: 'new',
- },
- new_: 'AccountId32',
- },
- remove_invulnerable: {
- who: 'AccountId32',
- },
- get_license: 'Null',
- onboard: 'Null',
- offboard: 'Null',
- release_license: 'Null',
- force_release_license: {
- who: 'AccountId32'
- }
- }
- },
- /**
- * Lookup114: pallet_session::pallet::Call<T>
- **/
- PalletSessionCall: {
- _enum: {
- set_keys: {
- _alias: {
- keys_: 'keys',
- },
- keys_: 'OpalRuntimeRuntimeCommonSessionKeys',
- proof: 'Bytes',
- },
- purge_keys: 'Null'
- }
- },
- /**
- * Lookup115: opal_runtime::runtime_common::SessionKeys
- **/
- OpalRuntimeRuntimeCommonSessionKeys: {
- aura: 'SpConsensusAuraSr25519AppSr25519Public'
- },
- /**
- * Lookup116: sp_consensus_aura::sr25519::app_sr25519::Public
- **/
- SpConsensusAuraSr25519AppSr25519Public: 'SpCoreSr25519Public',
- /**
- * Lookup117: sp_core::sr25519::Public
- **/
- SpCoreSr25519Public: '[u8;32]',
- /**
- * Lookup118: pallet_balances::pallet::Call<T, I>
- **/
- PalletBalancesCall: {
- _enum: {
- transfer_allow_death: {
- dest: 'MultiAddress',
- value: 'Compact<u128>',
- },
- set_balance_deprecated: {
- who: 'MultiAddress',
- newFree: 'Compact<u128>',
- oldReserved: 'Compact<u128>',
- },
- force_transfer: {
- source: 'MultiAddress',
- dest: 'MultiAddress',
- value: 'Compact<u128>',
- },
- transfer_keep_alive: {
- dest: 'MultiAddress',
- value: 'Compact<u128>',
- },
- transfer_all: {
- dest: 'MultiAddress',
- keepAlive: 'bool',
- },
- force_unreserve: {
- who: 'MultiAddress',
- amount: 'u128',
- },
- upgrade_accounts: {
- who: 'Vec<AccountId32>',
- },
- transfer: {
- dest: 'MultiAddress',
- value: 'Compact<u128>',
- },
- force_set_balance: {
- who: 'MultiAddress',
- newFree: 'Compact<u128>'
- }
- }
- },
- /**
- * Lookup122: pallet_timestamp::pallet::Call<T>
- **/
- PalletTimestampCall: {
- _enum: {
- set: {
- now: 'Compact<u64>'
- }
- }
- },
- /**
- * Lookup123: pallet_treasury::pallet::Call<T, I>
- **/
- PalletTreasuryCall: {
- _enum: {
- propose_spend: {
- value: 'Compact<u128>',
- beneficiary: 'MultiAddress',
- },
- reject_proposal: {
- proposalId: 'Compact<u32>',
- },
- approve_proposal: {
- proposalId: 'Compact<u32>',
- },
- spend: {
- amount: 'Compact<u128>',
- beneficiary: 'MultiAddress',
- },
- remove_approval: {
- proposalId: 'Compact<u32>'
- }
- }
- },
- /**
- * Lookup124: pallet_sudo::pallet::Call<T>
- **/
- PalletSudoCall: {
- _enum: {
- sudo: {
- call: 'Call',
- },
- sudo_unchecked_weight: {
- call: 'Call',
- weight: 'SpWeightsWeightV2Weight',
- },
- set_key: {
- _alias: {
- new_: 'new',
- },
- new_: 'MultiAddress',
- },
- sudo_as: {
- who: 'MultiAddress',
- call: 'Call'
- }
- }
- },
- /**
- * Lookup125: orml_vesting::module::Call<T>
- **/
- OrmlVestingModuleCall: {
- _enum: {
- claim: 'Null',
- vested_transfer: {
- dest: 'MultiAddress',
- schedule: 'OrmlVestingVestingSchedule',
- },
- update_vesting_schedules: {
- who: 'MultiAddress',
- vestingSchedules: 'Vec<OrmlVestingVestingSchedule>',
- },
- claim_for: {
- dest: 'MultiAddress'
- }
- }
- },
- /**
- * Lookup127: orml_xtokens::module::Call<T>
- **/
- OrmlXtokensModuleCall: {
- _enum: {
- transfer: {
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'u128',
- dest: 'StagingXcmVersionedMultiLocation',
- destWeightLimit: 'StagingXcmV3WeightLimit',
- },
- transfer_multiasset: {
- asset: 'StagingXcmVersionedMultiAsset',
- dest: 'StagingXcmVersionedMultiLocation',
- destWeightLimit: 'StagingXcmV3WeightLimit',
- },
- transfer_with_fee: {
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'u128',
- fee: 'u128',
- dest: 'StagingXcmVersionedMultiLocation',
- destWeightLimit: 'StagingXcmV3WeightLimit',
- },
- transfer_multiasset_with_fee: {
- asset: 'StagingXcmVersionedMultiAsset',
- fee: 'StagingXcmVersionedMultiAsset',
- dest: 'StagingXcmVersionedMultiLocation',
- destWeightLimit: 'StagingXcmV3WeightLimit',
- },
- transfer_multicurrencies: {
- currencies: 'Vec<(PalletForeignAssetsAssetId,u128)>',
- feeItem: 'u32',
- dest: 'StagingXcmVersionedMultiLocation',
- destWeightLimit: 'StagingXcmV3WeightLimit',
- },
- transfer_multiassets: {
- assets: 'StagingXcmVersionedMultiAssets',
- feeItem: 'u32',
- dest: 'StagingXcmVersionedMultiLocation',
- destWeightLimit: 'StagingXcmV3WeightLimit'
- }
- }
- },
- /**
- * Lookup128: staging_xcm::VersionedMultiLocation
- **/
- StagingXcmVersionedMultiLocation: {
- _enum: {
- __Unused0: 'Null',
- V2: 'StagingXcmV2MultiLocation',
- __Unused2: 'Null',
- V3: 'StagingXcmV3MultiLocation'
- }
- },
- /**
- * Lookup129: staging_xcm::v2::multilocation::MultiLocation
- **/
- StagingXcmV2MultiLocation: {
- parents: 'u8',
- interior: 'StagingXcmV2MultilocationJunctions'
- },
- /**
- * Lookup130: staging_xcm::v2::multilocation::Junctions
- **/
- StagingXcmV2MultilocationJunctions: {
- _enum: {
- Here: 'Null',
- X1: 'StagingXcmV2Junction',
- X2: '(StagingXcmV2Junction,StagingXcmV2Junction)',
- X3: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
- X4: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
- X5: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
- X6: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
- X7: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)',
- X8: '(StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction,StagingXcmV2Junction)'
- }
- },
- /**
- * Lookup131: staging_xcm::v2::junction::Junction
- **/
- StagingXcmV2Junction: {
- _enum: {
- Parachain: 'Compact<u32>',
- AccountId32: {
- network: 'StagingXcmV2NetworkId',
- id: '[u8;32]',
- },
- AccountIndex64: {
- network: 'StagingXcmV2NetworkId',
- index: 'Compact<u64>',
- },
- AccountKey20: {
- network: 'StagingXcmV2NetworkId',
- key: '[u8;20]',
- },
- PalletInstance: 'u8',
- GeneralIndex: 'Compact<u128>',
- GeneralKey: 'Bytes',
- OnlyChild: 'Null',
- Plurality: {
- id: 'StagingXcmV2BodyId',
- part: 'StagingXcmV2BodyPart'
- }
- }
- },
- /**
- * Lookup132: staging_xcm::v2::NetworkId
- **/
- StagingXcmV2NetworkId: {
- _enum: {
- Any: 'Null',
- Named: 'Bytes',
- Polkadot: 'Null',
- Kusama: 'Null'
- }
- },
- /**
- * Lookup134: staging_xcm::v2::BodyId
- **/
- StagingXcmV2BodyId: {
- _enum: {
- Unit: 'Null',
- Named: 'Bytes',
- Index: 'Compact<u32>',
- Executive: 'Null',
- Technical: 'Null',
- Legislative: 'Null',
- Judicial: 'Null',
- Defense: 'Null',
- Administration: 'Null',
- Treasury: 'Null'
- }
- },
- /**
- * Lookup135: staging_xcm::v2::BodyPart
- **/
- StagingXcmV2BodyPart: {
- _enum: {
- Voice: 'Null',
- Members: {
- count: 'Compact<u32>',
- },
- Fraction: {
- nom: 'Compact<u32>',
- denom: 'Compact<u32>',
- },
- AtLeastProportion: {
- nom: 'Compact<u32>',
- denom: 'Compact<u32>',
- },
- MoreThanProportion: {
- nom: 'Compact<u32>',
- denom: 'Compact<u32>'
- }
- }
- },
- /**
- * Lookup136: staging_xcm::v3::WeightLimit
- **/
- StagingXcmV3WeightLimit: {
- _enum: {
- Unlimited: 'Null',
- Limited: 'SpWeightsWeightV2Weight'
- }
- },
- /**
- * Lookup137: staging_xcm::VersionedMultiAsset
- **/
- StagingXcmVersionedMultiAsset: {
- _enum: {
- __Unused0: 'Null',
- V2: 'StagingXcmV2MultiAsset',
- __Unused2: 'Null',
- V3: 'StagingXcmV3MultiAsset'
- }
- },
- /**
- * Lookup138: staging_xcm::v2::multiasset::MultiAsset
- **/
- StagingXcmV2MultiAsset: {
- id: 'StagingXcmV2MultiassetAssetId',
- fun: 'StagingXcmV2MultiassetFungibility'
- },
- /**
- * Lookup139: staging_xcm::v2::multiasset::AssetId
- **/
- StagingXcmV2MultiassetAssetId: {
- _enum: {
- Concrete: 'StagingXcmV2MultiLocation',
- Abstract: 'Bytes'
- }
- },
- /**
- * Lookup140: staging_xcm::v2::multiasset::Fungibility
- **/
- StagingXcmV2MultiassetFungibility: {
- _enum: {
- Fungible: 'Compact<u128>',
- NonFungible: 'StagingXcmV2MultiassetAssetInstance'
- }
- },
- /**
- * Lookup141: staging_xcm::v2::multiasset::AssetInstance
- **/
- StagingXcmV2MultiassetAssetInstance: {
- _enum: {
- Undefined: 'Null',
- Index: 'Compact<u128>',
- Array4: '[u8;4]',
- Array8: '[u8;8]',
- Array16: '[u8;16]',
- Array32: '[u8;32]',
- Blob: 'Bytes'
- }
- },
- /**
- * Lookup144: staging_xcm::VersionedMultiAssets
- **/
- StagingXcmVersionedMultiAssets: {
- _enum: {
- __Unused0: 'Null',
- V2: 'StagingXcmV2MultiassetMultiAssets',
- __Unused2: 'Null',
- V3: 'StagingXcmV3MultiassetMultiAssets'
- }
- },
- /**
- * Lookup145: staging_xcm::v2::multiasset::MultiAssets
- **/
- StagingXcmV2MultiassetMultiAssets: 'Vec<StagingXcmV2MultiAsset>',
- /**
- * Lookup147: orml_tokens::module::Call<T>
- **/
- OrmlTokensModuleCall: {
- _enum: {
- transfer: {
- dest: 'MultiAddress',
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'Compact<u128>',
- },
- transfer_all: {
- dest: 'MultiAddress',
- currencyId: 'PalletForeignAssetsAssetId',
- keepAlive: 'bool',
- },
- transfer_keep_alive: {
- dest: 'MultiAddress',
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'Compact<u128>',
- },
- force_transfer: {
- source: 'MultiAddress',
- dest: 'MultiAddress',
- currencyId: 'PalletForeignAssetsAssetId',
- amount: 'Compact<u128>',
- },
- set_balance: {
- who: 'MultiAddress',
- currencyId: 'PalletForeignAssetsAssetId',
- newFree: 'Compact<u128>',
- newReserved: 'Compact<u128>'
- }
- }
- },
- /**
- * Lookup148: pallet_identity::pallet::Call<T>
- **/
- PalletIdentityCall: {
- _enum: {
- add_registrar: {
- account: 'MultiAddress',
- },
- set_identity: {
- info: 'PalletIdentityIdentityInfo',
- },
- set_subs: {
- subs: 'Vec<(AccountId32,Data)>',
- },
- clear_identity: 'Null',
- request_judgement: {
- regIndex: 'Compact<u32>',
- maxFee: 'Compact<u128>',
- },
- cancel_request: {
- regIndex: 'u32',
- },
- set_fee: {
- index: 'Compact<u32>',
- fee: 'Compact<u128>',
- },
- set_account_id: {
- _alias: {
- new_: 'new',
- },
- index: 'Compact<u32>',
- new_: 'MultiAddress',
- },
- set_fields: {
- index: 'Compact<u32>',
- fields: 'PalletIdentityBitFlags',
- },
- provide_judgement: {
- regIndex: 'Compact<u32>',
- target: 'MultiAddress',
- judgement: 'PalletIdentityJudgement',
- identity: 'H256',
- },
- kill_identity: {
- target: 'MultiAddress',
- },
- add_sub: {
- sub: 'MultiAddress',
- data: 'Data',
- },
- rename_sub: {
- sub: 'MultiAddress',
- data: 'Data',
- },
- remove_sub: {
- sub: 'MultiAddress',
- },
- quit_sub: 'Null',
- force_insert_identities: {
- identities: 'Vec<(AccountId32,PalletIdentityRegistration)>',
- },
- force_remove_identities: {
- identities: 'Vec<AccountId32>',
- },
- force_set_subs: {
- subs: 'Vec<(AccountId32,(u128,Vec<(AccountId32,Data)>))>'
- }
- }
- },
- /**
- * Lookup149: pallet_identity::types::IdentityInfo<FieldLimit>
- **/
- PalletIdentityIdentityInfo: {
- additional: 'Vec<(Data,Data)>',
- display: 'Data',
- legal: 'Data',
- web: 'Data',
- riot: 'Data',
- email: 'Data',
- pgpFingerprint: 'Option<[u8;20]>',
- image: 'Data',
- twitter: 'Data'
- },
- /**
- * Lookup185: pallet_identity::types::BitFlags<pallet_identity::types::IdentityField>
- **/
- PalletIdentityBitFlags: {
- _bitLength: 64,
- Display: 1,
- Legal: 2,
- Web: 4,
- Riot: 8,
- Email: 16,
- PgpFingerprint: 32,
- Image: 64,
- Twitter: 128
- },
- /**
- * Lookup186: pallet_identity::types::IdentityField
- **/
- PalletIdentityIdentityField: {
- _enum: ['__Unused0', 'Display', 'Legal', '__Unused3', 'Web', '__Unused5', '__Unused6', '__Unused7', 'Riot', '__Unused9', '__Unused10', '__Unused11', '__Unused12', '__Unused13', '__Unused14', '__Unused15', 'Email', '__Unused17', '__Unused18', '__Unused19', '__Unused20', '__Unused21', '__Unused22', '__Unused23', '__Unused24', '__Unused25', '__Unused26', '__Unused27', '__Unused28', '__Unused29', '__Unused30', '__Unused31', 'PgpFingerprint', '__Unused33', '__Unused34', '__Unused35', '__Unused36', '__Unused37', '__Unused38', '__Unused39', '__Unused40', '__Unused41', '__Unused42', '__Unused43', '__Unused44', '__Unused45', '__Unused46', '__Unused47', '__Unused48', '__Unused49', '__Unused50', '__Unused51', '__Unused52', '__Unused53', '__Unused54', '__Unused55', '__Unused56', '__Unused57', '__Unused58', '__Unused59', '__Unused60', '__Unused61', '__Unused62', '__Unused63', 'Image', '__Unused65', '__Unused66', '__Unused67', '__Unused68', '__Unused69', '__Unused70', '__Unused71', '__Unused72', '__Unused73', '__Unused74', '__Unused75', '__Unused76', '__Unused77', '__Unused78', '__Unused79', '__Unused80', '__Unused81', '__Unused82', '__Unused83', '__Unused84', '__Unused85', '__Unused86', '__Unused87', '__Unused88', '__Unused89', '__Unused90', '__Unused91', '__Unused92', '__Unused93', '__Unused94', '__Unused95', '__Unused96', '__Unused97', '__Unused98', '__Unused99', '__Unused100', '__Unused101', '__Unused102', '__Unused103', '__Unused104', '__Unused105', '__Unused106', '__Unused107', '__Unused108', '__Unused109', '__Unused110', '__Unused111', '__Unused112', '__Unused113', '__Unused114', '__Unused115', '__Unused116', '__Unused117', '__Unused118', '__Unused119', '__Unused120', '__Unused121', '__Unused122', '__Unused123', '__Unused124', '__Unused125', '__Unused126', '__Unused127', 'Twitter']
- },
- /**
- * Lookup187: pallet_identity::types::Judgement<Balance>
- **/
- PalletIdentityJudgement: {
- _enum: {
- Unknown: 'Null',
- FeePaid: 'u128',
- Reasonable: 'Null',
- KnownGood: 'Null',
- OutOfDate: 'Null',
- LowQuality: 'Null',
- Erroneous: 'Null'
- }
- },
- /**
- * Lookup190: pallet_identity::types::Registration<Balance, MaxJudgements, MaxAdditionalFields>
- **/
- PalletIdentityRegistration: {
- judgements: 'Vec<(u32,PalletIdentityJudgement)>',
- deposit: 'u128',
- info: 'PalletIdentityIdentityInfo'
- },
- /**
- * Lookup198: pallet_preimage::pallet::Call<T>
- **/
- PalletPreimageCall: {
- _enum: {
- note_preimage: {
- bytes: 'Bytes',
- },
- unnote_preimage: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- },
- request_preimage: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- },
- unrequest_preimage: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256'
- }
- }
- },
- /**
- * Lookup199: pallet_democracy::pallet::Call<T>
- **/
- PalletDemocracyCall: {
- _enum: {
- propose: {
- proposal: 'FrameSupportPreimagesBounded',
- value: 'Compact<u128>',
- },
- second: {
- proposal: 'Compact<u32>',
- },
- vote: {
- refIndex: 'Compact<u32>',
- vote: 'PalletDemocracyVoteAccountVote',
- },
- emergency_cancel: {
- refIndex: 'u32',
- },
- external_propose: {
- proposal: 'FrameSupportPreimagesBounded',
- },
- external_propose_majority: {
- proposal: 'FrameSupportPreimagesBounded',
- },
- external_propose_default: {
- proposal: 'FrameSupportPreimagesBounded',
- },
- fast_track: {
- proposalHash: 'H256',
- votingPeriod: 'u32',
- delay: 'u32',
- },
- veto_external: {
- proposalHash: 'H256',
- },
- cancel_referendum: {
- refIndex: 'Compact<u32>',
- },
- delegate: {
- to: 'MultiAddress',
- conviction: 'PalletDemocracyConviction',
- balance: 'u128',
- },
- undelegate: 'Null',
- clear_public_proposals: 'Null',
- unlock: {
- target: 'MultiAddress',
- },
- remove_vote: {
- index: 'u32',
- },
- remove_other_vote: {
- target: 'MultiAddress',
- index: 'u32',
- },
- blacklist: {
- proposalHash: 'H256',
- maybeRefIndex: 'Option<u32>',
- },
- cancel_proposal: {
- propIndex: 'Compact<u32>',
- },
- set_metadata: {
- owner: 'PalletDemocracyMetadataOwner',
- maybeHash: 'Option<H256>'
- }
- }
- },
- /**
- * Lookup200: pallet_democracy::conviction::Conviction
- **/
- PalletDemocracyConviction: {
- _enum: ['None', 'Locked1x', 'Locked2x', 'Locked3x', 'Locked4x', 'Locked5x', 'Locked6x']
- },
- /**
- * Lookup203: pallet_collective::pallet::Call<T, I>
- **/
- PalletCollectiveCall: {
- _enum: {
- set_members: {
- newMembers: 'Vec<AccountId32>',
- prime: 'Option<AccountId32>',
- oldCount: 'u32',
- },
- execute: {
- proposal: 'Call',
- lengthBound: 'Compact<u32>',
- },
- propose: {
- threshold: 'Compact<u32>',
- proposal: 'Call',
- lengthBound: 'Compact<u32>',
- },
- vote: {
- proposal: 'H256',
- index: 'Compact<u32>',
- approve: 'bool',
- },
- __Unused4: 'Null',
- disapprove_proposal: {
- proposalHash: 'H256',
- },
- close: {
- proposalHash: 'H256',
- index: 'Compact<u32>',
- proposalWeightBound: 'SpWeightsWeightV2Weight',
- lengthBound: 'Compact<u32>'
- }
- }
- },
- /**
- * Lookup205: pallet_membership::pallet::Call<T, I>
- **/
- PalletMembershipCall: {
- _enum: {
- add_member: {
- who: 'MultiAddress',
- },
- remove_member: {
- who: 'MultiAddress',
- },
- swap_member: {
- remove: 'MultiAddress',
- add: 'MultiAddress',
- },
- reset_members: {
- members: 'Vec<AccountId32>',
- },
- change_key: {
- _alias: {
- new_: 'new',
- },
- new_: 'MultiAddress',
- },
- set_prime: {
- who: 'MultiAddress',
- },
- clear_prime: 'Null'
- }
- },
- /**
- * Lookup207: pallet_ranked_collective::pallet::Call<T, I>
- **/
- PalletRankedCollectiveCall: {
- _enum: {
- add_member: {
- who: 'MultiAddress',
- },
- promote_member: {
- who: 'MultiAddress',
- },
- demote_member: {
- who: 'MultiAddress',
- },
- remove_member: {
- who: 'MultiAddress',
- minRank: 'u16',
- },
- vote: {
- poll: 'u32',
- aye: 'bool',
- },
- cleanup_poll: {
- pollIndex: 'u32',
- max: 'u32'
- }
- }
- },
- /**
- * Lookup208: pallet_referenda::pallet::Call<T, I>
- **/
- PalletReferendaCall: {
- _enum: {
- submit: {
- proposalOrigin: 'OpalRuntimeOriginCaller',
- proposal: 'FrameSupportPreimagesBounded',
- enactmentMoment: 'FrameSupportScheduleDispatchTime',
- },
- place_decision_deposit: {
- index: 'u32',
- },
- refund_decision_deposit: {
- index: 'u32',
- },
- cancel: {
- index: 'u32',
- },
- kill: {
- index: 'u32',
- },
- nudge_referendum: {
- index: 'u32',
- },
- one_fewer_deciding: {
- track: 'u16',
- },
- refund_submission_deposit: {
- index: 'u32',
- },
- set_metadata: {
- index: 'u32',
- maybeHash: 'Option<H256>'
- }
- }
- },
- /**
- * Lookup209: opal_runtime::OriginCaller
- **/
- OpalRuntimeOriginCaller: {
- _enum: {
- system: 'FrameSupportDispatchRawOrigin',
- __Unused1: 'Null',
- __Unused2: 'Null',
- __Unused3: 'Null',
- __Unused4: 'Null',
- __Unused5: 'Null',
- __Unused6: 'Null',
- Void: 'SpCoreVoid',
- __Unused8: 'Null',
- __Unused9: 'Null',
- __Unused10: 'Null',
- __Unused11: 'Null',
- __Unused12: 'Null',
- __Unused13: 'Null',
- __Unused14: 'Null',
- __Unused15: 'Null',
- __Unused16: 'Null',
- __Unused17: 'Null',
- __Unused18: 'Null',
- __Unused19: 'Null',
- __Unused20: 'Null',
- __Unused21: 'Null',
- __Unused22: 'Null',
- __Unused23: 'Null',
- __Unused24: 'Null',
- __Unused25: 'Null',
- __Unused26: 'Null',
- __Unused27: 'Null',
- __Unused28: 'Null',
- __Unused29: 'Null',
- __Unused30: 'Null',
- __Unused31: 'Null',
- __Unused32: 'Null',
- __Unused33: 'Null',
- __Unused34: 'Null',
- __Unused35: 'Null',
- __Unused36: 'Null',
- __Unused37: 'Null',
- __Unused38: 'Null',
- __Unused39: 'Null',
- __Unused40: 'Null',
- __Unused41: 'Null',
- __Unused42: 'Null',
- Council: 'PalletCollectiveRawOrigin',
- TechnicalCommittee: 'PalletCollectiveRawOrigin',
- __Unused45: 'Null',
- __Unused46: 'Null',
- __Unused47: 'Null',
- __Unused48: 'Null',
- __Unused49: 'Null',
- __Unused50: 'Null',
- PolkadotXcm: 'PalletXcmOrigin',
- CumulusXcm: 'CumulusPalletXcmOrigin',
- __Unused53: 'Null',
- __Unused54: 'Null',
- __Unused55: 'Null',
- __Unused56: 'Null',
- __Unused57: 'Null',
- __Unused58: 'Null',
- __Unused59: 'Null',
- __Unused60: 'Null',
- __Unused61: 'Null',
- __Unused62: 'Null',
- __Unused63: 'Null',
- __Unused64: 'Null',
- __Unused65: 'Null',
- __Unused66: 'Null',
- __Unused67: 'Null',
- __Unused68: 'Null',
- __Unused69: 'Null',
- __Unused70: 'Null',
- __Unused71: 'Null',
- __Unused72: 'Null',
- __Unused73: 'Null',
- __Unused74: 'Null',
- __Unused75: 'Null',
- __Unused76: 'Null',
- __Unused77: 'Null',
- __Unused78: 'Null',
- __Unused79: 'Null',
- __Unused80: 'Null',
- __Unused81: 'Null',
- __Unused82: 'Null',
- __Unused83: 'Null',
- __Unused84: 'Null',
- __Unused85: 'Null',
- __Unused86: 'Null',
- __Unused87: 'Null',
- __Unused88: 'Null',
- __Unused89: 'Null',
- __Unused90: 'Null',
- __Unused91: 'Null',
- __Unused92: 'Null',
- __Unused93: 'Null',
- __Unused94: 'Null',
- __Unused95: 'Null',
- __Unused96: 'Null',
- __Unused97: 'Null',
- __Unused98: 'Null',
- Origins: 'PalletGovOriginsOrigin',
- __Unused100: 'Null',
- Ethereum: 'PalletEthereumRawOrigin'
- }
- },
- /**
- * Lookup210: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
- **/
- FrameSupportDispatchRawOrigin: {
- _enum: {
- Root: 'Null',
- Signed: 'AccountId32',
- None: 'Null'
- }
- },
- /**
- * Lookup211: pallet_collective::RawOrigin<sp_core::crypto::AccountId32, I>
- **/
- PalletCollectiveRawOrigin: {
- _enum: {
- Members: '(u32,u32)',
- Member: 'AccountId32',
- _Phantom: 'Null'
- }
- },
- /**
- * Lookup213: pallet_gov_origins::pallet::Origin
- **/
- PalletGovOriginsOrigin: {
- _enum: ['FellowshipProposition']
- },
- /**
- * Lookup214: pallet_xcm::pallet::Origin
- **/
- PalletXcmOrigin: {
- _enum: {
- Xcm: 'StagingXcmV3MultiLocation',
- Response: 'StagingXcmV3MultiLocation'
- }
- },
- /**
- * Lookup215: cumulus_pallet_xcm::pallet::Origin
- **/
- CumulusPalletXcmOrigin: {
- _enum: {
- Relay: 'Null',
- SiblingParachain: 'u32'
- }
- },
- /**
- * Lookup216: pallet_ethereum::RawOrigin
- **/
- PalletEthereumRawOrigin: {
- _enum: {
- EthereumTransaction: 'H160'
- }
- },
- /**
- * Lookup218: sp_core::Void
- **/
- SpCoreVoid: 'Null',
- /**
- * Lookup219: frame_support::traits::schedule::DispatchTime<BlockNumber>
- **/
- FrameSupportScheduleDispatchTime: {
- _enum: {
- At: 'u32',
- After: 'u32'
- }
- },
- /**
- * Lookup220: pallet_scheduler::pallet::Call<T>
- **/
- PalletSchedulerCall: {
- _enum: {
- schedule: {
- when: 'u32',
- maybePeriodic: 'Option<(u32,u32)>',
- priority: 'u8',
- call: 'Call',
- },
- cancel: {
- when: 'u32',
- index: 'u32',
- },
- schedule_named: {
- id: '[u8;32]',
- when: 'u32',
- maybePeriodic: 'Option<(u32,u32)>',
- priority: 'u8',
- call: 'Call',
- },
- cancel_named: {
- id: '[u8;32]',
- },
- schedule_after: {
- after: 'u32',
- maybePeriodic: 'Option<(u32,u32)>',
- priority: 'u8',
- call: 'Call',
- },
- schedule_named_after: {
- id: '[u8;32]',
- after: 'u32',
- maybePeriodic: 'Option<(u32,u32)>',
- priority: 'u8',
- call: 'Call'
- }
- }
- },
- /**
- * Lookup223: cumulus_pallet_xcmp_queue::pallet::Call<T>
- **/
- CumulusPalletXcmpQueueCall: {
- _enum: {
- service_overweight: {
- index: 'u64',
- weightLimit: 'SpWeightsWeightV2Weight',
- },
- suspend_xcm_execution: 'Null',
- resume_xcm_execution: 'Null',
- update_suspend_threshold: {
- _alias: {
- new_: 'new',
- },
- new_: 'u32',
- },
- update_drop_threshold: {
- _alias: {
- new_: 'new',
- },
- new_: 'u32',
- },
- update_resume_threshold: {
- _alias: {
- new_: 'new',
- },
- new_: 'u32',
- },
- update_threshold_weight: {
- _alias: {
- new_: 'new',
- },
- new_: 'SpWeightsWeightV2Weight',
- },
- update_weight_restrict_decay: {
- _alias: {
- new_: 'new',
- },
- new_: 'SpWeightsWeightV2Weight',
- },
- update_xcmp_max_individual_weight: {
- _alias: {
- new_: 'new',
- },
- new_: 'SpWeightsWeightV2Weight'
- }
- }
- },
- /**
- * Lookup224: pallet_xcm::pallet::Call<T>
- **/
- PalletXcmCall: {
- _enum: {
- send: {
- dest: 'StagingXcmVersionedMultiLocation',
- message: 'StagingXcmVersionedXcm',
- },
- teleport_assets: {
- dest: 'StagingXcmVersionedMultiLocation',
- beneficiary: 'StagingXcmVersionedMultiLocation',
- assets: 'StagingXcmVersionedMultiAssets',
- feeAssetItem: 'u32',
- },
- reserve_transfer_assets: {
- dest: 'StagingXcmVersionedMultiLocation',
- beneficiary: 'StagingXcmVersionedMultiLocation',
- assets: 'StagingXcmVersionedMultiAssets',
- feeAssetItem: 'u32',
- },
- execute: {
- message: 'StagingXcmVersionedXcm',
- maxWeight: 'SpWeightsWeightV2Weight',
- },
- force_xcm_version: {
- location: 'StagingXcmV3MultiLocation',
- version: 'u32',
- },
- force_default_xcm_version: {
- maybeXcmVersion: 'Option<u32>',
- },
- force_subscribe_version_notify: {
- location: 'StagingXcmVersionedMultiLocation',
- },
- force_unsubscribe_version_notify: {
- location: 'StagingXcmVersionedMultiLocation',
- },
- limited_reserve_transfer_assets: {
- dest: 'StagingXcmVersionedMultiLocation',
- beneficiary: 'StagingXcmVersionedMultiLocation',
- assets: 'StagingXcmVersionedMultiAssets',
- feeAssetItem: 'u32',
- weightLimit: 'StagingXcmV3WeightLimit',
- },
- limited_teleport_assets: {
- dest: 'StagingXcmVersionedMultiLocation',
- beneficiary: 'StagingXcmVersionedMultiLocation',
- assets: 'StagingXcmVersionedMultiAssets',
- feeAssetItem: 'u32',
- weightLimit: 'StagingXcmV3WeightLimit',
- },
- force_suspension: {
- suspended: 'bool'
- }
- }
- },
- /**
- * Lookup225: staging_xcm::VersionedXcm<RuntimeCall>
- **/
- StagingXcmVersionedXcm: {
- _enum: {
- __Unused0: 'Null',
- __Unused1: 'Null',
- V2: 'StagingXcmV2Xcm',
- V3: 'StagingXcmV3Xcm'
- }
- },
- /**
- * Lookup226: staging_xcm::v2::Xcm<RuntimeCall>
- **/
- StagingXcmV2Xcm: 'Vec<StagingXcmV2Instruction>',
- /**
- * Lookup228: staging_xcm::v2::Instruction<RuntimeCall>
- **/
- StagingXcmV2Instruction: {
- _enum: {
- WithdrawAsset: 'StagingXcmV2MultiassetMultiAssets',
- ReserveAssetDeposited: 'StagingXcmV2MultiassetMultiAssets',
- ReceiveTeleportedAsset: 'StagingXcmV2MultiassetMultiAssets',
- QueryResponse: {
- queryId: 'Compact<u64>',
- response: 'StagingXcmV2Response',
- maxWeight: 'Compact<u64>',
- },
- TransferAsset: {
- assets: 'StagingXcmV2MultiassetMultiAssets',
- beneficiary: 'StagingXcmV2MultiLocation',
- },
- TransferReserveAsset: {
- assets: 'StagingXcmV2MultiassetMultiAssets',
- dest: 'StagingXcmV2MultiLocation',
- xcm: 'StagingXcmV2Xcm',
- },
- Transact: {
- originType: 'StagingXcmV2OriginKind',
- requireWeightAtMost: 'Compact<u64>',
- call: 'StagingXcmDoubleEncoded',
- },
- HrmpNewChannelOpenRequest: {
- sender: 'Compact<u32>',
- maxMessageSize: 'Compact<u32>',
- maxCapacity: 'Compact<u32>',
- },
- HrmpChannelAccepted: {
- recipient: 'Compact<u32>',
- },
- HrmpChannelClosing: {
- initiator: 'Compact<u32>',
- sender: 'Compact<u32>',
- recipient: 'Compact<u32>',
- },
- ClearOrigin: 'Null',
- DescendOrigin: 'StagingXcmV2MultilocationJunctions',
- ReportError: {
- queryId: 'Compact<u64>',
- dest: 'StagingXcmV2MultiLocation',
- maxResponseWeight: 'Compact<u64>',
- },
- DepositAsset: {
- assets: 'StagingXcmV2MultiassetMultiAssetFilter',
- maxAssets: 'Compact<u32>',
- beneficiary: 'StagingXcmV2MultiLocation',
- },
- DepositReserveAsset: {
- assets: 'StagingXcmV2MultiassetMultiAssetFilter',
- maxAssets: 'Compact<u32>',
- dest: 'StagingXcmV2MultiLocation',
- xcm: 'StagingXcmV2Xcm',
- },
- ExchangeAsset: {
- give: 'StagingXcmV2MultiassetMultiAssetFilter',
- receive: 'StagingXcmV2MultiassetMultiAssets',
- },
- InitiateReserveWithdraw: {
- assets: 'StagingXcmV2MultiassetMultiAssetFilter',
- reserve: 'StagingXcmV2MultiLocation',
- xcm: 'StagingXcmV2Xcm',
- },
- InitiateTeleport: {
- assets: 'StagingXcmV2MultiassetMultiAssetFilter',
- dest: 'StagingXcmV2MultiLocation',
- xcm: 'StagingXcmV2Xcm',
- },
- QueryHolding: {
- queryId: 'Compact<u64>',
- dest: 'StagingXcmV2MultiLocation',
- assets: 'StagingXcmV2MultiassetMultiAssetFilter',
- maxResponseWeight: 'Compact<u64>',
- },
- BuyExecution: {
- fees: 'StagingXcmV2MultiAsset',
- weightLimit: 'StagingXcmV2WeightLimit',
- },
- RefundSurplus: 'Null',
- SetErrorHandler: 'StagingXcmV2Xcm',
- SetAppendix: 'StagingXcmV2Xcm',
- ClearError: 'Null',
- ClaimAsset: {
- assets: 'StagingXcmV2MultiassetMultiAssets',
- ticket: 'StagingXcmV2MultiLocation',
- },
- Trap: 'Compact<u64>',
- SubscribeVersion: {
- queryId: 'Compact<u64>',
- maxResponseWeight: 'Compact<u64>',
- },
- UnsubscribeVersion: 'Null'
- }
- },
- /**
- * Lookup229: staging_xcm::v2::Response
- **/
- StagingXcmV2Response: {
- _enum: {
- Null: 'Null',
- Assets: 'StagingXcmV2MultiassetMultiAssets',
- ExecutionResult: 'Option<(u32,StagingXcmV2TraitsError)>',
- Version: 'u32'
- }
- },
- /**
- * Lookup232: staging_xcm::v2::traits::Error
- **/
- StagingXcmV2TraitsError: {
- _enum: {
- Overflow: 'Null',
- Unimplemented: 'Null',
- UntrustedReserveLocation: 'Null',
- UntrustedTeleportLocation: 'Null',
- MultiLocationFull: 'Null',
- MultiLocationNotInvertible: 'Null',
- BadOrigin: 'Null',
- InvalidLocation: 'Null',
- AssetNotFound: 'Null',
- FailedToTransactAsset: 'Null',
- NotWithdrawable: 'Null',
- LocationCannotHold: 'Null',
- ExceedsMaxMessageSize: 'Null',
- DestinationUnsupported: 'Null',
- Transport: 'Null',
- Unroutable: 'Null',
- UnknownClaim: 'Null',
- FailedToDecode: 'Null',
- MaxWeightInvalid: 'Null',
- NotHoldingFees: 'Null',
- TooExpensive: 'Null',
- Trap: 'u64',
- UnhandledXcmVersion: 'Null',
- WeightLimitReached: 'u64',
- Barrier: 'Null',
- WeightNotComputable: 'Null'
- }
- },
- /**
- * Lookup233: staging_xcm::v2::OriginKind
- **/
- StagingXcmV2OriginKind: {
- _enum: ['Native', 'SovereignAccount', 'Superuser', 'Xcm']
- },
- /**
- * Lookup234: staging_xcm::double_encoded::DoubleEncoded<T>
- **/
- StagingXcmDoubleEncoded: {
- encoded: 'Bytes'
- },
- /**
- * Lookup235: staging_xcm::v2::multiasset::MultiAssetFilter
- **/
- StagingXcmV2MultiassetMultiAssetFilter: {
- _enum: {
- Definite: 'StagingXcmV2MultiassetMultiAssets',
- Wild: 'StagingXcmV2MultiassetWildMultiAsset'
- }
- },
- /**
- * Lookup236: staging_xcm::v2::multiasset::WildMultiAsset
- **/
- StagingXcmV2MultiassetWildMultiAsset: {
- _enum: {
- All: 'Null',
- AllOf: {
- id: 'StagingXcmV2MultiassetAssetId',
- fun: 'StagingXcmV2MultiassetWildFungibility'
- }
- }
- },
- /**
- * Lookup237: staging_xcm::v2::multiasset::WildFungibility
- **/
- StagingXcmV2MultiassetWildFungibility: {
- _enum: ['Fungible', 'NonFungible']
- },
- /**
- * Lookup238: staging_xcm::v2::WeightLimit
- **/
- StagingXcmV2WeightLimit: {
- _enum: {
- Unlimited: 'Null',
- Limited: 'Compact<u64>'
- }
- },
- /**
- * Lookup239: staging_xcm::v3::Xcm<Call>
- **/
- StagingXcmV3Xcm: 'Vec<StagingXcmV3Instruction>',
- /**
- * Lookup241: staging_xcm::v3::Instruction<Call>
- **/
- StagingXcmV3Instruction: {
- _enum: {
- WithdrawAsset: 'StagingXcmV3MultiassetMultiAssets',
- ReserveAssetDeposited: 'StagingXcmV3MultiassetMultiAssets',
- ReceiveTeleportedAsset: 'StagingXcmV3MultiassetMultiAssets',
- QueryResponse: {
- queryId: 'Compact<u64>',
- response: 'StagingXcmV3Response',
- maxWeight: 'SpWeightsWeightV2Weight',
- querier: 'Option<StagingXcmV3MultiLocation>',
- },
- TransferAsset: {
- assets: 'StagingXcmV3MultiassetMultiAssets',
- beneficiary: 'StagingXcmV3MultiLocation',
- },
- TransferReserveAsset: {
- assets: 'StagingXcmV3MultiassetMultiAssets',
- dest: 'StagingXcmV3MultiLocation',
- xcm: 'StagingXcmV3Xcm',
- },
- Transact: {
- originKind: 'StagingXcmV2OriginKind',
- requireWeightAtMost: 'SpWeightsWeightV2Weight',
- call: 'StagingXcmDoubleEncoded',
- },
- HrmpNewChannelOpenRequest: {
- sender: 'Compact<u32>',
- maxMessageSize: 'Compact<u32>',
- maxCapacity: 'Compact<u32>',
- },
- HrmpChannelAccepted: {
- recipient: 'Compact<u32>',
- },
- HrmpChannelClosing: {
- initiator: 'Compact<u32>',
- sender: 'Compact<u32>',
- recipient: 'Compact<u32>',
- },
- ClearOrigin: 'Null',
- DescendOrigin: 'StagingXcmV3Junctions',
- ReportError: 'StagingXcmV3QueryResponseInfo',
- DepositAsset: {
- assets: 'StagingXcmV3MultiassetMultiAssetFilter',
- beneficiary: 'StagingXcmV3MultiLocation',
- },
- DepositReserveAsset: {
- assets: 'StagingXcmV3MultiassetMultiAssetFilter',
- dest: 'StagingXcmV3MultiLocation',
- xcm: 'StagingXcmV3Xcm',
- },
- ExchangeAsset: {
- give: 'StagingXcmV3MultiassetMultiAssetFilter',
- want: 'StagingXcmV3MultiassetMultiAssets',
- maximal: 'bool',
- },
- InitiateReserveWithdraw: {
- assets: 'StagingXcmV3MultiassetMultiAssetFilter',
- reserve: 'StagingXcmV3MultiLocation',
- xcm: 'StagingXcmV3Xcm',
- },
- InitiateTeleport: {
- assets: 'StagingXcmV3MultiassetMultiAssetFilter',
- dest: 'StagingXcmV3MultiLocation',
- xcm: 'StagingXcmV3Xcm',
- },
- ReportHolding: {
- responseInfo: 'StagingXcmV3QueryResponseInfo',
- assets: 'StagingXcmV3MultiassetMultiAssetFilter',
- },
- BuyExecution: {
- fees: 'StagingXcmV3MultiAsset',
- weightLimit: 'StagingXcmV3WeightLimit',
- },
- RefundSurplus: 'Null',
- SetErrorHandler: 'StagingXcmV3Xcm',
- SetAppendix: 'StagingXcmV3Xcm',
- ClearError: 'Null',
- ClaimAsset: {
- assets: 'StagingXcmV3MultiassetMultiAssets',
- ticket: 'StagingXcmV3MultiLocation',
- },
- Trap: 'Compact<u64>',
- SubscribeVersion: {
- queryId: 'Compact<u64>',
- maxResponseWeight: 'SpWeightsWeightV2Weight',
- },
- UnsubscribeVersion: 'Null',
- BurnAsset: 'StagingXcmV3MultiassetMultiAssets',
- ExpectAsset: 'StagingXcmV3MultiassetMultiAssets',
- ExpectOrigin: 'Option<StagingXcmV3MultiLocation>',
- ExpectError: 'Option<(u32,StagingXcmV3TraitsError)>',
- ExpectTransactStatus: 'StagingXcmV3MaybeErrorCode',
- QueryPallet: {
- moduleName: 'Bytes',
- responseInfo: 'StagingXcmV3QueryResponseInfo',
- },
- ExpectPallet: {
- index: 'Compact<u32>',
- name: 'Bytes',
- moduleName: 'Bytes',
- crateMajor: 'Compact<u32>',
- minCrateMinor: 'Compact<u32>',
- },
- ReportTransactStatus: 'StagingXcmV3QueryResponseInfo',
- ClearTransactStatus: 'Null',
- UniversalOrigin: 'StagingXcmV3Junction',
- ExportMessage: {
- network: 'StagingXcmV3JunctionNetworkId',
- destination: 'StagingXcmV3Junctions',
- xcm: 'StagingXcmV3Xcm',
- },
- LockAsset: {
- asset: 'StagingXcmV3MultiAsset',
- unlocker: 'StagingXcmV3MultiLocation',
- },
- UnlockAsset: {
- asset: 'StagingXcmV3MultiAsset',
- target: 'StagingXcmV3MultiLocation',
- },
- NoteUnlockable: {
- asset: 'StagingXcmV3MultiAsset',
- owner: 'StagingXcmV3MultiLocation',
- },
- RequestUnlock: {
- asset: 'StagingXcmV3MultiAsset',
- locker: 'StagingXcmV3MultiLocation',
- },
- SetFeesMode: {
- jitWithdraw: 'bool',
- },
- SetTopic: '[u8;32]',
- ClearTopic: 'Null',
- AliasOrigin: 'StagingXcmV3MultiLocation',
- UnpaidExecution: {
- weightLimit: 'StagingXcmV3WeightLimit',
- checkOrigin: 'Option<StagingXcmV3MultiLocation>'
- }
- }
- },
- /**
- * Lookup242: staging_xcm::v3::Response
- **/
- StagingXcmV3Response: {
- _enum: {
- Null: 'Null',
- Assets: 'StagingXcmV3MultiassetMultiAssets',
- ExecutionResult: 'Option<(u32,StagingXcmV3TraitsError)>',
- Version: 'u32',
- PalletsInfo: 'Vec<StagingXcmV3PalletInfo>',
- DispatchResult: 'StagingXcmV3MaybeErrorCode'
- }
- },
- /**
- * Lookup245: staging_xcm::v3::traits::Error
- **/
- StagingXcmV3TraitsError: {
- _enum: {
- Overflow: 'Null',
- Unimplemented: 'Null',
- UntrustedReserveLocation: 'Null',
- UntrustedTeleportLocation: 'Null',
- LocationFull: 'Null',
- LocationNotInvertible: 'Null',
- BadOrigin: 'Null',
- InvalidLocation: 'Null',
- AssetNotFound: 'Null',
- FailedToTransactAsset: 'Null',
- NotWithdrawable: 'Null',
- LocationCannotHold: 'Null',
- ExceedsMaxMessageSize: 'Null',
- DestinationUnsupported: 'Null',
- Transport: 'Null',
- Unroutable: 'Null',
- UnknownClaim: 'Null',
- FailedToDecode: 'Null',
- MaxWeightInvalid: 'Null',
- NotHoldingFees: 'Null',
- TooExpensive: 'Null',
- Trap: 'u64',
- ExpectationFalse: 'Null',
- PalletNotFound: 'Null',
- NameMismatch: 'Null',
- VersionIncompatible: 'Null',
- HoldingWouldOverflow: 'Null',
- ExportError: 'Null',
- ReanchorFailed: 'Null',
- NoDeal: 'Null',
- FeesNotMet: 'Null',
- LockError: 'Null',
- NoPermission: 'Null',
- Unanchored: 'Null',
- NotDepositable: 'Null',
- UnhandledXcmVersion: 'Null',
- WeightLimitReached: 'SpWeightsWeightV2Weight',
- Barrier: 'Null',
- WeightNotComputable: 'Null',
- ExceedsStackLimit: 'Null'
- }
- },
- /**
- * Lookup247: staging_xcm::v3::PalletInfo
- **/
- StagingXcmV3PalletInfo: {
- index: 'Compact<u32>',
- name: 'Bytes',
- moduleName: 'Bytes',
- major: 'Compact<u32>',
- minor: 'Compact<u32>',
- patch: 'Compact<u32>'
- },
- /**
- * Lookup250: staging_xcm::v3::MaybeErrorCode
- **/
- StagingXcmV3MaybeErrorCode: {
- _enum: {
- Success: 'Null',
- Error: 'Bytes',
- TruncatedError: 'Bytes'
- }
- },
- /**
- * Lookup253: staging_xcm::v3::QueryResponseInfo
- **/
- StagingXcmV3QueryResponseInfo: {
- destination: 'StagingXcmV3MultiLocation',
- queryId: 'Compact<u64>',
- maxWeight: 'SpWeightsWeightV2Weight'
- },
- /**
- * Lookup254: staging_xcm::v3::multiasset::MultiAssetFilter
- **/
- StagingXcmV3MultiassetMultiAssetFilter: {
- _enum: {
- Definite: 'StagingXcmV3MultiassetMultiAssets',
- Wild: 'StagingXcmV3MultiassetWildMultiAsset'
- }
- },
- /**
- * Lookup255: staging_xcm::v3::multiasset::WildMultiAsset
- **/
- StagingXcmV3MultiassetWildMultiAsset: {
- _enum: {
- All: 'Null',
- AllOf: {
- id: 'StagingXcmV3MultiassetAssetId',
- fun: 'StagingXcmV3MultiassetWildFungibility',
- },
- AllCounted: 'Compact<u32>',
- AllOfCounted: {
- id: 'StagingXcmV3MultiassetAssetId',
- fun: 'StagingXcmV3MultiassetWildFungibility',
- count: 'Compact<u32>'
- }
- }
- },
- /**
- * Lookup256: staging_xcm::v3::multiasset::WildFungibility
- **/
- StagingXcmV3MultiassetWildFungibility: {
- _enum: ['Fungible', 'NonFungible']
- },
- /**
- * Lookup265: cumulus_pallet_xcm::pallet::Call<T>
- **/
- CumulusPalletXcmCall: 'Null',
- /**
- * Lookup266: cumulus_pallet_dmp_queue::pallet::Call<T>
- **/
- CumulusPalletDmpQueueCall: {
- _enum: {
- service_overweight: {
- index: 'u64',
- weightLimit: 'SpWeightsWeightV2Weight'
- }
- }
- },
- /**
- * Lookup267: pallet_inflation::pallet::Call<T>
- **/
- PalletInflationCall: {
- _enum: {
- start_inflation: {
- inflationStartRelayBlock: 'u32'
- }
- }
- },
- /**
- * Lookup268: pallet_unique::pallet::Call<T>
- **/
- PalletUniqueCall: {
- _enum: {
- create_collection: {
- collectionName: 'Vec<u16>',
- collectionDescription: 'Vec<u16>',
- tokenPrefix: 'Bytes',
- mode: 'UpDataStructsCollectionMode',
- },
- create_collection_ex: {
- data: 'UpDataStructsCreateCollectionData',
- },
- destroy_collection: {
- collectionId: 'u32',
- },
- add_to_allow_list: {
- collectionId: 'u32',
- address: 'PalletEvmAccountBasicCrossAccountIdRepr',
- },
- remove_from_allow_list: {
- collectionId: 'u32',
- address: 'PalletEvmAccountBasicCrossAccountIdRepr',
- },
- change_collection_owner: {
- collectionId: 'u32',
- newOwner: 'AccountId32',
- },
- add_collection_admin: {
- collectionId: 'u32',
- newAdminId: 'PalletEvmAccountBasicCrossAccountIdRepr',
- },
- remove_collection_admin: {
- collectionId: 'u32',
- accountId: 'PalletEvmAccountBasicCrossAccountIdRepr',
- },
- set_collection_sponsor: {
- collectionId: 'u32',
- newSponsor: 'AccountId32',
- },
- confirm_sponsorship: {
- collectionId: 'u32',
- },
- remove_collection_sponsor: {
- collectionId: 'u32',
- },
- create_item: {
- collectionId: 'u32',
- owner: 'PalletEvmAccountBasicCrossAccountIdRepr',
- data: 'UpDataStructsCreateItemData',
- },
- create_multiple_items: {
- collectionId: 'u32',
- owner: 'PalletEvmAccountBasicCrossAccountIdRepr',
- itemsData: 'Vec<UpDataStructsCreateItemData>',
- },
- set_collection_properties: {
- collectionId: 'u32',
- properties: 'Vec<UpDataStructsProperty>',
- },
- delete_collection_properties: {
- collectionId: 'u32',
- propertyKeys: 'Vec<Bytes>',
- },
- set_token_properties: {
- collectionId: 'u32',
- tokenId: 'u32',
- properties: 'Vec<UpDataStructsProperty>',
- },
- delete_token_properties: {
- collectionId: 'u32',
- tokenId: 'u32',
- propertyKeys: 'Vec<Bytes>',
- },
- set_token_property_permissions: {
- collectionId: 'u32',
- propertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
- },
- create_multiple_items_ex: {
- collectionId: 'u32',
- data: 'UpDataStructsCreateItemExData',
- },
- set_transfers_enabled_flag: {
- collectionId: 'u32',
- value: 'bool',
- },
- burn_item: {
- collectionId: 'u32',
- itemId: 'u32',
- value: 'u128',
- },
- burn_from: {
- collectionId: 'u32',
- from: 'PalletEvmAccountBasicCrossAccountIdRepr',
- itemId: 'u32',
- value: 'u128',
- },
- transfer: {
- recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',
- collectionId: 'u32',
- itemId: 'u32',
- value: 'u128',
- },
- approve: {
- spender: 'PalletEvmAccountBasicCrossAccountIdRepr',
- collectionId: 'u32',
- itemId: 'u32',
- amount: 'u128',
- },
- approve_from: {
- from: 'PalletEvmAccountBasicCrossAccountIdRepr',
- to: 'PalletEvmAccountBasicCrossAccountIdRepr',
- collectionId: 'u32',
- itemId: 'u32',
- amount: 'u128',
- },
- transfer_from: {
- from: 'PalletEvmAccountBasicCrossAccountIdRepr',
- recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',
- collectionId: 'u32',
- itemId: 'u32',
- value: 'u128',
- },
- set_collection_limits: {
- collectionId: 'u32',
- newLimit: 'UpDataStructsCollectionLimits',
- },
- set_collection_permissions: {
- collectionId: 'u32',
- newPermission: 'UpDataStructsCollectionPermissions',
- },
- repartition: {
- collectionId: 'u32',
- tokenId: 'u32',
- amount: 'u128',
- },
- set_allowance_for_all: {
- collectionId: 'u32',
- operator: 'PalletEvmAccountBasicCrossAccountIdRepr',
- approve: 'bool',
- },
- force_repair_collection: {
- collectionId: 'u32',
- },
- force_repair_item: {
- collectionId: 'u32',
- itemId: 'u32'
- }
- }
- },
- /**
- * Lookup273: up_data_structs::CollectionMode
- **/
- UpDataStructsCollectionMode: {
- _enum: {
- NFT: 'Null',
- Fungible: 'u8',
- ReFungible: 'Null'
- }
- },
- /**
- * Lookup274: up_data_structs::CreateCollectionData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsCreateCollectionData: {
- mode: 'UpDataStructsCollectionMode',
- access: 'Option<UpDataStructsAccessMode>',
- name: 'Vec<u16>',
- description: 'Vec<u16>',
- tokenPrefix: 'Bytes',
- limits: 'Option<UpDataStructsCollectionLimits>',
- permissions: 'Option<UpDataStructsCollectionPermissions>',
- tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
- properties: 'Vec<UpDataStructsProperty>',
- adminList: 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
- pendingSponsor: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>',
- flags: '[u8;1]'
- },
- /**
- * Lookup275: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>
- **/
- PalletEvmAccountBasicCrossAccountIdRepr: {
- _enum: {
- Substrate: 'AccountId32',
- Ethereum: 'H160'
- }
- },
- /**
- * Lookup277: up_data_structs::AccessMode
- **/
- UpDataStructsAccessMode: {
- _enum: ['Normal', 'AllowList']
- },
- /**
- * Lookup279: up_data_structs::CollectionLimits
- **/
- UpDataStructsCollectionLimits: {
- accountTokenOwnershipLimit: 'Option<u32>',
- sponsoredDataSize: 'Option<u32>',
- sponsoredDataRateLimit: 'Option<UpDataStructsSponsoringRateLimit>',
- tokenLimit: 'Option<u32>',
- sponsorTransferTimeout: 'Option<u32>',
- sponsorApproveTimeout: 'Option<u32>',
- ownerCanTransfer: 'Option<bool>',
- ownerCanDestroy: 'Option<bool>',
- transfersEnabled: 'Option<bool>'
- },
- /**
- * Lookup281: up_data_structs::SponsoringRateLimit
- **/
- UpDataStructsSponsoringRateLimit: {
- _enum: {
- SponsoringDisabled: 'Null',
- Blocks: 'u32'
- }
- },
- /**
- * Lookup284: up_data_structs::CollectionPermissions
- **/
- UpDataStructsCollectionPermissions: {
- access: 'Option<UpDataStructsAccessMode>',
- mintMode: 'Option<bool>',
- nesting: 'Option<UpDataStructsNestingPermissions>'
- },
- /**
- * Lookup286: up_data_structs::NestingPermissions
- **/
- UpDataStructsNestingPermissions: {
- tokenOwner: 'bool',
- collectionAdmin: 'bool',
- restricted: 'Option<UpDataStructsOwnerRestrictedSet>'
- },
- /**
- * Lookup288: up_data_structs::OwnerRestrictedSet
- **/
- UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',
- /**
- * Lookup294: up_data_structs::PropertyKeyPermission
- **/
- UpDataStructsPropertyKeyPermission: {
- key: 'Bytes',
- permission: 'UpDataStructsPropertyPermission'
- },
- /**
- * Lookup296: up_data_structs::PropertyPermission
- **/
- UpDataStructsPropertyPermission: {
- mutable: 'bool',
- collectionAdmin: 'bool',
- tokenOwner: 'bool'
- },
- /**
- * Lookup299: up_data_structs::Property
- **/
- UpDataStructsProperty: {
- key: 'Bytes',
- value: 'Bytes'
- },
- /**
- * Lookup304: up_data_structs::CreateItemData
- **/
- UpDataStructsCreateItemData: {
- _enum: {
- NFT: 'UpDataStructsCreateNftData',
- Fungible: 'UpDataStructsCreateFungibleData',
- ReFungible: 'UpDataStructsCreateReFungibleData'
- }
- },
- /**
- * Lookup305: up_data_structs::CreateNftData
- **/
- UpDataStructsCreateNftData: {
- properties: 'Vec<UpDataStructsProperty>'
- },
- /**
- * Lookup306: up_data_structs::CreateFungibleData
- **/
- UpDataStructsCreateFungibleData: {
- value: 'u128'
- },
- /**
- * Lookup307: up_data_structs::CreateReFungibleData
- **/
- UpDataStructsCreateReFungibleData: {
- pieces: 'u128',
- properties: 'Vec<UpDataStructsProperty>'
- },
- /**
- * Lookup311: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsCreateItemExData: {
- _enum: {
- NFT: 'Vec<UpDataStructsCreateNftExData>',
- Fungible: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
- RefungibleMultipleItems: 'Vec<UpDataStructsCreateRefungibleExSingleOwner>',
- RefungibleMultipleOwners: 'UpDataStructsCreateRefungibleExMultipleOwners'
- }
- },
- /**
- * Lookup313: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsCreateNftExData: {
- properties: 'Vec<UpDataStructsProperty>',
- owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
- },
- /**
- * Lookup320: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsCreateRefungibleExSingleOwner: {
- user: 'PalletEvmAccountBasicCrossAccountIdRepr',
- pieces: 'u128',
- properties: 'Vec<UpDataStructsProperty>'
- },
- /**
- * Lookup322: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsCreateRefungibleExMultipleOwners: {
- users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
- properties: 'Vec<UpDataStructsProperty>'
- },
- /**
- * Lookup323: pallet_configuration::pallet::Call<T>
- **/
- PalletConfigurationCall: {
- _enum: {
- set_weight_to_fee_coefficient_override: {
- coeff: 'Option<u64>',
- },
- set_min_gas_price_override: {
- coeff: 'Option<u64>',
- },
- __Unused2: 'Null',
- set_app_promotion_configuration_override: {
- configuration: 'PalletConfigurationAppPromotionConfiguration',
- },
- set_collator_selection_desired_collators: {
- max: 'Option<u32>',
- },
- set_collator_selection_license_bond: {
- amount: 'Option<u128>',
- },
- set_collator_selection_kick_threshold: {
- threshold: 'Option<u32>'
- }
- }
- },
- /**
- * Lookup325: pallet_configuration::AppPromotionConfiguration<BlockNumber>
- **/
- PalletConfigurationAppPromotionConfiguration: {
- recalculationInterval: 'Option<u32>',
- pendingInterval: 'Option<u32>',
- intervalIncome: 'Option<Perbill>',
- maxStakersPerCalculation: 'Option<u8>'
- },
- /**
- * Lookup330: pallet_structure::pallet::Call<T>
- **/
- PalletStructureCall: 'Null',
- /**
- * Lookup331: pallet_app_promotion::pallet::Call<T>
- **/
- PalletAppPromotionCall: {
- _enum: {
- set_admin_address: {
- admin: 'PalletEvmAccountBasicCrossAccountIdRepr',
- },
- stake: {
- amount: 'u128',
- },
- unstake_all: 'Null',
- sponsor_collection: {
- collectionId: 'u32',
- },
- stop_sponsoring_collection: {
- collectionId: 'u32',
- },
- sponsor_contract: {
- contractId: 'H160',
- },
- stop_sponsoring_contract: {
- contractId: 'H160',
- },
- payout_stakers: {
- stakersNumber: 'Option<u8>',
- },
- unstake_partial: {
- amount: 'u128',
- },
- force_unstake: {
- pendingBlocks: 'Vec<u32>'
- }
- }
- },
- /**
- * Lookup333: pallet_foreign_assets::module::Call<T>
- **/
- PalletForeignAssetsModuleCall: {
- _enum: {
- register_foreign_asset: {
- owner: 'AccountId32',
- location: 'StagingXcmVersionedMultiLocation',
- metadata: 'PalletForeignAssetsModuleAssetMetadata',
- },
- update_foreign_asset: {
- foreignAssetId: 'u32',
- location: 'StagingXcmVersionedMultiLocation',
- metadata: 'PalletForeignAssetsModuleAssetMetadata'
- }
- }
- },
- /**
- * Lookup334: pallet_foreign_assets::module::AssetMetadata<Balance>
- **/
- PalletForeignAssetsModuleAssetMetadata: {
- name: 'Bytes',
- symbol: 'Bytes',
- decimals: 'u8',
- minimalBalance: 'u128'
- },
- /**
- * Lookup337: pallet_evm::pallet::Call<T>
- **/
- PalletEvmCall: {
- _enum: {
- withdraw: {
- address: 'H160',
- value: 'u128',
- },
- call: {
- source: 'H160',
- target: 'H160',
- input: 'Bytes',
- value: 'U256',
- gasLimit: 'u64',
- maxFeePerGas: 'U256',
- maxPriorityFeePerGas: 'Option<U256>',
- nonce: 'Option<U256>',
- accessList: 'Vec<(H160,Vec<H256>)>',
- },
- create: {
- source: 'H160',
- init: 'Bytes',
- value: 'U256',
- gasLimit: 'u64',
- maxFeePerGas: 'U256',
- maxPriorityFeePerGas: 'Option<U256>',
- nonce: 'Option<U256>',
- accessList: 'Vec<(H160,Vec<H256>)>',
- },
- create2: {
- source: 'H160',
- init: 'Bytes',
- salt: 'H256',
- value: 'U256',
- gasLimit: 'u64',
- maxFeePerGas: 'U256',
- maxPriorityFeePerGas: 'Option<U256>',
- nonce: 'Option<U256>',
- accessList: 'Vec<(H160,Vec<H256>)>'
- }
- }
- },
- /**
- * Lookup344: pallet_ethereum::pallet::Call<T>
- **/
- PalletEthereumCall: {
- _enum: {
- transact: {
- transaction: 'EthereumTransactionTransactionV2'
- }
- }
- },
- /**
- * Lookup345: ethereum::transaction::TransactionV2
- **/
- EthereumTransactionTransactionV2: {
- _enum: {
- Legacy: 'EthereumTransactionLegacyTransaction',
- EIP2930: 'EthereumTransactionEip2930Transaction',
- EIP1559: 'EthereumTransactionEip1559Transaction'
- }
- },
- /**
- * Lookup346: ethereum::transaction::LegacyTransaction
- **/
- EthereumTransactionLegacyTransaction: {
- nonce: 'U256',
- gasPrice: 'U256',
- gasLimit: 'U256',
- action: 'EthereumTransactionTransactionAction',
- value: 'U256',
- input: 'Bytes',
- signature: 'EthereumTransactionTransactionSignature'
- },
- /**
- * Lookup347: ethereum::transaction::TransactionAction
- **/
- EthereumTransactionTransactionAction: {
- _enum: {
- Call: 'H160',
- Create: 'Null'
- }
- },
- /**
- * Lookup348: ethereum::transaction::TransactionSignature
- **/
- EthereumTransactionTransactionSignature: {
- v: 'u64',
- r: 'H256',
- s: 'H256'
- },
- /**
- * Lookup350: ethereum::transaction::EIP2930Transaction
- **/
- EthereumTransactionEip2930Transaction: {
- chainId: 'u64',
- nonce: 'U256',
- gasPrice: 'U256',
- gasLimit: 'U256',
- action: 'EthereumTransactionTransactionAction',
- value: 'U256',
- input: 'Bytes',
- accessList: 'Vec<EthereumTransactionAccessListItem>',
- oddYParity: 'bool',
- r: 'H256',
- s: 'H256'
- },
- /**
- * Lookup352: ethereum::transaction::AccessListItem
- **/
- EthereumTransactionAccessListItem: {
- address: 'H160',
- storageKeys: 'Vec<H256>'
- },
- /**
- * Lookup353: ethereum::transaction::EIP1559Transaction
- **/
- EthereumTransactionEip1559Transaction: {
- chainId: 'u64',
- nonce: 'U256',
- maxPriorityFeePerGas: 'U256',
- maxFeePerGas: 'U256',
- gasLimit: 'U256',
- action: 'EthereumTransactionTransactionAction',
- value: 'U256',
- input: 'Bytes',
- accessList: 'Vec<EthereumTransactionAccessListItem>',
- oddYParity: 'bool',
- r: 'H256',
- s: 'H256'
- },
- /**
- * Lookup354: pallet_evm_contract_helpers::pallet::Call<T>
- **/
- PalletEvmContractHelpersCall: {
- _enum: {
- migrate_from_self_sponsoring: {
- addresses: 'Vec<H160>'
- }
- }
- },
- /**
- * Lookup356: pallet_evm_migration::pallet::Call<T>
- **/
- PalletEvmMigrationCall: {
- _enum: {
- begin: {
- address: 'H160',
- },
- set_data: {
- address: 'H160',
- data: 'Vec<(H256,H256)>',
- },
- finish: {
- address: 'H160',
- code: 'Bytes',
- },
- insert_eth_logs: {
- logs: 'Vec<EthereumLog>',
- },
- insert_events: {
- events: 'Vec<Bytes>',
- },
- remove_rmrk_data: 'Null'
- }
- },
- /**
- * Lookup360: ethereum::log::Log
- **/
- EthereumLog: {
- address: 'H160',
- topics: 'Vec<H256>',
- data: 'Bytes'
- },
- /**
- * Lookup361: pallet_maintenance::pallet::Call<T>
- **/
- PalletMaintenanceCall: {
- _enum: ['enable', 'disable']
- },
- /**
- * Lookup362: pallet_utility::pallet::Call<T>
- **/
- PalletUtilityCall: {
- _enum: {
- batch: {
- calls: 'Vec<Call>',
- },
- as_derivative: {
- index: 'u16',
- call: 'Call',
- },
- batch_all: {
- calls: 'Vec<Call>',
- },
- dispatch_as: {
- asOrigin: 'OpalRuntimeOriginCaller',
- call: 'Call',
- },
- force_batch: {
- calls: 'Vec<Call>',
- },
- with_weight: {
- call: 'Call',
- weight: 'SpWeightsWeightV2Weight'
- }
- }
- },
- /**
- * Lookup364: pallet_test_utils::pallet::Call<T>
- **/
- PalletTestUtilsCall: {
- _enum: {
- enable: 'Null',
- set_test_value: {
- value: 'u32',
- },
- set_test_value_and_rollback: {
- value: 'u32',
- },
- inc_test_value: 'Null',
- just_take_fee: 'Null',
- batch_all: {
- calls: 'Vec<Call>'
- }
- }
- },
- /**
- * Lookup366: pallet_scheduler::pallet::Event<T>
- **/
- PalletSchedulerEvent: {
- _enum: {
- Scheduled: {
- when: 'u32',
- index: 'u32',
- },
- Canceled: {
- when: 'u32',
- index: 'u32',
- },
- Dispatched: {
- task: '(u32,u32)',
- id: 'Option<[u8;32]>',
- result: 'Result<Null, SpRuntimeDispatchError>',
- },
- CallUnavailable: {
- task: '(u32,u32)',
- id: 'Option<[u8;32]>',
- },
- PeriodicFailed: {
- task: '(u32,u32)',
- id: 'Option<[u8;32]>',
- },
- PermanentlyOverweight: {
- task: '(u32,u32)',
- id: 'Option<[u8;32]>'
- }
- }
- },
- /**
- * Lookup367: cumulus_pallet_xcmp_queue::pallet::Event<T>
- **/
- CumulusPalletXcmpQueueEvent: {
- _enum: {
- Success: {
- messageHash: '[u8;32]',
- messageId: '[u8;32]',
- weight: 'SpWeightsWeightV2Weight',
- },
- Fail: {
- messageHash: '[u8;32]',
- messageId: '[u8;32]',
- error: 'StagingXcmV3TraitsError',
- weight: 'SpWeightsWeightV2Weight',
- },
- BadVersion: {
- messageHash: '[u8;32]',
- },
- BadFormat: {
- messageHash: '[u8;32]',
- },
- XcmpMessageSent: {
- messageHash: '[u8;32]',
- },
- OverweightEnqueued: {
- sender: 'u32',
- sentAt: 'u32',
- index: 'u64',
- required: 'SpWeightsWeightV2Weight',
- },
- OverweightServiced: {
- index: 'u64',
- used: 'SpWeightsWeightV2Weight'
- }
- }
- },
- /**
- * Lookup368: pallet_xcm::pallet::Event<T>
- **/
- PalletXcmEvent: {
- _enum: {
- Attempted: {
- outcome: 'StagingXcmV3TraitsOutcome',
- },
- Sent: {
- origin: 'StagingXcmV3MultiLocation',
- destination: 'StagingXcmV3MultiLocation',
- message: 'StagingXcmV3Xcm',
- messageId: '[u8;32]',
- },
- UnexpectedResponse: {
- origin: 'StagingXcmV3MultiLocation',
- queryId: 'u64',
- },
- ResponseReady: {
- queryId: 'u64',
- response: 'StagingXcmV3Response',
- },
- Notified: {
- queryId: 'u64',
- palletIndex: 'u8',
- callIndex: 'u8',
- },
- NotifyOverweight: {
- queryId: 'u64',
- palletIndex: 'u8',
- callIndex: 'u8',
- actualWeight: 'SpWeightsWeightV2Weight',
- maxBudgetedWeight: 'SpWeightsWeightV2Weight',
- },
- NotifyDispatchError: {
- queryId: 'u64',
- palletIndex: 'u8',
- callIndex: 'u8',
- },
- NotifyDecodeFailed: {
- queryId: 'u64',
- palletIndex: 'u8',
- callIndex: 'u8',
- },
- InvalidResponder: {
- origin: 'StagingXcmV3MultiLocation',
- queryId: 'u64',
- expectedLocation: 'Option<StagingXcmV3MultiLocation>',
- },
- InvalidResponderVersion: {
- origin: 'StagingXcmV3MultiLocation',
- queryId: 'u64',
- },
- ResponseTaken: {
- queryId: 'u64',
- },
- AssetsTrapped: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- origin: 'StagingXcmV3MultiLocation',
- assets: 'StagingXcmVersionedMultiAssets',
- },
- VersionChangeNotified: {
- destination: 'StagingXcmV3MultiLocation',
- result: 'u32',
- cost: 'StagingXcmV3MultiassetMultiAssets',
- messageId: '[u8;32]',
- },
- SupportedVersionChanged: {
- location: 'StagingXcmV3MultiLocation',
- version: 'u32',
- },
- NotifyTargetSendFail: {
- location: 'StagingXcmV3MultiLocation',
- queryId: 'u64',
- error: 'StagingXcmV3TraitsError',
- },
- NotifyTargetMigrationFail: {
- location: 'StagingXcmVersionedMultiLocation',
- queryId: 'u64',
- },
- InvalidQuerierVersion: {
- origin: 'StagingXcmV3MultiLocation',
- queryId: 'u64',
- },
- InvalidQuerier: {
- origin: 'StagingXcmV3MultiLocation',
- queryId: 'u64',
- expectedQuerier: 'StagingXcmV3MultiLocation',
- maybeActualQuerier: 'Option<StagingXcmV3MultiLocation>',
- },
- VersionNotifyStarted: {
- destination: 'StagingXcmV3MultiLocation',
- cost: 'StagingXcmV3MultiassetMultiAssets',
- messageId: '[u8;32]',
- },
- VersionNotifyRequested: {
- destination: 'StagingXcmV3MultiLocation',
- cost: 'StagingXcmV3MultiassetMultiAssets',
- messageId: '[u8;32]',
- },
- VersionNotifyUnrequested: {
- destination: 'StagingXcmV3MultiLocation',
- cost: 'StagingXcmV3MultiassetMultiAssets',
- messageId: '[u8;32]',
- },
- FeesPaid: {
- paying: 'StagingXcmV3MultiLocation',
- fees: 'StagingXcmV3MultiassetMultiAssets',
- },
- AssetsClaimed: {
- _alias: {
- hash_: 'hash',
- },
- hash_: 'H256',
- origin: 'StagingXcmV3MultiLocation',
- assets: 'StagingXcmVersionedMultiAssets'
- }
- }
- },
- /**
- * Lookup369: staging_xcm::v3::traits::Outcome
- **/
- StagingXcmV3TraitsOutcome: {
- _enum: {
- Complete: 'SpWeightsWeightV2Weight',
- Incomplete: '(SpWeightsWeightV2Weight,StagingXcmV3TraitsError)',
- Error: 'StagingXcmV3TraitsError'
- }
- },
- /**
- * Lookup370: cumulus_pallet_xcm::pallet::Event<T>
- **/
- CumulusPalletXcmEvent: {
- _enum: {
- InvalidFormat: '[u8;32]',
- UnsupportedVersion: '[u8;32]',
- ExecutedDownward: '([u8;32],StagingXcmV3TraitsOutcome)'
- }
- },
- /**
- * Lookup371: cumulus_pallet_dmp_queue::pallet::Event<T>
- **/
- CumulusPalletDmpQueueEvent: {
- _enum: {
- InvalidFormat: {
- messageHash: '[u8;32]',
- },
- UnsupportedVersion: {
- messageHash: '[u8;32]',
- },
- ExecutedDownward: {
- messageHash: '[u8;32]',
- messageId: '[u8;32]',
- outcome: 'StagingXcmV3TraitsOutcome',
- },
- WeightExhausted: {
- messageHash: '[u8;32]',
- messageId: '[u8;32]',
- remainingWeight: 'SpWeightsWeightV2Weight',
- requiredWeight: 'SpWeightsWeightV2Weight',
- },
- OverweightEnqueued: {
- messageHash: '[u8;32]',
- messageId: '[u8;32]',
- overweightIndex: 'u64',
- requiredWeight: 'SpWeightsWeightV2Weight',
- },
- OverweightServiced: {
- overweightIndex: 'u64',
- weightUsed: 'SpWeightsWeightV2Weight',
- },
- MaxMessagesExhausted: {
- messageHash: '[u8;32]'
- }
- }
- },
- /**
- * Lookup372: pallet_configuration::pallet::Event<T>
- **/
- PalletConfigurationEvent: {
- _enum: {
- NewDesiredCollators: {
- desiredCollators: 'Option<u32>',
- },
- NewCollatorLicenseBond: {
- bondCost: 'Option<u128>',
- },
- NewCollatorKickThreshold: {
- lengthInBlocks: 'Option<u32>'
- }
- }
- },
- /**
- * Lookup373: pallet_common::pallet::Event<T>
- **/
- PalletCommonEvent: {
- _enum: {
- CollectionCreated: '(u32,u8,AccountId32)',
- CollectionDestroyed: 'u32',
- ItemCreated: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
- ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
- Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
- Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
- ApprovedForAll: '(u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,bool)',
- CollectionPropertySet: '(u32,Bytes)',
- CollectionPropertyDeleted: '(u32,Bytes)',
- TokenPropertySet: '(u32,u32,Bytes)',
- TokenPropertyDeleted: '(u32,u32,Bytes)',
- PropertyPermissionSet: '(u32,Bytes)',
- AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
- AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
- CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
- CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
- CollectionLimitSet: 'u32',
- CollectionOwnerChanged: '(u32,AccountId32)',
- CollectionPermissionSet: 'u32',
- CollectionSponsorSet: '(u32,AccountId32)',
- SponsorshipConfirmed: '(u32,AccountId32)',
- CollectionSponsorRemoved: 'u32'
- }
- },
- /**
- * Lookup374: pallet_structure::pallet::Event<T>
- **/
- PalletStructureEvent: {
- _enum: {
- Executed: 'Result<Null, SpRuntimeDispatchError>'
- }
- },
- /**
- * Lookup375: pallet_app_promotion::pallet::Event<T>
- **/
- PalletAppPromotionEvent: {
- _enum: {
- StakingRecalculation: '(AccountId32,u128,u128)',
- Stake: '(AccountId32,u128)',
- Unstake: '(AccountId32,u128)',
- SetAdmin: 'AccountId32'
- }
- },
- /**
- * Lookup376: pallet_foreign_assets::module::Event<T>
- **/
- PalletForeignAssetsModuleEvent: {
- _enum: {
- ForeignAssetRegistered: {
- assetId: 'u32',
- assetAddress: 'StagingXcmV3MultiLocation',
- metadata: 'PalletForeignAssetsModuleAssetMetadata',
- },
- ForeignAssetUpdated: {
- assetId: 'u32',
- assetAddress: 'StagingXcmV3MultiLocation',
- metadata: 'PalletForeignAssetsModuleAssetMetadata',
- },
- AssetRegistered: {
- assetId: 'PalletForeignAssetsAssetId',
- metadata: 'PalletForeignAssetsModuleAssetMetadata',
- },
- AssetUpdated: {
- assetId: 'PalletForeignAssetsAssetId',
- metadata: 'PalletForeignAssetsModuleAssetMetadata'
- }
- }
- },
- /**
- * Lookup377: pallet_evm::pallet::Event<T>
- **/
- PalletEvmEvent: {
- _enum: {
- Log: {
- log: 'EthereumLog',
- },
- Created: {
- address: 'H160',
- },
- CreatedFailed: {
- address: 'H160',
- },
- Executed: {
- address: 'H160',
- },
- ExecutedFailed: {
- address: 'H160'
- }
- }
- },
- /**
- * Lookup378: pallet_ethereum::pallet::Event
- **/
- PalletEthereumEvent: {
- _enum: {
- Executed: {
- from: 'H160',
- to: 'H160',
- transactionHash: 'H256',
- exitReason: 'EvmCoreErrorExitReason',
- extraData: 'Bytes'
- }
- }
- },
- /**
- * Lookup379: evm_core::error::ExitReason
- **/
- EvmCoreErrorExitReason: {
- _enum: {
- Succeed: 'EvmCoreErrorExitSucceed',
- Error: 'EvmCoreErrorExitError',
- Revert: 'EvmCoreErrorExitRevert',
- Fatal: 'EvmCoreErrorExitFatal'
- }
- },
- /**
- * Lookup380: evm_core::error::ExitSucceed
- **/
- EvmCoreErrorExitSucceed: {
- _enum: ['Stopped', 'Returned', 'Suicided']
- },
- /**
- * Lookup381: evm_core::error::ExitError
- **/
- EvmCoreErrorExitError: {
- _enum: {
- StackUnderflow: 'Null',
- StackOverflow: 'Null',
- InvalidJump: 'Null',
- InvalidRange: 'Null',
- DesignatedInvalid: 'Null',
- CallTooDeep: 'Null',
- CreateCollision: 'Null',
- CreateContractLimit: 'Null',
- OutOfOffset: 'Null',
- OutOfGas: 'Null',
- OutOfFund: 'Null',
- PCUnderflow: 'Null',
- CreateEmpty: 'Null',
- Other: 'Text',
- MaxNonce: 'Null',
- InvalidCode: 'u8'
- }
- },
- /**
- * Lookup385: evm_core::error::ExitRevert
- **/
- EvmCoreErrorExitRevert: {
- _enum: ['Reverted']
- },
- /**
- * Lookup386: evm_core::error::ExitFatal
- **/
- EvmCoreErrorExitFatal: {
- _enum: {
- NotSupported: 'Null',
- UnhandledInterrupt: 'Null',
- CallErrorAsFatal: 'EvmCoreErrorExitError',
- Other: 'Text'
- }
- },
- /**
- * Lookup387: pallet_evm_contract_helpers::pallet::Event<T>
- **/
- PalletEvmContractHelpersEvent: {
- _enum: {
- ContractSponsorSet: '(H160,AccountId32)',
- ContractSponsorshipConfirmed: '(H160,AccountId32)',
- ContractSponsorRemoved: 'H160'
- }
- },
- /**
- * Lookup388: pallet_evm_migration::pallet::Event<T>
- **/
- PalletEvmMigrationEvent: {
- _enum: ['TestEvent']
- },
- /**
- * Lookup389: pallet_maintenance::pallet::Event<T>
- **/
- PalletMaintenanceEvent: {
- _enum: ['MaintenanceEnabled', 'MaintenanceDisabled']
- },
- /**
- * Lookup390: pallet_utility::pallet::Event
- **/
- PalletUtilityEvent: {
- _enum: {
- BatchInterrupted: {
- index: 'u32',
- error: 'SpRuntimeDispatchError',
- },
- BatchCompleted: 'Null',
- BatchCompletedWithErrors: 'Null',
- ItemCompleted: 'Null',
- ItemFailed: {
- error: 'SpRuntimeDispatchError',
- },
- DispatchedAs: {
- result: 'Result<Null, SpRuntimeDispatchError>'
- }
- }
- },
- /**
- * Lookup391: pallet_test_utils::pallet::Event<T>
- **/
- PalletTestUtilsEvent: {
- _enum: ['ValueIsSet', 'ShouldRollback', 'BatchCompleted']
- },
- /**
- * Lookup392: frame_system::Phase
- **/
- FrameSystemPhase: {
- _enum: {
- ApplyExtrinsic: 'u32',
- Finalization: 'Null',
- Initialization: 'Null'
- }
- },
- /**
- * Lookup394: frame_system::LastRuntimeUpgradeInfo
- **/
- FrameSystemLastRuntimeUpgradeInfo: {
- specVersion: 'Compact<u32>',
- specName: 'Text'
- },
- /**
- * Lookup395: frame_system::limits::BlockWeights
- **/
- FrameSystemLimitsBlockWeights: {
- baseBlock: 'SpWeightsWeightV2Weight',
- maxBlock: 'SpWeightsWeightV2Weight',
- perClass: 'FrameSupportDispatchPerDispatchClassWeightsPerClass'
- },
- /**
- * Lookup396: frame_support::dispatch::PerDispatchClass<frame_system::limits::WeightsPerClass>
- **/
- FrameSupportDispatchPerDispatchClassWeightsPerClass: {
- normal: 'FrameSystemLimitsWeightsPerClass',
- operational: 'FrameSystemLimitsWeightsPerClass',
- mandatory: 'FrameSystemLimitsWeightsPerClass'
- },
- /**
- * Lookup397: frame_system::limits::WeightsPerClass
- **/
- FrameSystemLimitsWeightsPerClass: {
- baseExtrinsic: 'SpWeightsWeightV2Weight',
- maxExtrinsic: 'Option<SpWeightsWeightV2Weight>',
- maxTotal: 'Option<SpWeightsWeightV2Weight>',
- reserved: 'Option<SpWeightsWeightV2Weight>'
- },
- /**
- * Lookup399: frame_system::limits::BlockLength
- **/
- FrameSystemLimitsBlockLength: {
- max: 'FrameSupportDispatchPerDispatchClassU32'
- },
- /**
- * Lookup400: frame_support::dispatch::PerDispatchClass<T>
- **/
- FrameSupportDispatchPerDispatchClassU32: {
- normal: 'u32',
- operational: 'u32',
- mandatory: 'u32'
- },
- /**
- * Lookup401: sp_weights::RuntimeDbWeight
- **/
- SpWeightsRuntimeDbWeight: {
- read: 'u64',
- write: 'u64'
- },
- /**
- * Lookup402: sp_version::RuntimeVersion
- **/
- SpVersionRuntimeVersion: {
- specName: 'Text',
- implName: 'Text',
- authoringVersion: 'u32',
- specVersion: 'u32',
- implVersion: 'u32',
- apis: 'Vec<([u8;8],u32)>',
- transactionVersion: 'u32',
- stateVersion: 'u8'
- },
- /**
- * Lookup406: frame_system::pallet::Error<T>
- **/
- FrameSystemError: {
- _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
- },
- /**
- * Lookup408: cumulus_pallet_parachain_system::unincluded_segment::Ancestor<primitive_types::H256>
- **/
- CumulusPalletParachainSystemUnincludedSegmentAncestor: {
- usedBandwidth: 'CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth',
- paraHeadHash: 'Option<H256>',
- consumedGoAheadSignal: 'Option<PolkadotPrimitivesV5UpgradeGoAhead>'
- },
- /**
- * Lookup409: cumulus_pallet_parachain_system::unincluded_segment::UsedBandwidth
- **/
- CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth: {
- umpMsgCount: 'u32',
- umpTotalBytes: 'u32',
- hrmpOutgoing: 'BTreeMap<u32, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate>'
- },
- /**
- * Lookup411: cumulus_pallet_parachain_system::unincluded_segment::HrmpChannelUpdate
- **/
- CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate: {
- msgCount: 'u32',
- totalBytes: 'u32'
- },
- /**
- * Lookup415: polkadot_primitives::v5::UpgradeGoAhead
- **/
- PolkadotPrimitivesV5UpgradeGoAhead: {
- _enum: ['Abort', 'GoAhead']
- },
- /**
- * Lookup416: cumulus_pallet_parachain_system::unincluded_segment::SegmentTracker<primitive_types::H256>
- **/
- CumulusPalletParachainSystemUnincludedSegmentSegmentTracker: {
- usedBandwidth: 'CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth',
- hrmpWatermark: 'Option<u32>',
- consumedGoAheadSignal: 'Option<PolkadotPrimitivesV5UpgradeGoAhead>'
- },
- /**
- * Lookup418: polkadot_primitives::v5::UpgradeRestriction
- **/
- PolkadotPrimitivesV5UpgradeRestriction: {
- _enum: ['Present']
- },
- /**
- * Lookup419: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
- **/
- CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {
- dmqMqcHead: 'H256',
- relayDispatchQueueRemainingCapacity: 'CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity',
- ingressChannels: 'Vec<(u32,PolkadotPrimitivesV5AbridgedHrmpChannel)>',
- egressChannels: 'Vec<(u32,PolkadotPrimitivesV5AbridgedHrmpChannel)>'
- },
- /**
- * Lookup420: cumulus_pallet_parachain_system::relay_state_snapshot::RelayDispatchQueueRemainingCapacity
- **/
- CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity: {
- remainingCount: 'u32',
- remainingSize: 'u32'
- },
- /**
- * Lookup423: polkadot_primitives::v5::AbridgedHrmpChannel
- **/
- PolkadotPrimitivesV5AbridgedHrmpChannel: {
- maxCapacity: 'u32',
- maxTotalSize: 'u32',
- maxMessageSize: 'u32',
- msgCount: 'u32',
- totalSize: 'u32',
- mqcHead: 'Option<H256>'
- },
- /**
- * Lookup424: polkadot_primitives::v5::AbridgedHostConfiguration
- **/
- PolkadotPrimitivesV5AbridgedHostConfiguration: {
- maxCodeSize: 'u32',
- maxHeadDataSize: 'u32',
- maxUpwardQueueCount: 'u32',
- maxUpwardQueueSize: 'u32',
- maxUpwardMessageSize: 'u32',
- maxUpwardMessageNumPerCandidate: 'u32',
- hrmpMaxMessageNumPerCandidate: 'u32',
- validationUpgradeCooldown: 'u32',
- validationUpgradeDelay: 'u32',
- asyncBackingParams: 'PolkadotPrimitivesVstagingAsyncBackingParams'
- },
- /**
- * Lookup425: polkadot_primitives::vstaging::AsyncBackingParams
- **/
- PolkadotPrimitivesVstagingAsyncBackingParams: {
- maxCandidateDepth: 'u32',
- allowedAncestryLen: 'u32'
- },
- /**
- * Lookup431: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain_primitives::primitives::Id>
- **/
- PolkadotCorePrimitivesOutboundHrmpMessage: {
- recipient: 'u32',
- data: 'Bytes'
- },
- /**
- * Lookup432: cumulus_pallet_parachain_system::CodeUpgradeAuthorization<T>
- **/
- CumulusPalletParachainSystemCodeUpgradeAuthorization: {
- codeHash: 'H256',
- checkVersion: 'bool'
- },
- /**
- * Lookup433: cumulus_pallet_parachain_system::pallet::Error<T>
- **/
- CumulusPalletParachainSystemError: {
- _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']
- },
- /**
- * Lookup435: pallet_collator_selection::pallet::Error<T>
- **/
- PalletCollatorSelectionError: {
- _enum: ['TooManyCandidates', 'Unknown', 'Permission', 'AlreadyHoldingLicense', 'NoLicense', 'AlreadyCandidate', 'NotCandidate', 'TooManyInvulnerables', 'TooFewInvulnerables', 'AlreadyInvulnerable', 'NotInvulnerable', 'NoAssociatedValidatorId', 'ValidatorNotRegistered']
- },
- /**
- * Lookup439: sp_core::crypto::KeyTypeId
- **/
- SpCoreCryptoKeyTypeId: '[u8;4]',
- /**
- * Lookup440: pallet_session::pallet::Error<T>
- **/
- PalletSessionError: {
- _enum: ['InvalidProof', 'NoAssociatedValidatorId', 'DuplicatedKey', 'NoKeys', 'NoAccount']
- },
- /**
- * Lookup446: pallet_balances::types::BalanceLock<Balance>
- **/
- PalletBalancesBalanceLock: {
- id: '[u8;8]',
- amount: 'u128',
- reasons: 'PalletBalancesReasons'
- },
- /**
- * Lookup447: pallet_balances::types::Reasons
- **/
- PalletBalancesReasons: {
- _enum: ['Fee', 'Misc', 'All']
- },
- /**
- * Lookup450: pallet_balances::types::ReserveData<ReserveIdentifier, Balance>
- **/
- PalletBalancesReserveData: {
- id: '[u8;16]',
- amount: 'u128'
- },
- /**
- * Lookup454: opal_runtime::RuntimeHoldReason
- **/
- OpalRuntimeRuntimeHoldReason: {
- _enum: {
- __Unused0: 'Null',
- __Unused1: 'Null',
- __Unused2: 'Null',
- __Unused3: 'Null',
- __Unused4: 'Null',
- __Unused5: 'Null',
- __Unused6: 'Null',
- __Unused7: 'Null',
- __Unused8: 'Null',
- __Unused9: 'Null',
- __Unused10: 'Null',
- __Unused11: 'Null',
- __Unused12: 'Null',
- __Unused13: 'Null',
- __Unused14: 'Null',
- __Unused15: 'Null',
- __Unused16: 'Null',
- __Unused17: 'Null',
- __Unused18: 'Null',
- __Unused19: 'Null',
- __Unused20: 'Null',
- __Unused21: 'Null',
- __Unused22: 'Null',
- CollatorSelection: 'PalletCollatorSelectionHoldReason'
- }
- },
- /**
- * Lookup455: pallet_collator_selection::pallet::HoldReason
- **/
- PalletCollatorSelectionHoldReason: {
- _enum: ['LicenseBond']
- },
- /**
- * Lookup458: pallet_balances::types::IdAmount<Id, Balance>
- **/
- PalletBalancesIdAmount: {
- id: '[u8;16]',
- amount: 'u128'
- },
- /**
- * Lookup460: pallet_balances::pallet::Error<T, I>
- **/
- PalletBalancesError: {
- _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'Expendability', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves', 'TooManyHolds', 'TooManyFreezes']
- },
- /**
- * Lookup462: pallet_transaction_payment::Releases
- **/
- PalletTransactionPaymentReleases: {
- _enum: ['V1Ancient', 'V2']
- },
- /**
- * Lookup463: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
- **/
- PalletTreasuryProposal: {
- proposer: 'AccountId32',
- value: 'u128',
- beneficiary: 'AccountId32',
- bond: 'u128'
- },
- /**
- * Lookup466: frame_support::PalletId
- **/
- FrameSupportPalletId: '[u8;8]',
- /**
- * Lookup467: pallet_treasury::pallet::Error<T, I>
- **/
- PalletTreasuryError: {
- _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'InsufficientPermission', 'ProposalNotApproved']
- },
- /**
- * Lookup468: pallet_sudo::pallet::Error<T>
- **/
- PalletSudoError: {
- _enum: ['RequireSudo']
- },
- /**
- * Lookup470: orml_vesting::module::Error<T>
- **/
- OrmlVestingModuleError: {
- _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
- },
- /**
- * Lookup471: orml_xtokens::module::Error<T>
- **/
- OrmlXtokensModuleError: {
- _enum: ['AssetHasNoReserve', 'NotCrossChainTransfer', 'InvalidDest', 'NotCrossChainTransferableCurrency', 'UnweighableMessage', 'XcmExecutionFailed', 'CannotReanchor', 'InvalidAncestry', 'InvalidAsset', 'DestinationNotInvertible', 'BadVersion', 'DistinctReserveForAssetAndFee', 'ZeroFee', 'ZeroAmount', 'TooManyAssetsBeingSent', 'AssetIndexNonExistent', 'FeeNotEnough', 'NotSupportedMultiLocation', 'MinXcmFeeNotDefined']
- },
- /**
- * Lookup474: orml_tokens::BalanceLock<Balance>
- **/
- OrmlTokensBalanceLock: {
- id: '[u8;8]',
- amount: 'u128'
- },
- /**
- * Lookup476: orml_tokens::AccountData<Balance>
- **/
- OrmlTokensAccountData: {
- free: 'u128',
- reserved: 'u128',
- frozen: 'u128'
- },
- /**
- * Lookup478: orml_tokens::ReserveData<ReserveIdentifier, Balance>
- **/
- OrmlTokensReserveData: {
- id: 'Null',
- amount: 'u128'
- },
- /**
- * Lookup480: orml_tokens::module::Error<T>
- **/
- OrmlTokensModuleError: {
- _enum: ['BalanceTooLow', 'AmountIntoBalanceFailed', 'LiquidityRestrictions', 'MaxLocksExceeded', 'KeepAlive', 'ExistentialDeposit', 'DeadAccount', 'TooManyReserves']
- },
- /**
- * Lookup485: pallet_identity::types::RegistrarInfo<Balance, sp_core::crypto::AccountId32>
- **/
- PalletIdentityRegistrarInfo: {
- account: 'AccountId32',
- fee: 'u128',
- fields: 'PalletIdentityBitFlags'
- },
- /**
- * Lookup487: pallet_identity::pallet::Error<T>
- **/
- PalletIdentityError: {
- _enum: ['TooManySubAccounts', 'NotFound', 'NotNamed', 'EmptyIndex', 'FeeChanged', 'NoIdentity', 'StickyJudgement', 'JudgementGiven', 'InvalidJudgement', 'InvalidIndex', 'InvalidTarget', 'TooManyFields', 'TooManyRegistrars', 'AlreadyClaimed', 'NotSub', 'NotOwned', 'JudgementForDifferentIdentity', 'JudgementPaymentFailed']
- },
- /**
- * Lookup488: pallet_preimage::RequestStatus<sp_core::crypto::AccountId32, Balance>
- **/
- PalletPreimageRequestStatus: {
- _enum: {
- Unrequested: {
- deposit: '(AccountId32,u128)',
- len: 'u32',
- },
- Requested: {
- deposit: 'Option<(AccountId32,u128)>',
- count: 'u32',
- len: 'Option<u32>'
- }
- }
- },
- /**
- * Lookup493: pallet_preimage::pallet::Error<T>
- **/
- PalletPreimageError: {
- _enum: ['TooBig', 'AlreadyNoted', 'NotAuthorized', 'NotNoted', 'Requested', 'NotRequested']
- },
- /**
- * Lookup499: pallet_democracy::types::ReferendumInfo<BlockNumber, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance>
- **/
- PalletDemocracyReferendumInfo: {
- _enum: {
- Ongoing: 'PalletDemocracyReferendumStatus',
- Finished: {
- approved: 'bool',
- end: 'u32'
- }
- }
- },
- /**
- * Lookup500: pallet_democracy::types::ReferendumStatus<BlockNumber, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance>
- **/
- PalletDemocracyReferendumStatus: {
- end: 'u32',
- proposal: 'FrameSupportPreimagesBounded',
- threshold: 'PalletDemocracyVoteThreshold',
- delay: 'u32',
- tally: 'PalletDemocracyTally'
- },
- /**
- * Lookup501: pallet_democracy::types::Tally<Balance>
- **/
- PalletDemocracyTally: {
- ayes: 'u128',
- nays: 'u128',
- turnout: 'u128'
- },
- /**
- * Lookup502: pallet_democracy::vote::Voting<Balance, sp_core::crypto::AccountId32, BlockNumber, MaxVotes>
- **/
- PalletDemocracyVoteVoting: {
- _enum: {
- Direct: {
- votes: 'Vec<(u32,PalletDemocracyVoteAccountVote)>',
- delegations: 'PalletDemocracyDelegations',
- prior: 'PalletDemocracyVotePriorLock',
- },
- Delegating: {
- balance: 'u128',
- target: 'AccountId32',
- conviction: 'PalletDemocracyConviction',
- delegations: 'PalletDemocracyDelegations',
- prior: 'PalletDemocracyVotePriorLock'
- }
- }
- },
- /**
- * Lookup506: pallet_democracy::types::Delegations<Balance>
- **/
- PalletDemocracyDelegations: {
- votes: 'u128',
- capital: 'u128'
- },
- /**
- * Lookup507: pallet_democracy::vote::PriorLock<BlockNumber, Balance>
- **/
- PalletDemocracyVotePriorLock: '(u32,u128)',
- /**
- * Lookup510: pallet_democracy::pallet::Error<T>
- **/
- PalletDemocracyError: {
- _enum: ['ValueLow', 'ProposalMissing', 'AlreadyCanceled', 'DuplicateProposal', 'ProposalBlacklisted', 'NotSimpleMajority', 'InvalidHash', 'NoProposal', 'AlreadyVetoed', 'ReferendumInvalid', 'NoneWaiting', 'NotVoter', 'NoPermission', 'AlreadyDelegating', 'InsufficientFunds', 'NotDelegating', 'VotesExist', 'InstantNotAllowed', 'Nonsense', 'WrongUpperBound', 'MaxVotesReached', 'TooMany', 'VotingPeriodLow', 'PreimageNotExist']
- },
- /**
- * Lookup512: pallet_collective::Votes<sp_core::crypto::AccountId32, BlockNumber>
- **/
- PalletCollectiveVotes: {
- index: 'u32',
- threshold: 'u32',
- ayes: 'Vec<AccountId32>',
- nays: 'Vec<AccountId32>',
- end: 'u32'
- },
- /**
- * Lookup513: pallet_collective::pallet::Error<T, I>
- **/
- PalletCollectiveError: {
- _enum: ['NotMember', 'DuplicateProposal', 'ProposalMissing', 'WrongIndex', 'DuplicateVote', 'AlreadyInitialized', 'TooEarly', 'TooManyProposals', 'WrongProposalWeight', 'WrongProposalLength', 'PrimeAccountNotMember']
- },
- /**
- * Lookup517: pallet_membership::pallet::Error<T, I>
- **/
- PalletMembershipError: {
- _enum: ['AlreadyMember', 'NotMember', 'TooManyMembers']
- },
- /**
- * Lookup520: pallet_ranked_collective::MemberRecord
- **/
- PalletRankedCollectiveMemberRecord: {
- rank: 'u16'
- },
- /**
- * Lookup525: pallet_ranked_collective::pallet::Error<T, I>
- **/
- PalletRankedCollectiveError: {
- _enum: ['AlreadyMember', 'NotMember', 'NotPolling', 'Ongoing', 'NoneRemaining', 'Corruption', 'RankTooLow', 'InvalidWitness', 'NoPermission']
- },
- /**
- * Lookup526: pallet_referenda::types::ReferendumInfo<TrackId, opal_runtime::OriginCaller, Moment, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance, pallet_ranked_collective::Tally<T, I, M>, sp_core::crypto::AccountId32, ScheduleAddress>
- **/
- PalletReferendaReferendumInfo: {
- _enum: {
- Ongoing: 'PalletReferendaReferendumStatus',
- Approved: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
- Rejected: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
- Cancelled: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
- TimedOut: '(u32,Option<PalletReferendaDeposit>,Option<PalletReferendaDeposit>)',
- Killed: 'u32'
- }
- },
- /**
- * Lookup527: pallet_referenda::types::ReferendumStatus<TrackId, opal_runtime::OriginCaller, Moment, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, Balance, pallet_ranked_collective::Tally<T, I, M>, sp_core::crypto::AccountId32, ScheduleAddress>
- **/
- PalletReferendaReferendumStatus: {
- track: 'u16',
- origin: 'OpalRuntimeOriginCaller',
- proposal: 'FrameSupportPreimagesBounded',
- enactment: 'FrameSupportScheduleDispatchTime',
- submitted: 'u32',
- submissionDeposit: 'PalletReferendaDeposit',
- decisionDeposit: 'Option<PalletReferendaDeposit>',
- deciding: 'Option<PalletReferendaDecidingStatus>',
- tally: 'PalletRankedCollectiveTally',
- inQueue: 'bool',
- alarm: 'Option<(u32,(u32,u32))>'
- },
- /**
- * Lookup528: pallet_referenda::types::Deposit<sp_core::crypto::AccountId32, Balance>
- **/
- PalletReferendaDeposit: {
- who: 'AccountId32',
- amount: 'u128'
- },
- /**
- * Lookup531: pallet_referenda::types::DecidingStatus<BlockNumber>
- **/
- PalletReferendaDecidingStatus: {
- since: 'u32',
- confirming: 'Option<u32>'
- },
- /**
- * Lookup537: pallet_referenda::types::TrackInfo<Balance, Moment>
- **/
- PalletReferendaTrackInfo: {
- name: 'Text',
- maxDeciding: 'u32',
- decisionDeposit: 'u128',
- preparePeriod: 'u32',
- decisionPeriod: 'u32',
- confirmPeriod: 'u32',
- minEnactmentPeriod: 'u32',
- minApproval: 'PalletReferendaCurve',
- minSupport: 'PalletReferendaCurve'
- },
- /**
- * Lookup538: pallet_referenda::types::Curve
- **/
- PalletReferendaCurve: {
- _enum: {
- LinearDecreasing: {
- length: 'Perbill',
- floor: 'Perbill',
- ceil: 'Perbill',
- },
- SteppedDecreasing: {
- begin: 'Perbill',
- end: 'Perbill',
- step: 'Perbill',
- period: 'Perbill',
- },
- Reciprocal: {
- factor: 'i64',
- xOffset: 'i64',
- yOffset: 'i64'
- }
- }
- },
- /**
- * Lookup541: pallet_referenda::pallet::Error<T, I>
- **/
- PalletReferendaError: {
- _enum: ['NotOngoing', 'HasDeposit', 'BadTrack', 'Full', 'QueueEmpty', 'BadReferendum', 'NothingToDo', 'NoTrack', 'Unfinished', 'NoPermission', 'NoDeposit', 'BadStatus', 'PreimageNotExist']
- },
- /**
- * Lookup544: pallet_scheduler::Scheduled<Name, frame_support::traits::preimages::Bounded<opal_runtime::RuntimeCall>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
- **/
- PalletSchedulerScheduled: {
- maybeId: 'Option<[u8;32]>',
- priority: 'u8',
- call: 'FrameSupportPreimagesBounded',
- maybePeriodic: 'Option<(u32,u32)>',
- origin: 'OpalRuntimeOriginCaller'
- },
- /**
- * Lookup546: pallet_scheduler::pallet::Error<T>
- **/
- PalletSchedulerError: {
- _enum: ['FailedToSchedule', 'NotFound', 'TargetBlockNumberInPast', 'RescheduleNoChange', 'Named']
- },
- /**
- * Lookup548: cumulus_pallet_xcmp_queue::InboundChannelDetails
- **/
- CumulusPalletXcmpQueueInboundChannelDetails: {
- sender: 'u32',
- state: 'CumulusPalletXcmpQueueInboundState',
- messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat)>'
- },
- /**
- * Lookup549: cumulus_pallet_xcmp_queue::InboundState
- **/
- CumulusPalletXcmpQueueInboundState: {
- _enum: ['Ok', 'Suspended']
- },
- /**
- * Lookup552: polkadot_parachain_primitives::primitives::XcmpMessageFormat
- **/
- PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat: {
- _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
- },
- /**
- * Lookup555: cumulus_pallet_xcmp_queue::OutboundChannelDetails
- **/
- CumulusPalletXcmpQueueOutboundChannelDetails: {
- recipient: 'u32',
- state: 'CumulusPalletXcmpQueueOutboundState',
- signalsExist: 'bool',
- firstIndex: 'u16',
- lastIndex: 'u16'
- },
- /**
- * Lookup556: cumulus_pallet_xcmp_queue::OutboundState
- **/
- CumulusPalletXcmpQueueOutboundState: {
- _enum: ['Ok', 'Suspended']
- },
- /**
- * Lookup558: cumulus_pallet_xcmp_queue::QueueConfigData
- **/
- CumulusPalletXcmpQueueQueueConfigData: {
- suspendThreshold: 'u32',
- dropThreshold: 'u32',
- resumeThreshold: 'u32',
- thresholdWeight: 'SpWeightsWeightV2Weight',
- weightRestrictDecay: 'SpWeightsWeightV2Weight',
- xcmpMaxIndividualWeight: 'SpWeightsWeightV2Weight'
- },
- /**
- * Lookup560: cumulus_pallet_xcmp_queue::pallet::Error<T>
- **/
- CumulusPalletXcmpQueueError: {
- _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
- },
- /**
- * Lookup561: pallet_xcm::pallet::QueryStatus<BlockNumber>
- **/
- PalletXcmQueryStatus: {
- _enum: {
- Pending: {
- responder: 'StagingXcmVersionedMultiLocation',
- maybeMatchQuerier: 'Option<StagingXcmVersionedMultiLocation>',
- maybeNotify: 'Option<(u8,u8)>',
- timeout: 'u32',
- },
- VersionNotifier: {
- origin: 'StagingXcmVersionedMultiLocation',
- isActive: 'bool',
- },
- Ready: {
- response: 'StagingXcmVersionedResponse',
- at: 'u32'
- }
- }
- },
- /**
- * Lookup565: staging_xcm::VersionedResponse
- **/
- StagingXcmVersionedResponse: {
- _enum: {
- __Unused0: 'Null',
- __Unused1: 'Null',
- V2: 'StagingXcmV2Response',
- V3: 'StagingXcmV3Response'
- }
- },
- /**
- * Lookup571: pallet_xcm::pallet::VersionMigrationStage
- **/
- PalletXcmVersionMigrationStage: {
- _enum: {
- MigrateSupportedVersion: 'Null',
- MigrateVersionNotifiers: 'Null',
- NotifyCurrentTargets: 'Option<Bytes>',
- MigrateAndNotifyOldTargets: 'Null'
- }
- },
- /**
- * Lookup574: staging_xcm::VersionedAssetId
- **/
- StagingXcmVersionedAssetId: {
- _enum: {
- __Unused0: 'Null',
- __Unused1: 'Null',
- __Unused2: 'Null',
- V3: 'StagingXcmV3MultiassetAssetId'
- }
- },
- /**
- * Lookup575: pallet_xcm::pallet::RemoteLockedFungibleRecord<ConsumerIdentifier, MaxConsumers>
- **/
- PalletXcmRemoteLockedFungibleRecord: {
- amount: 'u128',
- owner: 'StagingXcmVersionedMultiLocation',
- locker: 'StagingXcmVersionedMultiLocation',
- consumers: 'Vec<(Null,u128)>'
- },
- /**
- * Lookup582: pallet_xcm::pallet::Error<T>
- **/
- PalletXcmError: {
- _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed', 'InvalidAsset', 'LowBalance', 'TooManyLocks', 'AccountNotSovereign', 'FeesNotMet', 'LockNotFound', 'InUse']
- },
- /**
- * Lookup583: cumulus_pallet_xcm::pallet::Error<T>
- **/
- CumulusPalletXcmError: 'Null',
- /**
- * Lookup584: cumulus_pallet_dmp_queue::ConfigData
- **/
- CumulusPalletDmpQueueConfigData: {
- maxIndividual: 'SpWeightsWeightV2Weight'
- },
- /**
- * Lookup585: cumulus_pallet_dmp_queue::PageIndexData
- **/
- CumulusPalletDmpQueuePageIndexData: {
- beginUsed: 'u32',
- endUsed: 'u32',
- overweightCount: 'u64'
- },
- /**
- * Lookup588: cumulus_pallet_dmp_queue::pallet::Error<T>
- **/
- CumulusPalletDmpQueueError: {
- _enum: ['Unknown', 'OverLimit']
- },
- /**
- * Lookup592: pallet_unique::pallet::Error<T>
- **/
- PalletUniqueError: {
- _enum: ['CollectionDecimalPointLimitExceeded', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']
- },
- /**
- * Lookup593: pallet_configuration::pallet::Error<T>
- **/
- PalletConfigurationError: {
- _enum: ['InconsistentConfiguration']
- },
- /**
- * Lookup594: up_data_structs::Collection<sp_core::crypto::AccountId32>
- **/
- UpDataStructsCollection: {
- owner: 'AccountId32',
- mode: 'UpDataStructsCollectionMode',
- name: 'Vec<u16>',
- description: 'Vec<u16>',
- tokenPrefix: 'Bytes',
- sponsorship: 'UpDataStructsSponsorshipStateAccountId32',
- limits: 'UpDataStructsCollectionLimits',
- permissions: 'UpDataStructsCollectionPermissions',
- flags: '[u8;1]'
- },
- /**
- * Lookup595: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
- **/
- UpDataStructsSponsorshipStateAccountId32: {
- _enum: {
- Disabled: 'Null',
- Unconfirmed: 'AccountId32',
- Confirmed: 'AccountId32'
- }
- },
- /**
- * Lookup596: up_data_structs::Properties
- **/
- UpDataStructsProperties: {
- map: 'UpDataStructsPropertiesMapBoundedVec',
- consumedSpace: 'u32',
- reserved: 'u32'
- },
- /**
- * Lookup597: up_data_structs::PropertiesMap<bounded_collections::bounded_vec::BoundedVec<T, S>>
- **/
- UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
- /**
- * Lookup602: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
- **/
- UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
- /**
- * Lookup609: up_data_structs::CollectionStats
- **/
- UpDataStructsCollectionStats: {
- created: 'u32',
- destroyed: 'u32',
- alive: 'u32'
- },
- /**
- * Lookup610: up_data_structs::TokenChild
- **/
- UpDataStructsTokenChild: {
- token: 'u32',
- collection: 'u32'
- },
- /**
- * Lookup611: PhantomType::up_data_structs<T>
- **/
- PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,UpPovEstimateRpcPovInfo);0]',
- /**
- * Lookup613: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsTokenData: {
- properties: 'Vec<UpDataStructsProperty>',
- owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>',
- pieces: 'u128'
- },
- /**
- * Lookup614: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
- **/
- UpDataStructsRpcCollection: {
- owner: 'AccountId32',
- mode: 'UpDataStructsCollectionMode',
- name: 'Vec<u16>',
- description: 'Vec<u16>',
- tokenPrefix: 'Bytes',
- sponsorship: 'UpDataStructsSponsorshipStateAccountId32',
- limits: 'UpDataStructsCollectionLimits',
- permissions: 'UpDataStructsCollectionPermissions',
- tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
- properties: 'Vec<UpDataStructsProperty>',
- readOnly: 'bool',
- flags: 'UpDataStructsRpcCollectionFlags'
- },
- /**
- * Lookup615: up_data_structs::RpcCollectionFlags
- **/
- UpDataStructsRpcCollectionFlags: {
- foreign: 'bool',
- erc721metadata: 'bool'
- },
- /**
- * Lookup616: up_pov_estimate_rpc::PovInfo
- **/
- UpPovEstimateRpcPovInfo: {
- proofSize: 'u64',
- compactProofSize: 'u64',
- compressedProofSize: 'u64',
- results: 'Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>',
- keyValues: 'Vec<UpPovEstimateRpcTrieKeyValue>'
- },
- /**
- * Lookup619: sp_runtime::transaction_validity::TransactionValidityError
- **/
- SpRuntimeTransactionValidityTransactionValidityError: {
- _enum: {
- Invalid: 'SpRuntimeTransactionValidityInvalidTransaction',
- Unknown: 'SpRuntimeTransactionValidityUnknownTransaction'
- }
- },
- /**
- * Lookup620: sp_runtime::transaction_validity::InvalidTransaction
- **/
- SpRuntimeTransactionValidityInvalidTransaction: {
- _enum: {
- Call: 'Null',
- Payment: 'Null',
- Future: 'Null',
- Stale: 'Null',
- BadProof: 'Null',
- AncientBirthBlock: 'Null',
- ExhaustsResources: 'Null',
- Custom: 'u8',
- BadMandatory: 'Null',
- MandatoryValidation: 'Null',
- BadSigner: 'Null'
- }
- },
- /**
- * Lookup621: sp_runtime::transaction_validity::UnknownTransaction
- **/
- SpRuntimeTransactionValidityUnknownTransaction: {
- _enum: {
- CannotLookup: 'Null',
- NoUnsignedValidator: 'Null',
- Custom: 'u8'
- }
- },
- /**
- * Lookup623: up_pov_estimate_rpc::TrieKeyValue
- **/
- UpPovEstimateRpcTrieKeyValue: {
- key: 'Bytes',
- value: 'Bytes'
- },
- /**
- * Lookup625: pallet_common::pallet::Error<T>
- **/
- PalletCommonError: {
- _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsNotEthMirror', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal', 'ConfirmSponsorshipFail', 'UserIsNotCollectionAdmin', 'FungibleItemsHaveNoId']
- },
- /**
- * Lookup627: pallet_fungible::pallet::Error<T>
- **/
- PalletFungibleError: {
- _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingAllowanceForAllNotAllowed', 'FungibleTokensAreAlwaysValid']
- },
- /**
- * Lookup632: pallet_refungible::pallet::Error<T>
- **/
- PalletRefungibleError: {
- _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
- },
- /**
- * Lookup633: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- PalletNonfungibleItemData: {
- owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
- },
- /**
- * Lookup635: up_data_structs::PropertyScope
- **/
- UpDataStructsPropertyScope: {
- _enum: ['None', 'Rmrk']
- },
- /**
- * Lookup638: pallet_nonfungible::pallet::Error<T>
- **/
- PalletNonfungibleError: {
- _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
- },
- /**
- * Lookup639: pallet_structure::pallet::Error<T>
- **/
- PalletStructureError: {
- _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound', 'CantNestTokenUnderCollection']
- },
- /**
- * Lookup644: pallet_app_promotion::pallet::Error<T>
- **/
- PalletAppPromotionError: {
- _enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'InsufficientStakedBalance', 'InconsistencyState']
- },
- /**
- * Lookup645: pallet_foreign_assets::module::Error<T>
- **/
- PalletForeignAssetsModuleError: {
- _enum: ['BadLocation', 'MultiLocationExisted', 'AssetIdNotExists', 'AssetIdExisted']
- },
- /**
- * Lookup646: pallet_evm::CodeMetadata
- **/
- PalletEvmCodeMetadata: {
- _alias: {
- size_: 'size',
- hash_: 'hash'
- },
- size_: 'u64',
- hash_: 'H256'
- },
- /**
- * Lookup648: pallet_evm::pallet::Error<T>
- **/
- PalletEvmError: {
- _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce', 'GasLimitTooLow', 'GasLimitTooHigh', 'Undefined', 'Reentrancy', 'TransactionMustComeFromEOA']
- },
- /**
- * Lookup651: fp_rpc::TransactionStatus
- **/
- FpRpcTransactionStatus: {
- transactionHash: 'H256',
- transactionIndex: 'u32',
- from: 'H160',
- to: 'Option<H160>',
- contractAddress: 'Option<H160>',
- logs: 'Vec<EthereumLog>',
- logsBloom: 'EthbloomBloom'
- },
- /**
- * Lookup653: ethbloom::Bloom
- **/
- EthbloomBloom: '[u8;256]',
- /**
- * Lookup655: ethereum::receipt::ReceiptV3
- **/
- EthereumReceiptReceiptV3: {
- _enum: {
- Legacy: 'EthereumReceiptEip658ReceiptData',
- EIP2930: 'EthereumReceiptEip658ReceiptData',
- EIP1559: 'EthereumReceiptEip658ReceiptData'
- }
- },
- /**
- * Lookup656: ethereum::receipt::EIP658ReceiptData
- **/
- EthereumReceiptEip658ReceiptData: {
- statusCode: 'u8',
- usedGas: 'U256',
- logsBloom: 'EthbloomBloom',
- logs: 'Vec<EthereumLog>'
- },
- /**
- * Lookup657: ethereum::block::Block<ethereum::transaction::TransactionV2>
- **/
- EthereumBlock: {
- header: 'EthereumHeader',
- transactions: 'Vec<EthereumTransactionTransactionV2>',
- ommers: 'Vec<EthereumHeader>'
- },
- /**
- * Lookup658: ethereum::header::Header
- **/
- EthereumHeader: {
- parentHash: 'H256',
- ommersHash: 'H256',
- beneficiary: 'H160',
- stateRoot: 'H256',
- transactionsRoot: 'H256',
- receiptsRoot: 'H256',
- logsBloom: 'EthbloomBloom',
- difficulty: 'U256',
- number: 'U256',
- gasLimit: 'U256',
- gasUsed: 'U256',
- timestamp: 'u64',
- extraData: 'Bytes',
- mixHash: 'H256',
- nonce: 'EthereumTypesHashH64'
- },
- /**
- * Lookup659: ethereum_types::hash::H64
- **/
- EthereumTypesHashH64: '[u8;8]',
- /**
- * Lookup664: pallet_ethereum::pallet::Error<T>
- **/
- PalletEthereumError: {
- _enum: ['InvalidSignature', 'PreLogExists']
- },
- /**
- * Lookup665: pallet_evm_coder_substrate::pallet::Error<T>
- **/
- PalletEvmCoderSubstrateError: {
- _enum: ['OutOfGas', 'OutOfFund']
- },
- /**
- * Lookup666: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
- **/
- UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: {
- _enum: {
- Disabled: 'Null',
- Unconfirmed: 'PalletEvmAccountBasicCrossAccountIdRepr',
- Confirmed: 'PalletEvmAccountBasicCrossAccountIdRepr'
- }
- },
- /**
- * Lookup667: pallet_evm_contract_helpers::SponsoringModeT
- **/
- PalletEvmContractHelpersSponsoringModeT: {
- _enum: ['Disabled', 'Allowlisted', 'Generous']
- },
- /**
- * Lookup673: pallet_evm_contract_helpers::pallet::Error<T>
- **/
- PalletEvmContractHelpersError: {
- _enum: ['NoPermission', 'NoPendingSponsor', 'TooManyMethodsHaveSponsoredLimit']
- },
- /**
- * Lookup674: pallet_evm_migration::pallet::Error<T>
- **/
- PalletEvmMigrationError: {
- _enum: ['AccountNotEmpty', 'AccountIsNotMigrating', 'BadEvent']
- },
- /**
- * Lookup675: pallet_maintenance::pallet::Error<T>
- **/
- PalletMaintenanceError: 'Null',
- /**
- * Lookup676: pallet_utility::pallet::Error<T>
- **/
- PalletUtilityError: {
- _enum: ['TooManyCalls']
- },
- /**
- * Lookup677: pallet_test_utils::pallet::Error<T>
- **/
- PalletTestUtilsError: {
- _enum: ['TestPalletDisabled', 'TriggerRollback']
- },
- /**
- * Lookup679: sp_runtime::MultiSignature
- **/
- SpRuntimeMultiSignature: {
- _enum: {
- Ed25519: 'SpCoreEd25519Signature',
- Sr25519: 'SpCoreSr25519Signature',
- Ecdsa: 'SpCoreEcdsaSignature'
- }
- },
- /**
- * Lookup680: sp_core::ed25519::Signature
- **/
- SpCoreEd25519Signature: '[u8;64]',
- /**
- * Lookup682: sp_core::sr25519::Signature
- **/
- SpCoreSr25519Signature: '[u8;64]',
- /**
- * Lookup683: sp_core::ecdsa::Signature
- **/
- SpCoreEcdsaSignature: '[u8;65]',
- /**
- * Lookup686: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
- **/
- FrameSystemExtensionsCheckSpecVersion: 'Null',
- /**
- * Lookup687: frame_system::extensions::check_tx_version::CheckTxVersion<T>
- **/
- FrameSystemExtensionsCheckTxVersion: 'Null',
- /**
- * Lookup688: frame_system::extensions::check_genesis::CheckGenesis<T>
- **/
- FrameSystemExtensionsCheckGenesis: 'Null',
- /**
- * Lookup691: frame_system::extensions::check_nonce::CheckNonce<T>
- **/
- FrameSystemExtensionsCheckNonce: 'Compact<u32>',
- /**
- * Lookup692: frame_system::extensions::check_weight::CheckWeight<T>
- **/
- FrameSystemExtensionsCheckWeight: 'Null',
- /**
- * Lookup693: opal_runtime::runtime_common::maintenance::CheckMaintenance
- **/
- OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: 'Null',
- /**
- * Lookup694: opal_runtime::runtime_common::identity::DisableIdentityCalls
- **/
- OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls: 'Null',
- /**
- * Lookup695: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
- **/
- PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
- /**
- * Lookup696: opal_runtime::Runtime
- **/
- OpalRuntimeRuntime: 'Null',
- /**
- * Lookup697: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
- **/
- PalletEthereumFakeTransactionFinalizer: 'Null'
-};
js-packages/types/src/povinfo/definitions.tsdiffbeforeafterboth--- a/js-packages/types/src/povinfo/definitions.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-type RpcParam = {
- name: string;
- type: string;
- isOptional?: true;
-};
-
-const atParam = {name: 'at', type: 'Hash', isOptional: true};
-
-const fun = (description: string, params: RpcParam[], type: string) => ({
- description,
- params: [...params, atParam],
- type,
-});
-
-export default {
- types: {},
- rpc: {
- estimateExtrinsicPoV: fun(
- 'Estimate PoV size of encoded signed extrinsics',
- [{name: 'encodedXt', type: 'Vec<Bytes>'}],
- 'UpPovEstimateRpcPovInfo',
- ),
- },
-};
js-packages/types/src/povinfo/index.tsdiffbeforeafterboth--- a/js-packages/types/src/povinfo/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './types.js';
js-packages/types/src/povinfo/types.tsdiffbeforeafterboth--- a/js-packages/types/src/povinfo/types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export type PHANTOM_POVINFO = 'povinfo';
js-packages/types/src/registry.tsdiffbeforeafterboth--- a/js-packages/types/src/registry.ts
+++ /dev/null
@@ -1,370 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/types/types/registry';
-
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemCodeUpgradeAuthorization, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity, CumulusPalletParachainSystemUnincludedSegmentAncestor, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate, CumulusPalletParachainSystemUnincludedSegmentSegmentTracker, CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportPreimagesBounded, FrameSupportScheduleDispatchTime, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OpalRuntimeRuntimeCommonSessionKeys, OpalRuntimeRuntimeHoldReason, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesIdAmount, PalletBalancesReasons, PalletBalancesReserveData, PalletCollatorSelectionCall, PalletCollatorSelectionError, PalletCollatorSelectionEvent, PalletCollatorSelectionHoldReason, PalletCollectiveCall, PalletCollectiveError, PalletCollectiveEvent, PalletCollectiveRawOrigin, PalletCollectiveVotes, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletConfigurationEvent, PalletDemocracyCall, PalletDemocracyConviction, PalletDemocracyDelegations, PalletDemocracyError, PalletDemocracyEvent, PalletDemocracyMetadataOwner, PalletDemocracyReferendumInfo, PalletDemocracyReferendumStatus, PalletDemocracyTally, PalletDemocracyVoteAccountVote, PalletDemocracyVotePriorLock, PalletDemocracyVoteThreshold, PalletDemocracyVoteVoting, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCodeMetadata, PalletEvmCoderSubstrateError, PalletEvmContractHelpersCall, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetId, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletGovOriginsOrigin, PalletIdentityBitFlags, PalletIdentityCall, PalletIdentityError, PalletIdentityEvent, PalletIdentityIdentityField, PalletIdentityIdentityInfo, PalletIdentityJudgement, PalletIdentityRegistrarInfo, PalletIdentityRegistration, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletMembershipCall, PalletMembershipError, PalletMembershipEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletPreimageCall, PalletPreimageError, PalletPreimageEvent, PalletPreimageRequestStatus, PalletRankedCollectiveCall, PalletRankedCollectiveError, PalletRankedCollectiveEvent, PalletRankedCollectiveMemberRecord, PalletRankedCollectiveTally, PalletRankedCollectiveVoteRecord, PalletReferendaCall, PalletReferendaCurve, PalletReferendaDecidingStatus, PalletReferendaDeposit, PalletReferendaError, PalletReferendaEvent, PalletReferendaReferendumInfo, PalletReferendaReferendumStatus, PalletReferendaTrackInfo, PalletRefungibleError, PalletSchedulerCall, PalletSchedulerError, PalletSchedulerEvent, PalletSchedulerScheduled, PalletSessionCall, PalletSessionError, PalletSessionEvent, PalletStateTrieMigrationCall, PalletStateTrieMigrationError, PalletStateTrieMigrationEvent, PalletStateTrieMigrationMigrationCompute, PalletStateTrieMigrationMigrationLimits, PalletStateTrieMigrationMigrationTask, PalletStateTrieMigrationProgress, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUtilityCall, PalletUtilityError, PalletUtilityEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PalletXcmQueryStatus, PalletXcmRemoteLockedFungibleRecord, PalletXcmVersionMigrationStage, ParachainInfoCall, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat, PolkadotPrimitivesV5AbridgedHostConfiguration, PolkadotPrimitivesV5AbridgedHrmpChannel, PolkadotPrimitivesV5PersistedValidationData, PolkadotPrimitivesV5UpgradeGoAhead, PolkadotPrimitivesV5UpgradeRestriction, PolkadotPrimitivesVstagingAsyncBackingParams, SpArithmeticArithmeticError, SpConsensusAuraSr25519AppSr25519Public, SpCoreCryptoKeyTypeId, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Public, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, StagingXcmDoubleEncoded, StagingXcmV2BodyId, StagingXcmV2BodyPart, StagingXcmV2Instruction, StagingXcmV2Junction, StagingXcmV2MultiAsset, StagingXcmV2MultiLocation, StagingXcmV2MultiassetAssetId, StagingXcmV2MultiassetAssetInstance, StagingXcmV2MultiassetFungibility, StagingXcmV2MultiassetMultiAssetFilter, StagingXcmV2MultiassetMultiAssets, StagingXcmV2MultiassetWildFungibility, StagingXcmV2MultiassetWildMultiAsset, StagingXcmV2MultilocationJunctions, StagingXcmV2NetworkId, StagingXcmV2OriginKind, StagingXcmV2Response, StagingXcmV2TraitsError, StagingXcmV2WeightLimit, StagingXcmV2Xcm, StagingXcmV3Instruction, StagingXcmV3Junction, StagingXcmV3JunctionBodyId, StagingXcmV3JunctionBodyPart, StagingXcmV3JunctionNetworkId, StagingXcmV3Junctions, StagingXcmV3MaybeErrorCode, StagingXcmV3MultiAsset, StagingXcmV3MultiLocation, StagingXcmV3MultiassetAssetId, StagingXcmV3MultiassetAssetInstance, StagingXcmV3MultiassetFungibility, StagingXcmV3MultiassetMultiAssetFilter, StagingXcmV3MultiassetMultiAssets, StagingXcmV3MultiassetWildFungibility, StagingXcmV3MultiassetWildMultiAsset, StagingXcmV3PalletInfo, StagingXcmV3QueryResponseInfo, StagingXcmV3Response, StagingXcmV3TraitsError, StagingXcmV3TraitsOutcome, StagingXcmV3WeightLimit, StagingXcmV3Xcm, StagingXcmVersionedAssetId, StagingXcmVersionedMultiAsset, StagingXcmVersionedMultiAssets, StagingXcmVersionedMultiLocation, StagingXcmVersionedResponse, StagingXcmVersionedXcm, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission,
- UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue } from '@polkadot/types/lookup';
-
-declare module '@polkadot/types/types/registry' {
- interface InterfaceTypes {
- CumulusPalletDmpQueueCall: CumulusPalletDmpQueueCall;
- CumulusPalletDmpQueueConfigData: CumulusPalletDmpQueueConfigData;
- CumulusPalletDmpQueueError: CumulusPalletDmpQueueError;
- CumulusPalletDmpQueueEvent: CumulusPalletDmpQueueEvent;
- CumulusPalletDmpQueuePageIndexData: CumulusPalletDmpQueuePageIndexData;
- CumulusPalletParachainSystemCall: CumulusPalletParachainSystemCall;
- CumulusPalletParachainSystemCodeUpgradeAuthorization: CumulusPalletParachainSystemCodeUpgradeAuthorization;
- CumulusPalletParachainSystemError: CumulusPalletParachainSystemError;
- CumulusPalletParachainSystemEvent: CumulusPalletParachainSystemEvent;
- CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot;
- CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity: CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity;
- CumulusPalletParachainSystemUnincludedSegmentAncestor: CumulusPalletParachainSystemUnincludedSegmentAncestor;
- CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate: CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate;
- CumulusPalletParachainSystemUnincludedSegmentSegmentTracker: CumulusPalletParachainSystemUnincludedSegmentSegmentTracker;
- CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
- CumulusPalletXcmCall: CumulusPalletXcmCall;
- CumulusPalletXcmError: CumulusPalletXcmError;
- CumulusPalletXcmEvent: CumulusPalletXcmEvent;
- CumulusPalletXcmOrigin: CumulusPalletXcmOrigin;
- CumulusPalletXcmpQueueCall: CumulusPalletXcmpQueueCall;
- CumulusPalletXcmpQueueError: CumulusPalletXcmpQueueError;
- CumulusPalletXcmpQueueEvent: CumulusPalletXcmpQueueEvent;
- CumulusPalletXcmpQueueInboundChannelDetails: CumulusPalletXcmpQueueInboundChannelDetails;
- CumulusPalletXcmpQueueInboundState: CumulusPalletXcmpQueueInboundState;
- CumulusPalletXcmpQueueOutboundChannelDetails: CumulusPalletXcmpQueueOutboundChannelDetails;
- CumulusPalletXcmpQueueOutboundState: CumulusPalletXcmpQueueOutboundState;
- CumulusPalletXcmpQueueQueueConfigData: CumulusPalletXcmpQueueQueueConfigData;
- CumulusPrimitivesParachainInherentParachainInherentData: CumulusPrimitivesParachainInherentParachainInherentData;
- EthbloomBloom: EthbloomBloom;
- EthereumBlock: EthereumBlock;
- EthereumHeader: EthereumHeader;
- EthereumLog: EthereumLog;
- EthereumReceiptEip658ReceiptData: EthereumReceiptEip658ReceiptData;
- EthereumReceiptReceiptV3: EthereumReceiptReceiptV3;
- EthereumTransactionAccessListItem: EthereumTransactionAccessListItem;
- EthereumTransactionEip1559Transaction: EthereumTransactionEip1559Transaction;
- EthereumTransactionEip2930Transaction: EthereumTransactionEip2930Transaction;
- EthereumTransactionLegacyTransaction: EthereumTransactionLegacyTransaction;
- EthereumTransactionTransactionAction: EthereumTransactionTransactionAction;
- EthereumTransactionTransactionSignature: EthereumTransactionTransactionSignature;
- EthereumTransactionTransactionV2: EthereumTransactionTransactionV2;
- EthereumTypesHashH64: EthereumTypesHashH64;
- EvmCoreErrorExitError: EvmCoreErrorExitError;
- EvmCoreErrorExitFatal: EvmCoreErrorExitFatal;
- EvmCoreErrorExitReason: EvmCoreErrorExitReason;
- EvmCoreErrorExitRevert: EvmCoreErrorExitRevert;
- EvmCoreErrorExitSucceed: EvmCoreErrorExitSucceed;
- FpRpcTransactionStatus: FpRpcTransactionStatus;
- FrameSupportDispatchDispatchClass: FrameSupportDispatchDispatchClass;
- FrameSupportDispatchDispatchInfo: FrameSupportDispatchDispatchInfo;
- FrameSupportDispatchPays: FrameSupportDispatchPays;
- FrameSupportDispatchPerDispatchClassU32: FrameSupportDispatchPerDispatchClassU32;
- FrameSupportDispatchPerDispatchClassWeight: FrameSupportDispatchPerDispatchClassWeight;
- FrameSupportDispatchPerDispatchClassWeightsPerClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
- FrameSupportDispatchRawOrigin: FrameSupportDispatchRawOrigin;
- FrameSupportPalletId: FrameSupportPalletId;
- FrameSupportPreimagesBounded: FrameSupportPreimagesBounded;
- FrameSupportScheduleDispatchTime: FrameSupportScheduleDispatchTime;
- FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus;
- FrameSystemAccountInfo: FrameSystemAccountInfo;
- FrameSystemCall: FrameSystemCall;
- FrameSystemError: FrameSystemError;
- FrameSystemEvent: FrameSystemEvent;
- FrameSystemEventRecord: FrameSystemEventRecord;
- FrameSystemExtensionsCheckGenesis: FrameSystemExtensionsCheckGenesis;
- FrameSystemExtensionsCheckNonce: FrameSystemExtensionsCheckNonce;
- FrameSystemExtensionsCheckSpecVersion: FrameSystemExtensionsCheckSpecVersion;
- FrameSystemExtensionsCheckTxVersion: FrameSystemExtensionsCheckTxVersion;
- FrameSystemExtensionsCheckWeight: FrameSystemExtensionsCheckWeight;
- FrameSystemLastRuntimeUpgradeInfo: FrameSystemLastRuntimeUpgradeInfo;
- FrameSystemLimitsBlockLength: FrameSystemLimitsBlockLength;
- FrameSystemLimitsBlockWeights: FrameSystemLimitsBlockWeights;
- FrameSystemLimitsWeightsPerClass: FrameSystemLimitsWeightsPerClass;
- FrameSystemPhase: FrameSystemPhase;
- OpalRuntimeOriginCaller: OpalRuntimeOriginCaller;
- OpalRuntimeRuntime: OpalRuntimeRuntime;
- OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls: OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls;
- OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance;
- OpalRuntimeRuntimeCommonSessionKeys: OpalRuntimeRuntimeCommonSessionKeys;
- OpalRuntimeRuntimeHoldReason: OpalRuntimeRuntimeHoldReason;
- OrmlTokensAccountData: OrmlTokensAccountData;
- OrmlTokensBalanceLock: OrmlTokensBalanceLock;
- OrmlTokensModuleCall: OrmlTokensModuleCall;
- OrmlTokensModuleError: OrmlTokensModuleError;
- OrmlTokensModuleEvent: OrmlTokensModuleEvent;
- OrmlTokensReserveData: OrmlTokensReserveData;
- OrmlVestingModuleCall: OrmlVestingModuleCall;
- OrmlVestingModuleError: OrmlVestingModuleError;
- OrmlVestingModuleEvent: OrmlVestingModuleEvent;
- OrmlVestingVestingSchedule: OrmlVestingVestingSchedule;
- OrmlXtokensModuleCall: OrmlXtokensModuleCall;
- OrmlXtokensModuleError: OrmlXtokensModuleError;
- OrmlXtokensModuleEvent: OrmlXtokensModuleEvent;
- PalletAppPromotionCall: PalletAppPromotionCall;
- PalletAppPromotionError: PalletAppPromotionError;
- PalletAppPromotionEvent: PalletAppPromotionEvent;
- PalletBalancesAccountData: PalletBalancesAccountData;
- PalletBalancesBalanceLock: PalletBalancesBalanceLock;
- PalletBalancesCall: PalletBalancesCall;
- PalletBalancesError: PalletBalancesError;
- PalletBalancesEvent: PalletBalancesEvent;
- PalletBalancesIdAmount: PalletBalancesIdAmount;
- PalletBalancesReasons: PalletBalancesReasons;
- PalletBalancesReserveData: PalletBalancesReserveData;
- PalletCollatorSelectionCall: PalletCollatorSelectionCall;
- PalletCollatorSelectionError: PalletCollatorSelectionError;
- PalletCollatorSelectionEvent: PalletCollatorSelectionEvent;
- PalletCollatorSelectionHoldReason: PalletCollatorSelectionHoldReason;
- PalletCollectiveCall: PalletCollectiveCall;
- PalletCollectiveError: PalletCollectiveError;
- PalletCollectiveEvent: PalletCollectiveEvent;
- PalletCollectiveRawOrigin: PalletCollectiveRawOrigin;
- PalletCollectiveVotes: PalletCollectiveVotes;
- PalletCommonError: PalletCommonError;
- PalletCommonEvent: PalletCommonEvent;
- PalletConfigurationAppPromotionConfiguration: PalletConfigurationAppPromotionConfiguration;
- PalletConfigurationCall: PalletConfigurationCall;
- PalletConfigurationError: PalletConfigurationError;
- PalletConfigurationEvent: PalletConfigurationEvent;
- PalletDemocracyCall: PalletDemocracyCall;
- PalletDemocracyConviction: PalletDemocracyConviction;
- PalletDemocracyDelegations: PalletDemocracyDelegations;
- PalletDemocracyError: PalletDemocracyError;
- PalletDemocracyEvent: PalletDemocracyEvent;
- PalletDemocracyMetadataOwner: PalletDemocracyMetadataOwner;
- PalletDemocracyReferendumInfo: PalletDemocracyReferendumInfo;
- PalletDemocracyReferendumStatus: PalletDemocracyReferendumStatus;
- PalletDemocracyTally: PalletDemocracyTally;
- PalletDemocracyVoteAccountVote: PalletDemocracyVoteAccountVote;
- PalletDemocracyVotePriorLock: PalletDemocracyVotePriorLock;
- PalletDemocracyVoteThreshold: PalletDemocracyVoteThreshold;
- PalletDemocracyVoteVoting: PalletDemocracyVoteVoting;
- PalletEthereumCall: PalletEthereumCall;
- PalletEthereumError: PalletEthereumError;
- PalletEthereumEvent: PalletEthereumEvent;
- PalletEthereumFakeTransactionFinalizer: PalletEthereumFakeTransactionFinalizer;
- PalletEthereumRawOrigin: PalletEthereumRawOrigin;
- PalletEvmAccountBasicCrossAccountIdRepr: PalletEvmAccountBasicCrossAccountIdRepr;
- PalletEvmCall: PalletEvmCall;
- PalletEvmCodeMetadata: PalletEvmCodeMetadata;
- PalletEvmCoderSubstrateError: PalletEvmCoderSubstrateError;
- PalletEvmContractHelpersCall: PalletEvmContractHelpersCall;
- PalletEvmContractHelpersError: PalletEvmContractHelpersError;
- PalletEvmContractHelpersEvent: PalletEvmContractHelpersEvent;
- PalletEvmContractHelpersSponsoringModeT: PalletEvmContractHelpersSponsoringModeT;
- PalletEvmError: PalletEvmError;
- PalletEvmEvent: PalletEvmEvent;
- PalletEvmMigrationCall: PalletEvmMigrationCall;
- PalletEvmMigrationError: PalletEvmMigrationError;
- PalletEvmMigrationEvent: PalletEvmMigrationEvent;
- PalletForeignAssetsAssetId: PalletForeignAssetsAssetId;
- PalletForeignAssetsModuleAssetMetadata: PalletForeignAssetsModuleAssetMetadata;
- PalletForeignAssetsModuleCall: PalletForeignAssetsModuleCall;
- PalletForeignAssetsModuleError: PalletForeignAssetsModuleError;
- PalletForeignAssetsModuleEvent: PalletForeignAssetsModuleEvent;
- PalletForeignAssetsNativeCurrency: PalletForeignAssetsNativeCurrency;
- PalletFungibleError: PalletFungibleError;
- PalletGovOriginsOrigin: PalletGovOriginsOrigin;
- PalletIdentityBitFlags: PalletIdentityBitFlags;
- PalletIdentityCall: PalletIdentityCall;
- PalletIdentityError: PalletIdentityError;
- PalletIdentityEvent: PalletIdentityEvent;
- PalletIdentityIdentityField: PalletIdentityIdentityField;
- PalletIdentityIdentityInfo: PalletIdentityIdentityInfo;
- PalletIdentityJudgement: PalletIdentityJudgement;
- PalletIdentityRegistrarInfo: PalletIdentityRegistrarInfo;
- PalletIdentityRegistration: PalletIdentityRegistration;
- PalletInflationCall: PalletInflationCall;
- PalletMaintenanceCall: PalletMaintenanceCall;
- PalletMaintenanceError: PalletMaintenanceError;
- PalletMaintenanceEvent: PalletMaintenanceEvent;
- PalletMembershipCall: PalletMembershipCall;
- PalletMembershipError: PalletMembershipError;
- PalletMembershipEvent: PalletMembershipEvent;
- PalletNonfungibleError: PalletNonfungibleError;
- PalletNonfungibleItemData: PalletNonfungibleItemData;
- PalletPreimageCall: PalletPreimageCall;
- PalletPreimageError: PalletPreimageError;
- PalletPreimageEvent: PalletPreimageEvent;
- PalletPreimageRequestStatus: PalletPreimageRequestStatus;
- PalletRankedCollectiveCall: PalletRankedCollectiveCall;
- PalletRankedCollectiveError: PalletRankedCollectiveError;
- PalletRankedCollectiveEvent: PalletRankedCollectiveEvent;
- PalletRankedCollectiveMemberRecord: PalletRankedCollectiveMemberRecord;
- PalletRankedCollectiveTally: PalletRankedCollectiveTally;
- PalletRankedCollectiveVoteRecord: PalletRankedCollectiveVoteRecord;
- PalletReferendaCall: PalletReferendaCall;
- PalletReferendaCurve: PalletReferendaCurve;
- PalletReferendaDecidingStatus: PalletReferendaDecidingStatus;
- PalletReferendaDeposit: PalletReferendaDeposit;
- PalletReferendaError: PalletReferendaError;
- PalletReferendaEvent: PalletReferendaEvent;
- PalletReferendaReferendumInfo: PalletReferendaReferendumInfo;
- PalletReferendaReferendumStatus: PalletReferendaReferendumStatus;
- PalletReferendaTrackInfo: PalletReferendaTrackInfo;
- PalletRefungibleError: PalletRefungibleError;
- PalletSchedulerCall: PalletSchedulerCall;
- PalletSchedulerError: PalletSchedulerError;
- PalletSchedulerEvent: PalletSchedulerEvent;
- PalletSchedulerScheduled: PalletSchedulerScheduled;
- PalletSessionCall: PalletSessionCall;
- PalletSessionError: PalletSessionError;
- PalletSessionEvent: PalletSessionEvent;
- PalletStateTrieMigrationCall: PalletStateTrieMigrationCall;
- PalletStateTrieMigrationError: PalletStateTrieMigrationError;
- PalletStateTrieMigrationEvent: PalletStateTrieMigrationEvent;
- PalletStateTrieMigrationMigrationCompute: PalletStateTrieMigrationMigrationCompute;
- PalletStateTrieMigrationMigrationLimits: PalletStateTrieMigrationMigrationLimits;
- PalletStateTrieMigrationMigrationTask: PalletStateTrieMigrationMigrationTask;
- PalletStateTrieMigrationProgress: PalletStateTrieMigrationProgress;
- PalletStructureCall: PalletStructureCall;
- PalletStructureError: PalletStructureError;
- PalletStructureEvent: PalletStructureEvent;
- PalletSudoCall: PalletSudoCall;
- PalletSudoError: PalletSudoError;
- PalletSudoEvent: PalletSudoEvent;
- PalletTemplateTransactionPaymentChargeTransactionPayment: PalletTemplateTransactionPaymentChargeTransactionPayment;
- PalletTestUtilsCall: PalletTestUtilsCall;
- PalletTestUtilsError: PalletTestUtilsError;
- PalletTestUtilsEvent: PalletTestUtilsEvent;
- PalletTimestampCall: PalletTimestampCall;
- PalletTransactionPaymentEvent: PalletTransactionPaymentEvent;
- PalletTransactionPaymentReleases: PalletTransactionPaymentReleases;
- PalletTreasuryCall: PalletTreasuryCall;
- PalletTreasuryError: PalletTreasuryError;
- PalletTreasuryEvent: PalletTreasuryEvent;
- PalletTreasuryProposal: PalletTreasuryProposal;
- PalletUniqueCall: PalletUniqueCall;
- PalletUniqueError: PalletUniqueError;
- PalletUtilityCall: PalletUtilityCall;
- PalletUtilityError: PalletUtilityError;
- PalletUtilityEvent: PalletUtilityEvent;
- PalletXcmCall: PalletXcmCall;
- PalletXcmError: PalletXcmError;
- PalletXcmEvent: PalletXcmEvent;
- PalletXcmOrigin: PalletXcmOrigin;
- PalletXcmQueryStatus: PalletXcmQueryStatus;
- PalletXcmRemoteLockedFungibleRecord: PalletXcmRemoteLockedFungibleRecord;
- PalletXcmVersionMigrationStage: PalletXcmVersionMigrationStage;
- ParachainInfoCall: ParachainInfoCall;
- PhantomTypeUpDataStructs: PhantomTypeUpDataStructs;
- PolkadotCorePrimitivesInboundDownwardMessage: PolkadotCorePrimitivesInboundDownwardMessage;
- PolkadotCorePrimitivesInboundHrmpMessage: PolkadotCorePrimitivesInboundHrmpMessage;
- PolkadotCorePrimitivesOutboundHrmpMessage: PolkadotCorePrimitivesOutboundHrmpMessage;
- PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat: PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat;
- PolkadotPrimitivesV5AbridgedHostConfiguration: PolkadotPrimitivesV5AbridgedHostConfiguration;
- PolkadotPrimitivesV5AbridgedHrmpChannel: PolkadotPrimitivesV5AbridgedHrmpChannel;
- PolkadotPrimitivesV5PersistedValidationData: PolkadotPrimitivesV5PersistedValidationData;
- PolkadotPrimitivesV5UpgradeGoAhead: PolkadotPrimitivesV5UpgradeGoAhead;
- PolkadotPrimitivesV5UpgradeRestriction: PolkadotPrimitivesV5UpgradeRestriction;
- PolkadotPrimitivesVstagingAsyncBackingParams: PolkadotPrimitivesVstagingAsyncBackingParams;
- SpArithmeticArithmeticError: SpArithmeticArithmeticError;
- SpConsensusAuraSr25519AppSr25519Public: SpConsensusAuraSr25519AppSr25519Public;
- SpCoreCryptoKeyTypeId: SpCoreCryptoKeyTypeId;
- SpCoreEcdsaSignature: SpCoreEcdsaSignature;
- SpCoreEd25519Signature: SpCoreEd25519Signature;
- SpCoreSr25519Public: SpCoreSr25519Public;
- SpCoreSr25519Signature: SpCoreSr25519Signature;
- SpCoreVoid: SpCoreVoid;
- SpRuntimeDigest: SpRuntimeDigest;
- SpRuntimeDigestDigestItem: SpRuntimeDigestDigestItem;
- SpRuntimeDispatchError: SpRuntimeDispatchError;
- SpRuntimeModuleError: SpRuntimeModuleError;
- SpRuntimeMultiSignature: SpRuntimeMultiSignature;
- SpRuntimeTokenError: SpRuntimeTokenError;
- SpRuntimeTransactionValidityInvalidTransaction: SpRuntimeTransactionValidityInvalidTransaction;
- SpRuntimeTransactionValidityTransactionValidityError: SpRuntimeTransactionValidityTransactionValidityError;
- SpRuntimeTransactionValidityUnknownTransaction: SpRuntimeTransactionValidityUnknownTransaction;
- SpRuntimeTransactionalError: SpRuntimeTransactionalError;
- SpTrieStorageProof: SpTrieStorageProof;
- SpVersionRuntimeVersion: SpVersionRuntimeVersion;
- SpWeightsRuntimeDbWeight: SpWeightsRuntimeDbWeight;
- SpWeightsWeightV2Weight: SpWeightsWeightV2Weight;
- StagingXcmDoubleEncoded: StagingXcmDoubleEncoded;
- StagingXcmV2BodyId: StagingXcmV2BodyId;
- StagingXcmV2BodyPart: StagingXcmV2BodyPart;
- StagingXcmV2Instruction: StagingXcmV2Instruction;
- StagingXcmV2Junction: StagingXcmV2Junction;
- StagingXcmV2MultiAsset: StagingXcmV2MultiAsset;
- StagingXcmV2MultiLocation: StagingXcmV2MultiLocation;
- StagingXcmV2MultiassetAssetId: StagingXcmV2MultiassetAssetId;
- StagingXcmV2MultiassetAssetInstance: StagingXcmV2MultiassetAssetInstance;
- StagingXcmV2MultiassetFungibility: StagingXcmV2MultiassetFungibility;
- StagingXcmV2MultiassetMultiAssetFilter: StagingXcmV2MultiassetMultiAssetFilter;
- StagingXcmV2MultiassetMultiAssets: StagingXcmV2MultiassetMultiAssets;
- StagingXcmV2MultiassetWildFungibility: StagingXcmV2MultiassetWildFungibility;
- StagingXcmV2MultiassetWildMultiAsset: StagingXcmV2MultiassetWildMultiAsset;
- StagingXcmV2MultilocationJunctions: StagingXcmV2MultilocationJunctions;
- StagingXcmV2NetworkId: StagingXcmV2NetworkId;
- StagingXcmV2OriginKind: StagingXcmV2OriginKind;
- StagingXcmV2Response: StagingXcmV2Response;
- StagingXcmV2TraitsError: StagingXcmV2TraitsError;
- StagingXcmV2WeightLimit: StagingXcmV2WeightLimit;
- StagingXcmV2Xcm: StagingXcmV2Xcm;
- StagingXcmV3Instruction: StagingXcmV3Instruction;
- StagingXcmV3Junction: StagingXcmV3Junction;
- StagingXcmV3JunctionBodyId: StagingXcmV3JunctionBodyId;
- StagingXcmV3JunctionBodyPart: StagingXcmV3JunctionBodyPart;
- StagingXcmV3JunctionNetworkId: StagingXcmV3JunctionNetworkId;
- StagingXcmV3Junctions: StagingXcmV3Junctions;
- StagingXcmV3MaybeErrorCode: StagingXcmV3MaybeErrorCode;
- StagingXcmV3MultiAsset: StagingXcmV3MultiAsset;
- StagingXcmV3MultiLocation: StagingXcmV3MultiLocation;
- StagingXcmV3MultiassetAssetId: StagingXcmV3MultiassetAssetId;
- StagingXcmV3MultiassetAssetInstance: StagingXcmV3MultiassetAssetInstance;
- StagingXcmV3MultiassetFungibility: StagingXcmV3MultiassetFungibility;
- StagingXcmV3MultiassetMultiAssetFilter: StagingXcmV3MultiassetMultiAssetFilter;
- StagingXcmV3MultiassetMultiAssets: StagingXcmV3MultiassetMultiAssets;
- StagingXcmV3MultiassetWildFungibility: StagingXcmV3MultiassetWildFungibility;
- StagingXcmV3MultiassetWildMultiAsset: StagingXcmV3MultiassetWildMultiAsset;
- StagingXcmV3PalletInfo: StagingXcmV3PalletInfo;
- StagingXcmV3QueryResponseInfo: StagingXcmV3QueryResponseInfo;
- StagingXcmV3Response: StagingXcmV3Response;
- StagingXcmV3TraitsError: StagingXcmV3TraitsError;
- StagingXcmV3TraitsOutcome: StagingXcmV3TraitsOutcome;
- StagingXcmV3WeightLimit: StagingXcmV3WeightLimit;
- StagingXcmV3Xcm: StagingXcmV3Xcm;
- StagingXcmVersionedAssetId: StagingXcmVersionedAssetId;
- StagingXcmVersionedMultiAsset: StagingXcmVersionedMultiAsset;
- StagingXcmVersionedMultiAssets: StagingXcmVersionedMultiAssets;
- StagingXcmVersionedMultiLocation: StagingXcmVersionedMultiLocation;
- StagingXcmVersionedResponse: StagingXcmVersionedResponse;
- StagingXcmVersionedXcm: StagingXcmVersionedXcm;
- UpDataStructsAccessMode: UpDataStructsAccessMode;
- UpDataStructsCollection: UpDataStructsCollection;
- UpDataStructsCollectionLimits: UpDataStructsCollectionLimits;
- UpDataStructsCollectionMode: UpDataStructsCollectionMode;
- UpDataStructsCollectionPermissions: UpDataStructsCollectionPermissions;
- UpDataStructsCollectionStats: UpDataStructsCollectionStats;
- UpDataStructsCreateCollectionData: UpDataStructsCreateCollectionData;
- UpDataStructsCreateFungibleData: UpDataStructsCreateFungibleData;
- UpDataStructsCreateItemData: UpDataStructsCreateItemData;
- UpDataStructsCreateItemExData: UpDataStructsCreateItemExData;
- UpDataStructsCreateNftData: UpDataStructsCreateNftData;
- UpDataStructsCreateNftExData: UpDataStructsCreateNftExData;
- UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData;
- UpDataStructsCreateRefungibleExMultipleOwners: UpDataStructsCreateRefungibleExMultipleOwners;
- UpDataStructsCreateRefungibleExSingleOwner: UpDataStructsCreateRefungibleExSingleOwner;
- UpDataStructsNestingPermissions: UpDataStructsNestingPermissions;
- UpDataStructsOwnerRestrictedSet: UpDataStructsOwnerRestrictedSet;
- UpDataStructsProperties: UpDataStructsProperties;
- UpDataStructsPropertiesMapBoundedVec: UpDataStructsPropertiesMapBoundedVec;
- UpDataStructsPropertiesMapPropertyPermission: UpDataStructsPropertiesMapPropertyPermission;
- UpDataStructsProperty: UpDataStructsProperty;
- UpDataStructsPropertyKeyPermission: UpDataStructsPropertyKeyPermission;
- UpDataStructsPropertyPermission: UpDataStructsPropertyPermission;
- UpDataStructsPropertyScope: UpDataStructsPropertyScope;
- UpDataStructsRpcCollection: UpDataStructsRpcCollection;
- UpDataStructsRpcCollectionFlags: UpDataStructsRpcCollectionFlags;
- UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
- UpDataStructsSponsorshipStateAccountId32: UpDataStructsSponsorshipStateAccountId32;
- UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: UpDataStructsSponsorshipStateBasicCrossAccountIdRepr;
- UpDataStructsTokenChild: UpDataStructsTokenChild;
- UpDataStructsTokenData: UpDataStructsTokenData;
- UpPovEstimateRpcPovInfo: UpPovEstimateRpcPovInfo;
- UpPovEstimateRpcTrieKeyValue: UpPovEstimateRpcTrieKeyValue;
- } // InterfaceTypes
-} // declare module
js-packages/types/src/types-lookup.tsdiffbeforeafterboth--- a/js-packages/types/src/types-lookup.ts
+++ /dev/null
@@ -1,5540 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-// import type lookup before we augment - in some environments
-// this is required to allow for ambient/previous definitions
-import '@polkadot/types/lookup';
-
-import type { Data } from '@polkadot/types';
-import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Set, Struct, Text, U256, U8aFixed, Vec, bool, i64, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
-import type { ITuple } from '@polkadot/types-codec/types';
-import type { Vote } from '@polkadot/types/interfaces/elections';
-import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
-import type { Event } from '@polkadot/types/interfaces/system';
-
-declare module '@polkadot/types/lookup' {
- /** @name FrameSystemAccountInfo (3) */
- interface FrameSystemAccountInfo extends Struct {
- readonly nonce: u32;
- readonly consumers: u32;
- readonly providers: u32;
- readonly sufficients: u32;
- readonly data: PalletBalancesAccountData;
- }
-
- /** @name PalletBalancesAccountData (5) */
- interface PalletBalancesAccountData extends Struct {
- readonly free: u128;
- readonly reserved: u128;
- readonly frozen: u128;
- readonly flags: u128;
- }
-
- /** @name FrameSupportDispatchPerDispatchClassWeight (8) */
- interface FrameSupportDispatchPerDispatchClassWeight extends Struct {
- readonly normal: SpWeightsWeightV2Weight;
- readonly operational: SpWeightsWeightV2Weight;
- readonly mandatory: SpWeightsWeightV2Weight;
- }
-
- /** @name SpWeightsWeightV2Weight (9) */
- interface SpWeightsWeightV2Weight extends Struct {
- readonly refTime: Compact<u64>;
- readonly proofSize: Compact<u64>;
- }
-
- /** @name SpRuntimeDigest (14) */
- interface SpRuntimeDigest extends Struct {
- readonly logs: Vec<SpRuntimeDigestDigestItem>;
- }
-
- /** @name SpRuntimeDigestDigestItem (16) */
- interface SpRuntimeDigestDigestItem extends Enum {
- readonly isOther: boolean;
- readonly asOther: Bytes;
- readonly isConsensus: boolean;
- readonly asConsensus: ITuple<[U8aFixed, Bytes]>;
- readonly isSeal: boolean;
- readonly asSeal: ITuple<[U8aFixed, Bytes]>;
- readonly isPreRuntime: boolean;
- readonly asPreRuntime: ITuple<[U8aFixed, Bytes]>;
- readonly isRuntimeEnvironmentUpdated: boolean;
- readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated';
- }
-
- /** @name FrameSystemEventRecord (19) */
- interface FrameSystemEventRecord extends Struct {
- readonly phase: FrameSystemPhase;
- readonly event: Event;
- readonly topics: Vec<H256>;
- }
-
- /** @name FrameSystemEvent (21) */
- interface FrameSystemEvent extends Enum {
- readonly isExtrinsicSuccess: boolean;
- readonly asExtrinsicSuccess: {
- readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
- } & Struct;
- readonly isExtrinsicFailed: boolean;
- readonly asExtrinsicFailed: {
- readonly dispatchError: SpRuntimeDispatchError;
- readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
- } & Struct;
- readonly isCodeUpdated: boolean;
- readonly isNewAccount: boolean;
- readonly asNewAccount: {
- readonly account: AccountId32;
- } & Struct;
- readonly isKilledAccount: boolean;
- readonly asKilledAccount: {
- readonly account: AccountId32;
- } & Struct;
- readonly isRemarked: boolean;
- readonly asRemarked: {
- readonly sender: AccountId32;
- readonly hash_: H256;
- } & Struct;
- readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked';
- }
-
- /** @name FrameSupportDispatchDispatchInfo (22) */
- interface FrameSupportDispatchDispatchInfo extends Struct {
- readonly weight: SpWeightsWeightV2Weight;
- readonly class: FrameSupportDispatchDispatchClass;
- readonly paysFee: FrameSupportDispatchPays;
- }
-
- /** @name FrameSupportDispatchDispatchClass (23) */
- interface FrameSupportDispatchDispatchClass extends Enum {
- readonly isNormal: boolean;
- readonly isOperational: boolean;
- readonly isMandatory: boolean;
- readonly type: 'Normal' | 'Operational' | 'Mandatory';
- }
-
- /** @name FrameSupportDispatchPays (24) */
- interface FrameSupportDispatchPays extends Enum {
- readonly isYes: boolean;
- readonly isNo: boolean;
- readonly type: 'Yes' | 'No';
- }
-
- /** @name SpRuntimeDispatchError (25) */
- interface SpRuntimeDispatchError extends Enum {
- readonly isOther: boolean;
- readonly isCannotLookup: boolean;
- readonly isBadOrigin: boolean;
- readonly isModule: boolean;
- readonly asModule: SpRuntimeModuleError;
- readonly isConsumerRemaining: boolean;
- readonly isNoProviders: boolean;
- readonly isTooManyConsumers: boolean;
- readonly isToken: boolean;
- readonly asToken: SpRuntimeTokenError;
- readonly isArithmetic: boolean;
- readonly asArithmetic: SpArithmeticArithmeticError;
- readonly isTransactional: boolean;
- readonly asTransactional: SpRuntimeTransactionalError;
- readonly isExhausted: boolean;
- readonly isCorruption: boolean;
- readonly isUnavailable: boolean;
- readonly isRootNotAllowed: boolean;
- readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional' | 'Exhausted' | 'Corruption' | 'Unavailable' | 'RootNotAllowed';
- }
-
- /** @name SpRuntimeModuleError (26) */
- interface SpRuntimeModuleError extends Struct {
- readonly index: u8;
- readonly error: U8aFixed;
- }
-
- /** @name SpRuntimeTokenError (27) */
- interface SpRuntimeTokenError extends Enum {
- readonly isFundsUnavailable: boolean;
- readonly isOnlyProvider: boolean;
- readonly isBelowMinimum: boolean;
- readonly isCannotCreate: boolean;
- readonly isUnknownAsset: boolean;
- readonly isFrozen: boolean;
- readonly isUnsupported: boolean;
- readonly isCannotCreateHold: boolean;
- readonly isNotExpendable: boolean;
- readonly isBlocked: boolean;
- readonly type: 'FundsUnavailable' | 'OnlyProvider' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported' | 'CannotCreateHold' | 'NotExpendable' | 'Blocked';
- }
-
- /** @name SpArithmeticArithmeticError (28) */
- interface SpArithmeticArithmeticError extends Enum {
- readonly isUnderflow: boolean;
- readonly isOverflow: boolean;
- readonly isDivisionByZero: boolean;
- readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero';
- }
-
- /** @name SpRuntimeTransactionalError (29) */
- interface SpRuntimeTransactionalError extends Enum {
- readonly isLimitReached: boolean;
- readonly isNoLayer: boolean;
- readonly type: 'LimitReached' | 'NoLayer';
- }
-
- /** @name PalletStateTrieMigrationEvent (30) */
- interface PalletStateTrieMigrationEvent extends Enum {
- readonly isMigrated: boolean;
- readonly asMigrated: {
- readonly top: u32;
- readonly child: u32;
- readonly compute: PalletStateTrieMigrationMigrationCompute;
- } & Struct;
- readonly isSlashed: boolean;
- readonly asSlashed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isAutoMigrationFinished: boolean;
- readonly isHalted: boolean;
- readonly asHalted: {
- readonly error: PalletStateTrieMigrationError;
- } & Struct;
- readonly type: 'Migrated' | 'Slashed' | 'AutoMigrationFinished' | 'Halted';
- }
-
- /** @name PalletStateTrieMigrationMigrationCompute (31) */
- interface PalletStateTrieMigrationMigrationCompute extends Enum {
- readonly isSigned: boolean;
- readonly isAuto: boolean;
- readonly type: 'Signed' | 'Auto';
- }
-
- /** @name PalletStateTrieMigrationError (32) */
- interface PalletStateTrieMigrationError extends Enum {
- readonly isMaxSignedLimits: boolean;
- readonly isKeyTooLong: boolean;
- readonly isNotEnoughFunds: boolean;
- readonly isBadWitness: boolean;
- readonly isSignedMigrationNotAllowed: boolean;
- readonly isBadChildRoot: boolean;
- readonly type: 'MaxSignedLimits' | 'KeyTooLong' | 'NotEnoughFunds' | 'BadWitness' | 'SignedMigrationNotAllowed' | 'BadChildRoot';
- }
-
- /** @name CumulusPalletParachainSystemEvent (33) */
- interface CumulusPalletParachainSystemEvent extends Enum {
- readonly isValidationFunctionStored: boolean;
- readonly isValidationFunctionApplied: boolean;
- readonly asValidationFunctionApplied: {
- readonly relayChainBlockNum: u32;
- } & Struct;
- readonly isValidationFunctionDiscarded: boolean;
- readonly isUpgradeAuthorized: boolean;
- readonly asUpgradeAuthorized: {
- readonly codeHash: H256;
- } & Struct;
- readonly isDownwardMessagesReceived: boolean;
- readonly asDownwardMessagesReceived: {
- readonly count: u32;
- } & Struct;
- readonly isDownwardMessagesProcessed: boolean;
- readonly asDownwardMessagesProcessed: {
- readonly weightUsed: SpWeightsWeightV2Weight;
- readonly dmqHead: H256;
- } & Struct;
- readonly isUpwardMessageSent: boolean;
- readonly asUpwardMessageSent: {
- readonly messageHash: Option<U8aFixed>;
- } & Struct;
- readonly type: 'ValidationFunctionStored' | 'ValidationFunctionApplied' | 'ValidationFunctionDiscarded' | 'UpgradeAuthorized' | 'DownwardMessagesReceived' | 'DownwardMessagesProcessed' | 'UpwardMessageSent';
- }
-
- /** @name PalletCollatorSelectionEvent (35) */
- interface PalletCollatorSelectionEvent extends Enum {
- readonly isInvulnerableAdded: boolean;
- readonly asInvulnerableAdded: {
- readonly invulnerable: AccountId32;
- } & Struct;
- readonly isInvulnerableRemoved: boolean;
- readonly asInvulnerableRemoved: {
- readonly invulnerable: AccountId32;
- } & Struct;
- readonly isLicenseObtained: boolean;
- readonly asLicenseObtained: {
- readonly accountId: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isLicenseReleased: boolean;
- readonly asLicenseReleased: {
- readonly accountId: AccountId32;
- readonly depositReturned: u128;
- } & Struct;
- readonly isCandidateAdded: boolean;
- readonly asCandidateAdded: {
- readonly accountId: AccountId32;
- } & Struct;
- readonly isCandidateRemoved: boolean;
- readonly asCandidateRemoved: {
- readonly accountId: AccountId32;
- } & Struct;
- readonly type: 'InvulnerableAdded' | 'InvulnerableRemoved' | 'LicenseObtained' | 'LicenseReleased' | 'CandidateAdded' | 'CandidateRemoved';
- }
-
- /** @name PalletSessionEvent (36) */
- interface PalletSessionEvent extends Enum {
- readonly isNewSession: boolean;
- readonly asNewSession: {
- readonly sessionIndex: u32;
- } & Struct;
- readonly type: 'NewSession';
- }
-
- /** @name PalletBalancesEvent (37) */
- interface PalletBalancesEvent extends Enum {
- readonly isEndowed: boolean;
- readonly asEndowed: {
- readonly account: AccountId32;
- readonly freeBalance: u128;
- } & Struct;
- readonly isDustLost: boolean;
- readonly asDustLost: {
- readonly account: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isBalanceSet: boolean;
- readonly asBalanceSet: {
- readonly who: AccountId32;
- readonly free: u128;
- } & Struct;
- readonly isReserved: boolean;
- readonly asReserved: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnreserved: boolean;
- readonly asUnreserved: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isReserveRepatriated: boolean;
- readonly asReserveRepatriated: {
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- readonly destinationStatus: FrameSupportTokensMiscBalanceStatus;
- } & Struct;
- readonly isDeposit: boolean;
- readonly asDeposit: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isWithdraw: boolean;
- readonly asWithdraw: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isSlashed: boolean;
- readonly asSlashed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isMinted: boolean;
- readonly asMinted: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isBurned: boolean;
- readonly asBurned: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isSuspended: boolean;
- readonly asSuspended: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isRestored: boolean;
- readonly asRestored: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUpgraded: boolean;
- readonly asUpgraded: {
- readonly who: AccountId32;
- } & Struct;
- readonly isIssued: boolean;
- readonly asIssued: {
- readonly amount: u128;
- } & Struct;
- readonly isRescinded: boolean;
- readonly asRescinded: {
- readonly amount: u128;
- } & Struct;
- readonly isLocked: boolean;
- readonly asLocked: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnlocked: boolean;
- readonly asUnlocked: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isFrozen: boolean;
- readonly asFrozen: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isThawed: boolean;
- readonly asThawed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'BalanceSet' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'Deposit' | 'Withdraw' | 'Slashed' | 'Minted' | 'Burned' | 'Suspended' | 'Restored' | 'Upgraded' | 'Issued' | 'Rescinded' | 'Locked' | 'Unlocked' | 'Frozen' | 'Thawed';
- }
-
- /** @name FrameSupportTokensMiscBalanceStatus (38) */
- interface FrameSupportTokensMiscBalanceStatus extends Enum {
- readonly isFree: boolean;
- readonly isReserved: boolean;
- readonly type: 'Free' | 'Reserved';
- }
-
- /** @name PalletTransactionPaymentEvent (39) */
- interface PalletTransactionPaymentEvent extends Enum {
- readonly isTransactionFeePaid: boolean;
- readonly asTransactionFeePaid: {
- readonly who: AccountId32;
- readonly actualFee: u128;
- readonly tip: u128;
- } & Struct;
- readonly type: 'TransactionFeePaid';
- }
-
- /** @name PalletTreasuryEvent (40) */
- interface PalletTreasuryEvent extends Enum {
- readonly isProposed: boolean;
- readonly asProposed: {
- readonly proposalIndex: u32;
- } & Struct;
- readonly isSpending: boolean;
- readonly asSpending: {
- readonly budgetRemaining: u128;
- } & Struct;
- readonly isAwarded: boolean;
- readonly asAwarded: {
- readonly proposalIndex: u32;
- readonly award: u128;
- readonly account: AccountId32;
- } & Struct;
- readonly isRejected: boolean;
- readonly asRejected: {
- readonly proposalIndex: u32;
- readonly slashed: u128;
- } & Struct;
- readonly isBurnt: boolean;
- readonly asBurnt: {
- readonly burntFunds: u128;
- } & Struct;
- readonly isRollover: boolean;
- readonly asRollover: {
- readonly rolloverBalance: u128;
- } & Struct;
- readonly isDeposit: boolean;
- readonly asDeposit: {
- readonly value: u128;
- } & Struct;
- readonly isSpendApproved: boolean;
- readonly asSpendApproved: {
- readonly proposalIndex: u32;
- readonly amount: u128;
- readonly beneficiary: AccountId32;
- } & Struct;
- readonly isUpdatedInactive: boolean;
- readonly asUpdatedInactive: {
- readonly reactivated: u128;
- readonly deactivated: u128;
- } & Struct;
- readonly type: 'Proposed' | 'Spending' | 'Awarded' | 'Rejected' | 'Burnt' | 'Rollover' | 'Deposit' | 'SpendApproved' | 'UpdatedInactive';
- }
-
- /** @name PalletSudoEvent (41) */
- interface PalletSudoEvent extends Enum {
- readonly isSudid: boolean;
- readonly asSudid: {
- readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isKeyChanged: boolean;
- readonly asKeyChanged: {
- readonly oldSudoer: Option<AccountId32>;
- } & Struct;
- readonly isSudoAsDone: boolean;
- readonly asSudoAsDone: {
- readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone';
- }
-
- /** @name OrmlVestingModuleEvent (45) */
- interface OrmlVestingModuleEvent extends Enum {
- readonly isVestingScheduleAdded: boolean;
- readonly asVestingScheduleAdded: {
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly vestingSchedule: OrmlVestingVestingSchedule;
- } & Struct;
- readonly isClaimed: boolean;
- readonly asClaimed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isVestingSchedulesUpdated: boolean;
- readonly asVestingSchedulesUpdated: {
- readonly who: AccountId32;
- } & Struct;
- readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated';
- }
-
- /** @name OrmlVestingVestingSchedule (46) */
- interface OrmlVestingVestingSchedule extends Struct {
- readonly start: u32;
- readonly period: u32;
- readonly periodCount: u32;
- readonly perPeriod: Compact<u128>;
- }
-
- /** @name OrmlXtokensModuleEvent (48) */
- interface OrmlXtokensModuleEvent extends Enum {
- readonly isTransferredMultiAssets: boolean;
- readonly asTransferredMultiAssets: {
- readonly sender: AccountId32;
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly fee: StagingXcmV3MultiAsset;
- readonly dest: StagingXcmV3MultiLocation;
- } & Struct;
- readonly type: 'TransferredMultiAssets';
- }
-
- /** @name StagingXcmV3MultiassetMultiAssets (49) */
- interface StagingXcmV3MultiassetMultiAssets extends Vec<StagingXcmV3MultiAsset> {}
-
- /** @name StagingXcmV3MultiAsset (51) */
- interface StagingXcmV3MultiAsset extends Struct {
- readonly id: StagingXcmV3MultiassetAssetId;
- readonly fun: StagingXcmV3MultiassetFungibility;
- }
-
- /** @name StagingXcmV3MultiassetAssetId (52) */
- interface StagingXcmV3MultiassetAssetId extends Enum {
- readonly isConcrete: boolean;
- readonly asConcrete: StagingXcmV3MultiLocation;
- readonly isAbstract: boolean;
- readonly asAbstract: U8aFixed;
- readonly type: 'Concrete' | 'Abstract';
- }
-
- /** @name StagingXcmV3MultiLocation (53) */
- interface StagingXcmV3MultiLocation extends Struct {
- readonly parents: u8;
- readonly interior: StagingXcmV3Junctions;
- }
-
- /** @name StagingXcmV3Junctions (54) */
- interface StagingXcmV3Junctions extends Enum {
- readonly isHere: boolean;
- readonly isX1: boolean;
- readonly asX1: StagingXcmV3Junction;
- readonly isX2: boolean;
- readonly asX2: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX3: boolean;
- readonly asX3: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX4: boolean;
- readonly asX4: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX5: boolean;
- readonly asX5: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX6: boolean;
- readonly asX6: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX7: boolean;
- readonly asX7: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly isX8: boolean;
- readonly asX8: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
- readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
- }
-
- /** @name StagingXcmV3Junction (55) */
- interface StagingXcmV3Junction extends Enum {
- readonly isParachain: boolean;
- readonly asParachain: Compact<u32>;
- readonly isAccountId32: boolean;
- readonly asAccountId32: {
- readonly network: Option<StagingXcmV3JunctionNetworkId>;
- readonly id: U8aFixed;
- } & Struct;
- readonly isAccountIndex64: boolean;
- readonly asAccountIndex64: {
- readonly network: Option<StagingXcmV3JunctionNetworkId>;
- readonly index: Compact<u64>;
- } & Struct;
- readonly isAccountKey20: boolean;
- readonly asAccountKey20: {
- readonly network: Option<StagingXcmV3JunctionNetworkId>;
- readonly key: U8aFixed;
- } & Struct;
- readonly isPalletInstance: boolean;
- readonly asPalletInstance: u8;
- readonly isGeneralIndex: boolean;
- readonly asGeneralIndex: Compact<u128>;
- readonly isGeneralKey: boolean;
- readonly asGeneralKey: {
- readonly length: u8;
- readonly data: U8aFixed;
- } & Struct;
- readonly isOnlyChild: boolean;
- readonly isPlurality: boolean;
- readonly asPlurality: {
- readonly id: StagingXcmV3JunctionBodyId;
- readonly part: StagingXcmV3JunctionBodyPart;
- } & Struct;
- readonly isGlobalConsensus: boolean;
- readonly asGlobalConsensus: StagingXcmV3JunctionNetworkId;
- readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality' | 'GlobalConsensus';
- }
-
- /** @name StagingXcmV3JunctionNetworkId (58) */
- interface StagingXcmV3JunctionNetworkId extends Enum {
- readonly isByGenesis: boolean;
- readonly asByGenesis: U8aFixed;
- readonly isByFork: boolean;
- readonly asByFork: {
- readonly blockNumber: u64;
- readonly blockHash: U8aFixed;
- } & Struct;
- readonly isPolkadot: boolean;
- readonly isKusama: boolean;
- readonly isWestend: boolean;
- readonly isRococo: boolean;
- readonly isWococo: boolean;
- readonly isEthereum: boolean;
- readonly asEthereum: {
- readonly chainId: Compact<u64>;
- } & Struct;
- readonly isBitcoinCore: boolean;
- readonly isBitcoinCash: boolean;
- readonly type: 'ByGenesis' | 'ByFork' | 'Polkadot' | 'Kusama' | 'Westend' | 'Rococo' | 'Wococo' | 'Ethereum' | 'BitcoinCore' | 'BitcoinCash';
- }
-
- /** @name StagingXcmV3JunctionBodyId (60) */
- interface StagingXcmV3JunctionBodyId extends Enum {
- readonly isUnit: boolean;
- readonly isMoniker: boolean;
- readonly asMoniker: U8aFixed;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u32>;
- readonly isExecutive: boolean;
- readonly isTechnical: boolean;
- readonly isLegislative: boolean;
- readonly isJudicial: boolean;
- readonly isDefense: boolean;
- readonly isAdministration: boolean;
- readonly isTreasury: boolean;
- readonly type: 'Unit' | 'Moniker' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
- }
-
- /** @name StagingXcmV3JunctionBodyPart (61) */
- interface StagingXcmV3JunctionBodyPart extends Enum {
- readonly isVoice: boolean;
- readonly isMembers: boolean;
- readonly asMembers: {
- readonly count: Compact<u32>;
- } & Struct;
- readonly isFraction: boolean;
- readonly asFraction: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isAtLeastProportion: boolean;
- readonly asAtLeastProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isMoreThanProportion: boolean;
- readonly asMoreThanProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
- }
-
- /** @name StagingXcmV3MultiassetFungibility (62) */
- interface StagingXcmV3MultiassetFungibility extends Enum {
- readonly isFungible: boolean;
- readonly asFungible: Compact<u128>;
- readonly isNonFungible: boolean;
- readonly asNonFungible: StagingXcmV3MultiassetAssetInstance;
- readonly type: 'Fungible' | 'NonFungible';
- }
-
- /** @name StagingXcmV3MultiassetAssetInstance (63) */
- interface StagingXcmV3MultiassetAssetInstance extends Enum {
- readonly isUndefined: boolean;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u128>;
- readonly isArray4: boolean;
- readonly asArray4: U8aFixed;
- readonly isArray8: boolean;
- readonly asArray8: U8aFixed;
- readonly isArray16: boolean;
- readonly asArray16: U8aFixed;
- readonly isArray32: boolean;
- readonly asArray32: U8aFixed;
- readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32';
- }
-
- /** @name OrmlTokensModuleEvent (66) */
- interface OrmlTokensModuleEvent extends Enum {
- readonly isEndowed: boolean;
- readonly asEndowed: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDustLost: boolean;
- readonly asDustLost: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isReserved: boolean;
- readonly asReserved: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnreserved: boolean;
- readonly asUnreserved: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isReserveRepatriated: boolean;
- readonly asReserveRepatriated: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly from: AccountId32;
- readonly to: AccountId32;
- readonly amount: u128;
- readonly status: FrameSupportTokensMiscBalanceStatus;
- } & Struct;
- readonly isBalanceSet: boolean;
- readonly asBalanceSet: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly free: u128;
- readonly reserved: u128;
- } & Struct;
- readonly isTotalIssuanceSet: boolean;
- readonly asTotalIssuanceSet: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- } & Struct;
- readonly isWithdrawn: boolean;
- readonly asWithdrawn: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isSlashed: boolean;
- readonly asSlashed: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly freeAmount: u128;
- readonly reservedAmount: u128;
- } & Struct;
- readonly isDeposited: boolean;
- readonly asDeposited: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isLockSet: boolean;
- readonly asLockSet: {
- readonly lockId: U8aFixed;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isLockRemoved: boolean;
- readonly asLockRemoved: {
- readonly lockId: U8aFixed;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- } & Struct;
- readonly isLocked: boolean;
- readonly asLocked: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isUnlocked: boolean;
- readonly asUnlocked: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isIssued: boolean;
- readonly asIssued: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- } & Struct;
- readonly isRescinded: boolean;
- readonly asRescinded: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- } & Struct;
- readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'BalanceSet' | 'TotalIssuanceSet' | 'Withdrawn' | 'Slashed' | 'Deposited' | 'LockSet' | 'LockRemoved' | 'Locked' | 'Unlocked' | 'Issued' | 'Rescinded';
- }
-
- /** @name PalletForeignAssetsAssetId (67) */
- interface PalletForeignAssetsAssetId extends Enum {
- readonly isForeignAssetId: boolean;
- readonly asForeignAssetId: u32;
- readonly isNativeAssetId: boolean;
- readonly asNativeAssetId: PalletForeignAssetsNativeCurrency;
- readonly type: 'ForeignAssetId' | 'NativeAssetId';
- }
-
- /** @name PalletForeignAssetsNativeCurrency (68) */
- interface PalletForeignAssetsNativeCurrency extends Enum {
- readonly isHere: boolean;
- readonly isParent: boolean;
- readonly type: 'Here' | 'Parent';
- }
-
- /** @name PalletIdentityEvent (69) */
- interface PalletIdentityEvent extends Enum {
- readonly isIdentitySet: boolean;
- readonly asIdentitySet: {
- readonly who: AccountId32;
- } & Struct;
- readonly isIdentityCleared: boolean;
- readonly asIdentityCleared: {
- readonly who: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isIdentityKilled: boolean;
- readonly asIdentityKilled: {
- readonly who: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isIdentitiesInserted: boolean;
- readonly asIdentitiesInserted: {
- readonly amount: u32;
- } & Struct;
- readonly isIdentitiesRemoved: boolean;
- readonly asIdentitiesRemoved: {
- readonly amount: u32;
- } & Struct;
- readonly isJudgementRequested: boolean;
- readonly asJudgementRequested: {
- readonly who: AccountId32;
- readonly registrarIndex: u32;
- } & Struct;
- readonly isJudgementUnrequested: boolean;
- readonly asJudgementUnrequested: {
- readonly who: AccountId32;
- readonly registrarIndex: u32;
- } & Struct;
- readonly isJudgementGiven: boolean;
- readonly asJudgementGiven: {
- readonly target: AccountId32;
- readonly registrarIndex: u32;
- } & Struct;
- readonly isRegistrarAdded: boolean;
- readonly asRegistrarAdded: {
- readonly registrarIndex: u32;
- } & Struct;
- readonly isSubIdentityAdded: boolean;
- readonly asSubIdentityAdded: {
- readonly sub: AccountId32;
- readonly main: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isSubIdentityRemoved: boolean;
- readonly asSubIdentityRemoved: {
- readonly sub: AccountId32;
- readonly main: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isSubIdentityRevoked: boolean;
- readonly asSubIdentityRevoked: {
- readonly sub: AccountId32;
- readonly main: AccountId32;
- readonly deposit: u128;
- } & Struct;
- readonly isSubIdentitiesInserted: boolean;
- readonly asSubIdentitiesInserted: {
- readonly amount: u32;
- } & Struct;
- readonly type: 'IdentitySet' | 'IdentityCleared' | 'IdentityKilled' | 'IdentitiesInserted' | 'IdentitiesRemoved' | 'JudgementRequested' | 'JudgementUnrequested' | 'JudgementGiven' | 'RegistrarAdded' | 'SubIdentityAdded' | 'SubIdentityRemoved' | 'SubIdentityRevoked' | 'SubIdentitiesInserted';
- }
-
- /** @name PalletPreimageEvent (70) */
- interface PalletPreimageEvent extends Enum {
- readonly isNoted: boolean;
- readonly asNoted: {
- readonly hash_: H256;
- } & Struct;
- readonly isRequested: boolean;
- readonly asRequested: {
- readonly hash_: H256;
- } & Struct;
- readonly isCleared: boolean;
- readonly asCleared: {
- readonly hash_: H256;
- } & Struct;
- readonly type: 'Noted' | 'Requested' | 'Cleared';
- }
-
- /** @name PalletDemocracyEvent (71) */
- interface PalletDemocracyEvent extends Enum {
- readonly isProposed: boolean;
- readonly asProposed: {
- readonly proposalIndex: u32;
- readonly deposit: u128;
- } & Struct;
- readonly isTabled: boolean;
- readonly asTabled: {
- readonly proposalIndex: u32;
- readonly deposit: u128;
- } & Struct;
- readonly isExternalTabled: boolean;
- readonly isStarted: boolean;
- readonly asStarted: {
- readonly refIndex: u32;
- readonly threshold: PalletDemocracyVoteThreshold;
- } & Struct;
- readonly isPassed: boolean;
- readonly asPassed: {
- readonly refIndex: u32;
- } & Struct;
- readonly isNotPassed: boolean;
- readonly asNotPassed: {
- readonly refIndex: u32;
- } & Struct;
- readonly isCancelled: boolean;
- readonly asCancelled: {
- readonly refIndex: u32;
- } & Struct;
- readonly isDelegated: boolean;
- readonly asDelegated: {
- readonly who: AccountId32;
- readonly target: AccountId32;
- } & Struct;
- readonly isUndelegated: boolean;
- readonly asUndelegated: {
- readonly account: AccountId32;
- } & Struct;
- readonly isVetoed: boolean;
- readonly asVetoed: {
- readonly who: AccountId32;
- readonly proposalHash: H256;
- readonly until: u32;
- } & Struct;
- readonly isBlacklisted: boolean;
- readonly asBlacklisted: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isVoted: boolean;
- readonly asVoted: {
- readonly voter: AccountId32;
- readonly refIndex: u32;
- readonly vote: PalletDemocracyVoteAccountVote;
- } & Struct;
- readonly isSeconded: boolean;
- readonly asSeconded: {
- readonly seconder: AccountId32;
- readonly propIndex: u32;
- } & Struct;
- readonly isProposalCanceled: boolean;
- readonly asProposalCanceled: {
- readonly propIndex: u32;
- } & Struct;
- readonly isMetadataSet: boolean;
- readonly asMetadataSet: {
- readonly owner: PalletDemocracyMetadataOwner;
- readonly hash_: H256;
- } & Struct;
- readonly isMetadataCleared: boolean;
- readonly asMetadataCleared: {
- readonly owner: PalletDemocracyMetadataOwner;
- readonly hash_: H256;
- } & Struct;
- readonly isMetadataTransferred: boolean;
- readonly asMetadataTransferred: {
- readonly prevOwner: PalletDemocracyMetadataOwner;
- readonly owner: PalletDemocracyMetadataOwner;
- readonly hash_: H256;
- } & Struct;
- readonly type: 'Proposed' | 'Tabled' | 'ExternalTabled' | 'Started' | 'Passed' | 'NotPassed' | 'Cancelled' | 'Delegated' | 'Undelegated' | 'Vetoed' | 'Blacklisted' | 'Voted' | 'Seconded' | 'ProposalCanceled' | 'MetadataSet' | 'MetadataCleared' | 'MetadataTransferred';
- }
-
- /** @name PalletDemocracyVoteThreshold (72) */
- interface PalletDemocracyVoteThreshold extends Enum {
- readonly isSuperMajorityApprove: boolean;
- readonly isSuperMajorityAgainst: boolean;
- readonly isSimpleMajority: boolean;
- readonly type: 'SuperMajorityApprove' | 'SuperMajorityAgainst' | 'SimpleMajority';
- }
-
- /** @name PalletDemocracyVoteAccountVote (73) */
- interface PalletDemocracyVoteAccountVote extends Enum {
- readonly isStandard: boolean;
- readonly asStandard: {
- readonly vote: Vote;
- readonly balance: u128;
- } & Struct;
- readonly isSplit: boolean;
- readonly asSplit: {
- readonly aye: u128;
- readonly nay: u128;
- } & Struct;
- readonly type: 'Standard' | 'Split';
- }
-
- /** @name PalletDemocracyMetadataOwner (75) */
- interface PalletDemocracyMetadataOwner extends Enum {
- readonly isExternal: boolean;
- readonly isProposal: boolean;
- readonly asProposal: u32;
- readonly isReferendum: boolean;
- readonly asReferendum: u32;
- readonly type: 'External' | 'Proposal' | 'Referendum';
- }
-
- /** @name PalletCollectiveEvent (76) */
- interface PalletCollectiveEvent extends Enum {
- readonly isProposed: boolean;
- readonly asProposed: {
- readonly account: AccountId32;
- readonly proposalIndex: u32;
- readonly proposalHash: H256;
- readonly threshold: u32;
- } & Struct;
- readonly isVoted: boolean;
- readonly asVoted: {
- readonly account: AccountId32;
- readonly proposalHash: H256;
- readonly voted: bool;
- readonly yes: u32;
- readonly no: u32;
- } & Struct;
- readonly isApproved: boolean;
- readonly asApproved: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isDisapproved: boolean;
- readonly asDisapproved: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isExecuted: boolean;
- readonly asExecuted: {
- readonly proposalHash: H256;
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isMemberExecuted: boolean;
- readonly asMemberExecuted: {
- readonly proposalHash: H256;
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isClosed: boolean;
- readonly asClosed: {
- readonly proposalHash: H256;
- readonly yes: u32;
- readonly no: u32;
- } & Struct;
- readonly type: 'Proposed' | 'Voted' | 'Approved' | 'Disapproved' | 'Executed' | 'MemberExecuted' | 'Closed';
- }
-
- /** @name PalletMembershipEvent (79) */
- interface PalletMembershipEvent extends Enum {
- readonly isMemberAdded: boolean;
- readonly isMemberRemoved: boolean;
- readonly isMembersSwapped: boolean;
- readonly isMembersReset: boolean;
- readonly isKeyChanged: boolean;
- readonly isDummy: boolean;
- readonly type: 'MemberAdded' | 'MemberRemoved' | 'MembersSwapped' | 'MembersReset' | 'KeyChanged' | 'Dummy';
- }
-
- /** @name PalletRankedCollectiveEvent (81) */
- interface PalletRankedCollectiveEvent extends Enum {
- readonly isMemberAdded: boolean;
- readonly asMemberAdded: {
- readonly who: AccountId32;
- } & Struct;
- readonly isRankChanged: boolean;
- readonly asRankChanged: {
- readonly who: AccountId32;
- readonly rank: u16;
- } & Struct;
- readonly isMemberRemoved: boolean;
- readonly asMemberRemoved: {
- readonly who: AccountId32;
- readonly rank: u16;
- } & Struct;
- readonly isVoted: boolean;
- readonly asVoted: {
- readonly who: AccountId32;
- readonly poll: u32;
- readonly vote: PalletRankedCollectiveVoteRecord;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly type: 'MemberAdded' | 'RankChanged' | 'MemberRemoved' | 'Voted';
- }
-
- /** @name PalletRankedCollectiveVoteRecord (83) */
- interface PalletRankedCollectiveVoteRecord extends Enum {
- readonly isAye: boolean;
- readonly asAye: u32;
- readonly isNay: boolean;
- readonly asNay: u32;
- readonly type: 'Aye' | 'Nay';
- }
-
- /** @name PalletRankedCollectiveTally (84) */
- interface PalletRankedCollectiveTally extends Struct {
- readonly bareAyes: u32;
- readonly ayes: u32;
- readonly nays: u32;
- }
-
- /** @name PalletReferendaEvent (85) */
- interface PalletReferendaEvent extends Enum {
- readonly isSubmitted: boolean;
- readonly asSubmitted: {
- readonly index: u32;
- readonly track: u16;
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isDecisionDepositPlaced: boolean;
- readonly asDecisionDepositPlaced: {
- readonly index: u32;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDecisionDepositRefunded: boolean;
- readonly asDecisionDepositRefunded: {
- readonly index: u32;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDepositSlashed: boolean;
- readonly asDepositSlashed: {
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isDecisionStarted: boolean;
- readonly asDecisionStarted: {
- readonly index: u32;
- readonly track: u16;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isConfirmStarted: boolean;
- readonly asConfirmStarted: {
- readonly index: u32;
- } & Struct;
- readonly isConfirmAborted: boolean;
- readonly asConfirmAborted: {
- readonly index: u32;
- } & Struct;
- readonly isConfirmed: boolean;
- readonly asConfirmed: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isApproved: boolean;
- readonly asApproved: {
- readonly index: u32;
- } & Struct;
- readonly isRejected: boolean;
- readonly asRejected: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isTimedOut: boolean;
- readonly asTimedOut: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isCancelled: boolean;
- readonly asCancelled: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isKilled: boolean;
- readonly asKilled: {
- readonly index: u32;
- readonly tally: PalletRankedCollectiveTally;
- } & Struct;
- readonly isSubmissionDepositRefunded: boolean;
- readonly asSubmissionDepositRefunded: {
- readonly index: u32;
- readonly who: AccountId32;
- readonly amount: u128;
- } & Struct;
- readonly isMetadataSet: boolean;
- readonly asMetadataSet: {
- readonly index: u32;
- readonly hash_: H256;
- } & Struct;
- readonly isMetadataCleared: boolean;
- readonly asMetadataCleared: {
- readonly index: u32;
- readonly hash_: H256;
- } & Struct;
- readonly type: 'Submitted' | 'DecisionDepositPlaced' | 'DecisionDepositRefunded' | 'DepositSlashed' | 'DecisionStarted' | 'ConfirmStarted' | 'ConfirmAborted' | 'Confirmed' | 'Approved' | 'Rejected' | 'TimedOut' | 'Cancelled' | 'Killed' | 'SubmissionDepositRefunded' | 'MetadataSet' | 'MetadataCleared';
- }
-
- /** @name FrameSupportPreimagesBounded (86) */
- interface FrameSupportPreimagesBounded extends Enum {
- readonly isLegacy: boolean;
- readonly asLegacy: {
- readonly hash_: H256;
- } & Struct;
- readonly isInline: boolean;
- readonly asInline: Bytes;
- readonly isLookup: boolean;
- readonly asLookup: {
- readonly hash_: H256;
- readonly len: u32;
- } & Struct;
- readonly type: 'Legacy' | 'Inline' | 'Lookup';
- }
-
- /** @name FrameSystemCall (88) */
- interface FrameSystemCall extends Enum {
- readonly isRemark: boolean;
- readonly asRemark: {
- readonly remark: Bytes;
- } & Struct;
- readonly isSetHeapPages: boolean;
- readonly asSetHeapPages: {
- readonly pages: u64;
- } & Struct;
- readonly isSetCode: boolean;
- readonly asSetCode: {
- readonly code: Bytes;
- } & Struct;
- readonly isSetCodeWithoutChecks: boolean;
- readonly asSetCodeWithoutChecks: {
- readonly code: Bytes;
- } & Struct;
- readonly isSetStorage: boolean;
- readonly asSetStorage: {
- readonly items: Vec<ITuple<[Bytes, Bytes]>>;
- } & Struct;
- readonly isKillStorage: boolean;
- readonly asKillStorage: {
- readonly keys_: Vec<Bytes>;
- } & Struct;
- readonly isKillPrefix: boolean;
- readonly asKillPrefix: {
- readonly prefix: Bytes;
- readonly subkeys: u32;
- } & Struct;
- readonly isRemarkWithEvent: boolean;
- readonly asRemarkWithEvent: {
- readonly remark: Bytes;
- } & Struct;
- readonly type: 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
- }
-
- /** @name PalletStateTrieMigrationCall (92) */
- interface PalletStateTrieMigrationCall extends Enum {
- readonly isControlAutoMigration: boolean;
- readonly asControlAutoMigration: {
- readonly maybeConfig: Option<PalletStateTrieMigrationMigrationLimits>;
- } & Struct;
- readonly isContinueMigrate: boolean;
- readonly asContinueMigrate: {
- readonly limits: PalletStateTrieMigrationMigrationLimits;
- readonly realSizeUpper: u32;
- readonly witnessTask: PalletStateTrieMigrationMigrationTask;
- } & Struct;
- readonly isMigrateCustomTop: boolean;
- readonly asMigrateCustomTop: {
- readonly keys_: Vec<Bytes>;
- readonly witnessSize: u32;
- } & Struct;
- readonly isMigrateCustomChild: boolean;
- readonly asMigrateCustomChild: {
- readonly root: Bytes;
- readonly childKeys: Vec<Bytes>;
- readonly totalSize: u32;
- } & Struct;
- readonly isSetSignedMaxLimits: boolean;
- readonly asSetSignedMaxLimits: {
- readonly limits: PalletStateTrieMigrationMigrationLimits;
- } & Struct;
- readonly isForceSetProgress: boolean;
- readonly asForceSetProgress: {
- readonly progressTop: PalletStateTrieMigrationProgress;
- readonly progressChild: PalletStateTrieMigrationProgress;
- } & Struct;
- readonly type: 'ControlAutoMigration' | 'ContinueMigrate' | 'MigrateCustomTop' | 'MigrateCustomChild' | 'SetSignedMaxLimits' | 'ForceSetProgress';
- }
-
- /** @name PalletStateTrieMigrationMigrationLimits (94) */
- interface PalletStateTrieMigrationMigrationLimits extends Struct {
- readonly size_: u32;
- readonly item: u32;
- }
-
- /** @name PalletStateTrieMigrationMigrationTask (95) */
- interface PalletStateTrieMigrationMigrationTask extends Struct {
- readonly progressTop: PalletStateTrieMigrationProgress;
- readonly progressChild: PalletStateTrieMigrationProgress;
- readonly size_: u32;
- readonly topItems: u32;
- readonly childItems: u32;
- }
-
- /** @name PalletStateTrieMigrationProgress (96) */
- interface PalletStateTrieMigrationProgress extends Enum {
- readonly isToStart: boolean;
- readonly isLastKey: boolean;
- readonly asLastKey: Bytes;
- readonly isComplete: boolean;
- readonly type: 'ToStart' | 'LastKey' | 'Complete';
- }
-
- /** @name CumulusPalletParachainSystemCall (98) */
- interface CumulusPalletParachainSystemCall extends Enum {
- readonly isSetValidationData: boolean;
- readonly asSetValidationData: {
- readonly data: CumulusPrimitivesParachainInherentParachainInherentData;
- } & Struct;
- readonly isSudoSendUpwardMessage: boolean;
- readonly asSudoSendUpwardMessage: {
- readonly message: Bytes;
- } & Struct;
- readonly isAuthorizeUpgrade: boolean;
- readonly asAuthorizeUpgrade: {
- readonly codeHash: H256;
- readonly checkVersion: bool;
- } & Struct;
- readonly isEnactAuthorizedUpgrade: boolean;
- readonly asEnactAuthorizedUpgrade: {
- readonly code: Bytes;
- } & Struct;
- readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
- }
-
- /** @name CumulusPrimitivesParachainInherentParachainInherentData (99) */
- interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
- readonly validationData: PolkadotPrimitivesV5PersistedValidationData;
- readonly relayChainState: SpTrieStorageProof;
- readonly downwardMessages: Vec<PolkadotCorePrimitivesInboundDownwardMessage>;
- readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
- }
-
- /** @name PolkadotPrimitivesV5PersistedValidationData (100) */
- interface PolkadotPrimitivesV5PersistedValidationData extends Struct {
- readonly parentHead: Bytes;
- readonly relayParentNumber: u32;
- readonly relayParentStorageRoot: H256;
- readonly maxPovSize: u32;
- }
-
- /** @name SpTrieStorageProof (102) */
- interface SpTrieStorageProof extends Struct {
- readonly trieNodes: BTreeSet<Bytes>;
- }
-
- /** @name PolkadotCorePrimitivesInboundDownwardMessage (105) */
- interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
- readonly sentAt: u32;
- readonly msg: Bytes;
- }
-
- /** @name PolkadotCorePrimitivesInboundHrmpMessage (109) */
- interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
- readonly sentAt: u32;
- readonly data: Bytes;
- }
-
- /** @name ParachainInfoCall (112) */
- type ParachainInfoCall = Null;
-
- /** @name PalletCollatorSelectionCall (113) */
- interface PalletCollatorSelectionCall extends Enum {
- readonly isAddInvulnerable: boolean;
- readonly asAddInvulnerable: {
- readonly new_: AccountId32;
- } & Struct;
- readonly isRemoveInvulnerable: boolean;
- readonly asRemoveInvulnerable: {
- readonly who: AccountId32;
- } & Struct;
- readonly isGetLicense: boolean;
- readonly isOnboard: boolean;
- readonly isOffboard: boolean;
- readonly isReleaseLicense: boolean;
- readonly isForceReleaseLicense: boolean;
- readonly asForceReleaseLicense: {
- readonly who: AccountId32;
- } & Struct;
- readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceReleaseLicense';
- }
-
- /** @name PalletSessionCall (114) */
- interface PalletSessionCall extends Enum {
- readonly isSetKeys: boolean;
- readonly asSetKeys: {
- readonly keys_: OpalRuntimeRuntimeCommonSessionKeys;
- readonly proof: Bytes;
- } & Struct;
- readonly isPurgeKeys: boolean;
- readonly type: 'SetKeys' | 'PurgeKeys';
- }
-
- /** @name OpalRuntimeRuntimeCommonSessionKeys (115) */
- interface OpalRuntimeRuntimeCommonSessionKeys extends Struct {
- readonly aura: SpConsensusAuraSr25519AppSr25519Public;
- }
-
- /** @name SpConsensusAuraSr25519AppSr25519Public (116) */
- interface SpConsensusAuraSr25519AppSr25519Public extends SpCoreSr25519Public {}
-
- /** @name SpCoreSr25519Public (117) */
- interface SpCoreSr25519Public extends U8aFixed {}
-
- /** @name PalletBalancesCall (118) */
- interface PalletBalancesCall extends Enum {
- readonly isTransferAllowDeath: boolean;
- readonly asTransferAllowDeath: {
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isSetBalanceDeprecated: boolean;
- readonly asSetBalanceDeprecated: {
- readonly who: MultiAddress;
- readonly newFree: Compact<u128>;
- readonly oldReserved: Compact<u128>;
- } & Struct;
- readonly isForceTransfer: boolean;
- readonly asForceTransfer: {
- readonly source: MultiAddress;
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isTransferKeepAlive: boolean;
- readonly asTransferKeepAlive: {
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isTransferAll: boolean;
- readonly asTransferAll: {
- readonly dest: MultiAddress;
- readonly keepAlive: bool;
- } & Struct;
- readonly isForceUnreserve: boolean;
- readonly asForceUnreserve: {
- readonly who: MultiAddress;
- readonly amount: u128;
- } & Struct;
- readonly isUpgradeAccounts: boolean;
- readonly asUpgradeAccounts: {
- readonly who: Vec<AccountId32>;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly dest: MultiAddress;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isForceSetBalance: boolean;
- readonly asForceSetBalance: {
- readonly who: MultiAddress;
- readonly newFree: Compact<u128>;
- } & Struct;
- readonly type: 'TransferAllowDeath' | 'SetBalanceDeprecated' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve' | 'UpgradeAccounts' | 'Transfer' | 'ForceSetBalance';
- }
-
- /** @name PalletTimestampCall (122) */
- interface PalletTimestampCall extends Enum {
- readonly isSet: boolean;
- readonly asSet: {
- readonly now: Compact<u64>;
- } & Struct;
- readonly type: 'Set';
- }
-
- /** @name PalletTreasuryCall (123) */
- interface PalletTreasuryCall extends Enum {
- readonly isProposeSpend: boolean;
- readonly asProposeSpend: {
- readonly value: Compact<u128>;
- readonly beneficiary: MultiAddress;
- } & Struct;
- readonly isRejectProposal: boolean;
- readonly asRejectProposal: {
- readonly proposalId: Compact<u32>;
- } & Struct;
- readonly isApproveProposal: boolean;
- readonly asApproveProposal: {
- readonly proposalId: Compact<u32>;
- } & Struct;
- readonly isSpend: boolean;
- readonly asSpend: {
- readonly amount: Compact<u128>;
- readonly beneficiary: MultiAddress;
- } & Struct;
- readonly isRemoveApproval: boolean;
- readonly asRemoveApproval: {
- readonly proposalId: Compact<u32>;
- } & Struct;
- readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
- }
-
- /** @name PalletSudoCall (124) */
- interface PalletSudoCall extends Enum {
- readonly isSudo: boolean;
- readonly asSudo: {
- readonly call: Call;
- } & Struct;
- readonly isSudoUncheckedWeight: boolean;
- readonly asSudoUncheckedWeight: {
- readonly call: Call;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isSetKey: boolean;
- readonly asSetKey: {
- readonly new_: MultiAddress;
- } & Struct;
- readonly isSudoAs: boolean;
- readonly asSudoAs: {
- readonly who: MultiAddress;
- readonly call: Call;
- } & Struct;
- readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
- }
-
- /** @name OrmlVestingModuleCall (125) */
- interface OrmlVestingModuleCall extends Enum {
- readonly isClaim: boolean;
- readonly isVestedTransfer: boolean;
- readonly asVestedTransfer: {
- readonly dest: MultiAddress;
- readonly schedule: OrmlVestingVestingSchedule;
- } & Struct;
- readonly isUpdateVestingSchedules: boolean;
- readonly asUpdateVestingSchedules: {
- readonly who: MultiAddress;
- readonly vestingSchedules: Vec<OrmlVestingVestingSchedule>;
- } & Struct;
- readonly isClaimFor: boolean;
- readonly asClaimFor: {
- readonly dest: MultiAddress;
- } & Struct;
- readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
- }
-
- /** @name OrmlXtokensModuleCall (127) */
- interface OrmlXtokensModuleCall extends Enum {
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMultiasset: boolean;
- readonly asTransferMultiasset: {
- readonly asset: StagingXcmVersionedMultiAsset;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferWithFee: boolean;
- readonly asTransferWithFee: {
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: u128;
- readonly fee: u128;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMultiassetWithFee: boolean;
- readonly asTransferMultiassetWithFee: {
- readonly asset: StagingXcmVersionedMultiAsset;
- readonly fee: StagingXcmVersionedMultiAsset;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMulticurrencies: boolean;
- readonly asTransferMulticurrencies: {
- readonly currencies: Vec<ITuple<[PalletForeignAssetsAssetId, u128]>>;
- readonly feeItem: u32;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isTransferMultiassets: boolean;
- readonly asTransferMultiassets: {
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeItem: u32;
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly destWeightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets';
- }
-
- /** @name StagingXcmVersionedMultiLocation (128) */
- interface StagingXcmVersionedMultiLocation extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2MultiLocation;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiLocation;
- readonly type: 'V2' | 'V3';
- }
-
- /** @name StagingXcmV2MultiLocation (129) */
- interface StagingXcmV2MultiLocation extends Struct {
- readonly parents: u8;
- readonly interior: StagingXcmV2MultilocationJunctions;
- }
-
- /** @name StagingXcmV2MultilocationJunctions (130) */
- interface StagingXcmV2MultilocationJunctions extends Enum {
- readonly isHere: boolean;
- readonly isX1: boolean;
- readonly asX1: StagingXcmV2Junction;
- readonly isX2: boolean;
- readonly asX2: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX3: boolean;
- readonly asX3: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX4: boolean;
- readonly asX4: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX5: boolean;
- readonly asX5: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX6: boolean;
- readonly asX6: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX7: boolean;
- readonly asX7: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly isX8: boolean;
- readonly asX8: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
- readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
- }
-
- /** @name StagingXcmV2Junction (131) */
- interface StagingXcmV2Junction extends Enum {
- readonly isParachain: boolean;
- readonly asParachain: Compact<u32>;
- readonly isAccountId32: boolean;
- readonly asAccountId32: {
- readonly network: StagingXcmV2NetworkId;
- readonly id: U8aFixed;
- } & Struct;
- readonly isAccountIndex64: boolean;
- readonly asAccountIndex64: {
- readonly network: StagingXcmV2NetworkId;
- readonly index: Compact<u64>;
- } & Struct;
- readonly isAccountKey20: boolean;
- readonly asAccountKey20: {
- readonly network: StagingXcmV2NetworkId;
- readonly key: U8aFixed;
- } & Struct;
- readonly isPalletInstance: boolean;
- readonly asPalletInstance: u8;
- readonly isGeneralIndex: boolean;
- readonly asGeneralIndex: Compact<u128>;
- readonly isGeneralKey: boolean;
- readonly asGeneralKey: Bytes;
- readonly isOnlyChild: boolean;
- readonly isPlurality: boolean;
- readonly asPlurality: {
- readonly id: StagingXcmV2BodyId;
- readonly part: StagingXcmV2BodyPart;
- } & Struct;
- readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality';
- }
-
- /** @name StagingXcmV2NetworkId (132) */
- interface StagingXcmV2NetworkId extends Enum {
- readonly isAny: boolean;
- readonly isNamed: boolean;
- readonly asNamed: Bytes;
- readonly isPolkadot: boolean;
- readonly isKusama: boolean;
- readonly type: 'Any' | 'Named' | 'Polkadot' | 'Kusama';
- }
-
- /** @name StagingXcmV2BodyId (134) */
- interface StagingXcmV2BodyId extends Enum {
- readonly isUnit: boolean;
- readonly isNamed: boolean;
- readonly asNamed: Bytes;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u32>;
- readonly isExecutive: boolean;
- readonly isTechnical: boolean;
- readonly isLegislative: boolean;
- readonly isJudicial: boolean;
- readonly isDefense: boolean;
- readonly isAdministration: boolean;
- readonly isTreasury: boolean;
- readonly type: 'Unit' | 'Named' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
- }
-
- /** @name StagingXcmV2BodyPart (135) */
- interface StagingXcmV2BodyPart extends Enum {
- readonly isVoice: boolean;
- readonly isMembers: boolean;
- readonly asMembers: {
- readonly count: Compact<u32>;
- } & Struct;
- readonly isFraction: boolean;
- readonly asFraction: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isAtLeastProportion: boolean;
- readonly asAtLeastProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly isMoreThanProportion: boolean;
- readonly asMoreThanProportion: {
- readonly nom: Compact<u32>;
- readonly denom: Compact<u32>;
- } & Struct;
- readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
- }
-
- /** @name StagingXcmV3WeightLimit (136) */
- interface StagingXcmV3WeightLimit extends Enum {
- readonly isUnlimited: boolean;
- readonly isLimited: boolean;
- readonly asLimited: SpWeightsWeightV2Weight;
- readonly type: 'Unlimited' | 'Limited';
- }
-
- /** @name StagingXcmVersionedMultiAsset (137) */
- interface StagingXcmVersionedMultiAsset extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2MultiAsset;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiAsset;
- readonly type: 'V2' | 'V3';
- }
-
- /** @name StagingXcmV2MultiAsset (138) */
- interface StagingXcmV2MultiAsset extends Struct {
- readonly id: StagingXcmV2MultiassetAssetId;
- readonly fun: StagingXcmV2MultiassetFungibility;
- }
-
- /** @name StagingXcmV2MultiassetAssetId (139) */
- interface StagingXcmV2MultiassetAssetId extends Enum {
- readonly isConcrete: boolean;
- readonly asConcrete: StagingXcmV2MultiLocation;
- readonly isAbstract: boolean;
- readonly asAbstract: Bytes;
- readonly type: 'Concrete' | 'Abstract';
- }
-
- /** @name StagingXcmV2MultiassetFungibility (140) */
- interface StagingXcmV2MultiassetFungibility extends Enum {
- readonly isFungible: boolean;
- readonly asFungible: Compact<u128>;
- readonly isNonFungible: boolean;
- readonly asNonFungible: StagingXcmV2MultiassetAssetInstance;
- readonly type: 'Fungible' | 'NonFungible';
- }
-
- /** @name StagingXcmV2MultiassetAssetInstance (141) */
- interface StagingXcmV2MultiassetAssetInstance extends Enum {
- readonly isUndefined: boolean;
- readonly isIndex: boolean;
- readonly asIndex: Compact<u128>;
- readonly isArray4: boolean;
- readonly asArray4: U8aFixed;
- readonly isArray8: boolean;
- readonly asArray8: U8aFixed;
- readonly isArray16: boolean;
- readonly asArray16: U8aFixed;
- readonly isArray32: boolean;
- readonly asArray32: U8aFixed;
- readonly isBlob: boolean;
- readonly asBlob: Bytes;
- readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32' | 'Blob';
- }
-
- /** @name StagingXcmVersionedMultiAssets (144) */
- interface StagingXcmVersionedMultiAssets extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2MultiassetMultiAssets;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiassetMultiAssets;
- readonly type: 'V2' | 'V3';
- }
-
- /** @name StagingXcmV2MultiassetMultiAssets (145) */
- interface StagingXcmV2MultiassetMultiAssets extends Vec<StagingXcmV2MultiAsset> {}
-
- /** @name OrmlTokensModuleCall (147) */
- interface OrmlTokensModuleCall extends Enum {
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: Compact<u128>;
- } & Struct;
- readonly isTransferAll: boolean;
- readonly asTransferAll: {
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly keepAlive: bool;
- } & Struct;
- readonly isTransferKeepAlive: boolean;
- readonly asTransferKeepAlive: {
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: Compact<u128>;
- } & Struct;
- readonly isForceTransfer: boolean;
- readonly asForceTransfer: {
- readonly source: MultiAddress;
- readonly dest: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly amount: Compact<u128>;
- } & Struct;
- readonly isSetBalance: boolean;
- readonly asSetBalance: {
- readonly who: MultiAddress;
- readonly currencyId: PalletForeignAssetsAssetId;
- readonly newFree: Compact<u128>;
- readonly newReserved: Compact<u128>;
- } & Struct;
- readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance';
- }
-
- /** @name PalletIdentityCall (148) */
- interface PalletIdentityCall extends Enum {
- readonly isAddRegistrar: boolean;
- readonly asAddRegistrar: {
- readonly account: MultiAddress;
- } & Struct;
- readonly isSetIdentity: boolean;
- readonly asSetIdentity: {
- readonly info: PalletIdentityIdentityInfo;
- } & Struct;
- readonly isSetSubs: boolean;
- readonly asSetSubs: {
- readonly subs: Vec<ITuple<[AccountId32, Data]>>;
- } & Struct;
- readonly isClearIdentity: boolean;
- readonly isRequestJudgement: boolean;
- readonly asRequestJudgement: {
- readonly regIndex: Compact<u32>;
- readonly maxFee: Compact<u128>;
- } & Struct;
- readonly isCancelRequest: boolean;
- readonly asCancelRequest: {
- readonly regIndex: u32;
- } & Struct;
- readonly isSetFee: boolean;
- readonly asSetFee: {
- readonly index: Compact<u32>;
- readonly fee: Compact<u128>;
- } & Struct;
- readonly isSetAccountId: boolean;
- readonly asSetAccountId: {
- readonly index: Compact<u32>;
- readonly new_: MultiAddress;
- } & Struct;
- readonly isSetFields: boolean;
- readonly asSetFields: {
- readonly index: Compact<u32>;
- readonly fields: PalletIdentityBitFlags;
- } & Struct;
- readonly isProvideJudgement: boolean;
- readonly asProvideJudgement: {
- readonly regIndex: Compact<u32>;
- readonly target: MultiAddress;
- readonly judgement: PalletIdentityJudgement;
- readonly identity: H256;
- } & Struct;
- readonly isKillIdentity: boolean;
- readonly asKillIdentity: {
- readonly target: MultiAddress;
- } & Struct;
- readonly isAddSub: boolean;
- readonly asAddSub: {
- readonly sub: MultiAddress;
- readonly data: Data;
- } & Struct;
- readonly isRenameSub: boolean;
- readonly asRenameSub: {
- readonly sub: MultiAddress;
- readonly data: Data;
- } & Struct;
- readonly isRemoveSub: boolean;
- readonly asRemoveSub: {
- readonly sub: MultiAddress;
- } & Struct;
- readonly isQuitSub: boolean;
- readonly isForceInsertIdentities: boolean;
- readonly asForceInsertIdentities: {
- readonly identities: Vec<ITuple<[AccountId32, PalletIdentityRegistration]>>;
- } & Struct;
- readonly isForceRemoveIdentities: boolean;
- readonly asForceRemoveIdentities: {
- readonly identities: Vec<AccountId32>;
- } & Struct;
- readonly isForceSetSubs: boolean;
- readonly asForceSetSubs: {
- readonly subs: Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>>;
- } & Struct;
- readonly type: 'AddRegistrar' | 'SetIdentity' | 'SetSubs' | 'ClearIdentity' | 'RequestJudgement' | 'CancelRequest' | 'SetFee' | 'SetAccountId' | 'SetFields' | 'ProvideJudgement' | 'KillIdentity' | 'AddSub' | 'RenameSub' | 'RemoveSub' | 'QuitSub' | 'ForceInsertIdentities' | 'ForceRemoveIdentities' | 'ForceSetSubs';
- }
-
- /** @name PalletIdentityIdentityInfo (149) */
- interface PalletIdentityIdentityInfo extends Struct {
- readonly additional: Vec<ITuple<[Data, Data]>>;
- readonly display: Data;
- readonly legal: Data;
- readonly web: Data;
- readonly riot: Data;
- readonly email: Data;
- readonly pgpFingerprint: Option<U8aFixed>;
- readonly image: Data;
- readonly twitter: Data;
- }
-
- /** @name PalletIdentityBitFlags (185) */
- interface PalletIdentityBitFlags extends Set {
- readonly isDisplay: boolean;
- readonly isLegal: boolean;
- readonly isWeb: boolean;
- readonly isRiot: boolean;
- readonly isEmail: boolean;
- readonly isPgpFingerprint: boolean;
- readonly isImage: boolean;
- readonly isTwitter: boolean;
- }
-
- /** @name PalletIdentityIdentityField (186) */
- interface PalletIdentityIdentityField extends Enum {
- readonly isDisplay: boolean;
- readonly isLegal: boolean;
- readonly isWeb: boolean;
- readonly isRiot: boolean;
- readonly isEmail: boolean;
- readonly isPgpFingerprint: boolean;
- readonly isImage: boolean;
- readonly isTwitter: boolean;
- readonly type: 'Display' | 'Legal' | 'Web' | 'Riot' | 'Email' | 'PgpFingerprint' | 'Image' | 'Twitter';
- }
-
- /** @name PalletIdentityJudgement (187) */
- interface PalletIdentityJudgement extends Enum {
- readonly isUnknown: boolean;
- readonly isFeePaid: boolean;
- readonly asFeePaid: u128;
- readonly isReasonable: boolean;
- readonly isKnownGood: boolean;
- readonly isOutOfDate: boolean;
- readonly isLowQuality: boolean;
- readonly isErroneous: boolean;
- readonly type: 'Unknown' | 'FeePaid' | 'Reasonable' | 'KnownGood' | 'OutOfDate' | 'LowQuality' | 'Erroneous';
- }
-
- /** @name PalletIdentityRegistration (190) */
- interface PalletIdentityRegistration extends Struct {
- readonly judgements: Vec<ITuple<[u32, PalletIdentityJudgement]>>;
- readonly deposit: u128;
- readonly info: PalletIdentityIdentityInfo;
- }
-
- /** @name PalletPreimageCall (198) */
- interface PalletPreimageCall extends Enum {
- readonly isNotePreimage: boolean;
- readonly asNotePreimage: {
- readonly bytes: Bytes;
- } & Struct;
- readonly isUnnotePreimage: boolean;
- readonly asUnnotePreimage: {
- readonly hash_: H256;
- } & Struct;
- readonly isRequestPreimage: boolean;
- readonly asRequestPreimage: {
- readonly hash_: H256;
- } & Struct;
- readonly isUnrequestPreimage: boolean;
- readonly asUnrequestPreimage: {
- readonly hash_: H256;
- } & Struct;
- readonly type: 'NotePreimage' | 'UnnotePreimage' | 'RequestPreimage' | 'UnrequestPreimage';
- }
-
- /** @name PalletDemocracyCall (199) */
- interface PalletDemocracyCall extends Enum {
- readonly isPropose: boolean;
- readonly asPropose: {
- readonly proposal: FrameSupportPreimagesBounded;
- readonly value: Compact<u128>;
- } & Struct;
- readonly isSecond: boolean;
- readonly asSecond: {
- readonly proposal: Compact<u32>;
- } & Struct;
- readonly isVote: boolean;
- readonly asVote: {
- readonly refIndex: Compact<u32>;
- readonly vote: PalletDemocracyVoteAccountVote;
- } & Struct;
- readonly isEmergencyCancel: boolean;
- readonly asEmergencyCancel: {
- readonly refIndex: u32;
- } & Struct;
- readonly isExternalPropose: boolean;
- readonly asExternalPropose: {
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isExternalProposeMajority: boolean;
- readonly asExternalProposeMajority: {
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isExternalProposeDefault: boolean;
- readonly asExternalProposeDefault: {
- readonly proposal: FrameSupportPreimagesBounded;
- } & Struct;
- readonly isFastTrack: boolean;
- readonly asFastTrack: {
- readonly proposalHash: H256;
- readonly votingPeriod: u32;
- readonly delay: u32;
- } & Struct;
- readonly isVetoExternal: boolean;
- readonly asVetoExternal: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isCancelReferendum: boolean;
- readonly asCancelReferendum: {
- readonly refIndex: Compact<u32>;
- } & Struct;
- readonly isDelegate: boolean;
- readonly asDelegate: {
- readonly to: MultiAddress;
- readonly conviction: PalletDemocracyConviction;
- readonly balance: u128;
- } & Struct;
- readonly isUndelegate: boolean;
- readonly isClearPublicProposals: boolean;
- readonly isUnlock: boolean;
- readonly asUnlock: {
- readonly target: MultiAddress;
- } & Struct;
- readonly isRemoveVote: boolean;
- readonly asRemoveVote: {
- readonly index: u32;
- } & Struct;
- readonly isRemoveOtherVote: boolean;
- readonly asRemoveOtherVote: {
- readonly target: MultiAddress;
- readonly index: u32;
- } & Struct;
- readonly isBlacklist: boolean;
- readonly asBlacklist: {
- readonly proposalHash: H256;
- readonly maybeRefIndex: Option<u32>;
- } & Struct;
- readonly isCancelProposal: boolean;
- readonly asCancelProposal: {
- readonly propIndex: Compact<u32>;
- } & Struct;
- readonly isSetMetadata: boolean;
- readonly asSetMetadata: {
- readonly owner: PalletDemocracyMetadataOwner;
- readonly maybeHash: Option<H256>;
- } & Struct;
- readonly type: 'Propose' | 'Second' | 'Vote' | 'EmergencyCancel' | 'ExternalPropose' | 'ExternalProposeMajority' | 'ExternalProposeDefault' | 'FastTrack' | 'VetoExternal' | 'CancelReferendum' | 'Delegate' | 'Undelegate' | 'ClearPublicProposals' | 'Unlock' | 'RemoveVote' | 'RemoveOtherVote' | 'Blacklist' | 'CancelProposal' | 'SetMetadata';
- }
-
- /** @name PalletDemocracyConviction (200) */
- interface PalletDemocracyConviction extends Enum {
- readonly isNone: boolean;
- readonly isLocked1x: boolean;
- readonly isLocked2x: boolean;
- readonly isLocked3x: boolean;
- readonly isLocked4x: boolean;
- readonly isLocked5x: boolean;
- readonly isLocked6x: boolean;
- readonly type: 'None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x' | 'Locked6x';
- }
-
- /** @name PalletCollectiveCall (203) */
- interface PalletCollectiveCall extends Enum {
- readonly isSetMembers: boolean;
- readonly asSetMembers: {
- readonly newMembers: Vec<AccountId32>;
- readonly prime: Option<AccountId32>;
- readonly oldCount: u32;
- } & Struct;
- readonly isExecute: boolean;
- readonly asExecute: {
- readonly proposal: Call;
- readonly lengthBound: Compact<u32>;
- } & Struct;
- readonly isPropose: boolean;
- readonly asPropose: {
- readonly threshold: Compact<u32>;
- readonly proposal: Call;
- readonly lengthBound: Compact<u32>;
- } & Struct;
- readonly isVote: boolean;
- readonly asVote: {
- readonly proposal: H256;
- readonly index: Compact<u32>;
- readonly approve: bool;
- } & Struct;
- readonly isDisapproveProposal: boolean;
- readonly asDisapproveProposal: {
- readonly proposalHash: H256;
- } & Struct;
- readonly isClose: boolean;
- readonly asClose: {
- readonly proposalHash: H256;
- readonly index: Compact<u32>;
- readonly proposalWeightBound: SpWeightsWeightV2Weight;
- readonly lengthBound: Compact<u32>;
- } & Struct;
- readonly type: 'SetMembers' | 'Execute' | 'Propose' | 'Vote' | 'DisapproveProposal' | 'Close';
- }
-
- /** @name PalletMembershipCall (205) */
- interface PalletMembershipCall extends Enum {
- readonly isAddMember: boolean;
- readonly asAddMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isRemoveMember: boolean;
- readonly asRemoveMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isSwapMember: boolean;
- readonly asSwapMember: {
- readonly remove: MultiAddress;
- readonly add: MultiAddress;
- } & Struct;
- readonly isResetMembers: boolean;
- readonly asResetMembers: {
- readonly members: Vec<AccountId32>;
- } & Struct;
- readonly isChangeKey: boolean;
- readonly asChangeKey: {
- readonly new_: MultiAddress;
- } & Struct;
- readonly isSetPrime: boolean;
- readonly asSetPrime: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isClearPrime: boolean;
- readonly type: 'AddMember' | 'RemoveMember' | 'SwapMember' | 'ResetMembers' | 'ChangeKey' | 'SetPrime' | 'ClearPrime';
- }
-
- /** @name PalletRankedCollectiveCall (207) */
- interface PalletRankedCollectiveCall extends Enum {
- readonly isAddMember: boolean;
- readonly asAddMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isPromoteMember: boolean;
- readonly asPromoteMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isDemoteMember: boolean;
- readonly asDemoteMember: {
- readonly who: MultiAddress;
- } & Struct;
- readonly isRemoveMember: boolean;
- readonly asRemoveMember: {
- readonly who: MultiAddress;
- readonly minRank: u16;
- } & Struct;
- readonly isVote: boolean;
- readonly asVote: {
- readonly poll: u32;
- readonly aye: bool;
- } & Struct;
- readonly isCleanupPoll: boolean;
- readonly asCleanupPoll: {
- readonly pollIndex: u32;
- readonly max: u32;
- } & Struct;
- readonly type: 'AddMember' | 'PromoteMember' | 'DemoteMember' | 'RemoveMember' | 'Vote' | 'CleanupPoll';
- }
-
- /** @name PalletReferendaCall (208) */
- interface PalletReferendaCall extends Enum {
- readonly isSubmit: boolean;
- readonly asSubmit: {
- readonly proposalOrigin: OpalRuntimeOriginCaller;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly enactmentMoment: FrameSupportScheduleDispatchTime;
- } & Struct;
- readonly isPlaceDecisionDeposit: boolean;
- readonly asPlaceDecisionDeposit: {
- readonly index: u32;
- } & Struct;
- readonly isRefundDecisionDeposit: boolean;
- readonly asRefundDecisionDeposit: {
- readonly index: u32;
- } & Struct;
- readonly isCancel: boolean;
- readonly asCancel: {
- readonly index: u32;
- } & Struct;
- readonly isKill: boolean;
- readonly asKill: {
- readonly index: u32;
- } & Struct;
- readonly isNudgeReferendum: boolean;
- readonly asNudgeReferendum: {
- readonly index: u32;
- } & Struct;
- readonly isOneFewerDeciding: boolean;
- readonly asOneFewerDeciding: {
- readonly track: u16;
- } & Struct;
- readonly isRefundSubmissionDeposit: boolean;
- readonly asRefundSubmissionDeposit: {
- readonly index: u32;
- } & Struct;
- readonly isSetMetadata: boolean;
- readonly asSetMetadata: {
- readonly index: u32;
- readonly maybeHash: Option<H256>;
- } & Struct;
- readonly type: 'Submit' | 'PlaceDecisionDeposit' | 'RefundDecisionDeposit' | 'Cancel' | 'Kill' | 'NudgeReferendum' | 'OneFewerDeciding' | 'RefundSubmissionDeposit' | 'SetMetadata';
- }
-
- /** @name OpalRuntimeOriginCaller (209) */
- interface OpalRuntimeOriginCaller extends Enum {
- readonly isSystem: boolean;
- readonly asSystem: FrameSupportDispatchRawOrigin;
- readonly isVoid: boolean;
- readonly isCouncil: boolean;
- readonly asCouncil: PalletCollectiveRawOrigin;
- readonly isTechnicalCommittee: boolean;
- readonly asTechnicalCommittee: PalletCollectiveRawOrigin;
- readonly isPolkadotXcm: boolean;
- readonly asPolkadotXcm: PalletXcmOrigin;
- readonly isCumulusXcm: boolean;
- readonly asCumulusXcm: CumulusPalletXcmOrigin;
- readonly isOrigins: boolean;
- readonly asOrigins: PalletGovOriginsOrigin;
- readonly isEthereum: boolean;
- readonly asEthereum: PalletEthereumRawOrigin;
- readonly type: 'System' | 'Void' | 'Council' | 'TechnicalCommittee' | 'PolkadotXcm' | 'CumulusXcm' | 'Origins' | 'Ethereum';
- }
-
- /** @name FrameSupportDispatchRawOrigin (210) */
- interface FrameSupportDispatchRawOrigin extends Enum {
- readonly isRoot: boolean;
- readonly isSigned: boolean;
- readonly asSigned: AccountId32;
- readonly isNone: boolean;
- readonly type: 'Root' | 'Signed' | 'None';
- }
-
- /** @name PalletCollectiveRawOrigin (211) */
- interface PalletCollectiveRawOrigin extends Enum {
- readonly isMembers: boolean;
- readonly asMembers: ITuple<[u32, u32]>;
- readonly isMember: boolean;
- readonly asMember: AccountId32;
- readonly isPhantom: boolean;
- readonly type: 'Members' | 'Member' | 'Phantom';
- }
-
- /** @name PalletGovOriginsOrigin (213) */
- interface PalletGovOriginsOrigin extends Enum {
- readonly isFellowshipProposition: boolean;
- readonly type: 'FellowshipProposition';
- }
-
- /** @name PalletXcmOrigin (214) */
- interface PalletXcmOrigin extends Enum {
- readonly isXcm: boolean;
- readonly asXcm: StagingXcmV3MultiLocation;
- readonly isResponse: boolean;
- readonly asResponse: StagingXcmV3MultiLocation;
- readonly type: 'Xcm' | 'Response';
- }
-
- /** @name CumulusPalletXcmOrigin (215) */
- interface CumulusPalletXcmOrigin extends Enum {
- readonly isRelay: boolean;
- readonly isSiblingParachain: boolean;
- readonly asSiblingParachain: u32;
- readonly type: 'Relay' | 'SiblingParachain';
- }
-
- /** @name PalletEthereumRawOrigin (216) */
- interface PalletEthereumRawOrigin extends Enum {
- readonly isEthereumTransaction: boolean;
- readonly asEthereumTransaction: H160;
- readonly type: 'EthereumTransaction';
- }
-
- /** @name SpCoreVoid (218) */
- type SpCoreVoid = Null;
-
- /** @name FrameSupportScheduleDispatchTime (219) */
- interface FrameSupportScheduleDispatchTime extends Enum {
- readonly isAt: boolean;
- readonly asAt: u32;
- readonly isAfter: boolean;
- readonly asAfter: u32;
- readonly type: 'At' | 'After';
- }
-
- /** @name PalletSchedulerCall (220) */
- interface PalletSchedulerCall extends Enum {
- readonly isSchedule: boolean;
- readonly asSchedule: {
- readonly when: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly isCancel: boolean;
- readonly asCancel: {
- readonly when: u32;
- readonly index: u32;
- } & Struct;
- readonly isScheduleNamed: boolean;
- readonly asScheduleNamed: {
- readonly id: U8aFixed;
- readonly when: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly isCancelNamed: boolean;
- readonly asCancelNamed: {
- readonly id: U8aFixed;
- } & Struct;
- readonly isScheduleAfter: boolean;
- readonly asScheduleAfter: {
- readonly after: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly isScheduleNamedAfter: boolean;
- readonly asScheduleNamedAfter: {
- readonly id: U8aFixed;
- readonly after: u32;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly priority: u8;
- readonly call: Call;
- } & Struct;
- readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter';
- }
-
- /** @name CumulusPalletXcmpQueueCall (223) */
- interface CumulusPalletXcmpQueueCall extends Enum {
- readonly isServiceOverweight: boolean;
- readonly asServiceOverweight: {
- readonly index: u64;
- readonly weightLimit: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isSuspendXcmExecution: boolean;
- readonly isResumeXcmExecution: boolean;
- readonly isUpdateSuspendThreshold: boolean;
- readonly asUpdateSuspendThreshold: {
- readonly new_: u32;
- } & Struct;
- readonly isUpdateDropThreshold: boolean;
- readonly asUpdateDropThreshold: {
- readonly new_: u32;
- } & Struct;
- readonly isUpdateResumeThreshold: boolean;
- readonly asUpdateResumeThreshold: {
- readonly new_: u32;
- } & Struct;
- readonly isUpdateThresholdWeight: boolean;
- readonly asUpdateThresholdWeight: {
- readonly new_: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isUpdateWeightRestrictDecay: boolean;
- readonly asUpdateWeightRestrictDecay: {
- readonly new_: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isUpdateXcmpMaxIndividualWeight: boolean;
- readonly asUpdateXcmpMaxIndividualWeight: {
- readonly new_: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
- }
-
- /** @name PalletXcmCall (224) */
- interface PalletXcmCall extends Enum {
- readonly isSend: boolean;
- readonly asSend: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly message: StagingXcmVersionedXcm;
- } & Struct;
- readonly isTeleportAssets: boolean;
- readonly asTeleportAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- } & Struct;
- readonly isReserveTransferAssets: boolean;
- readonly asReserveTransferAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- } & Struct;
- readonly isExecute: boolean;
- readonly asExecute: {
- readonly message: StagingXcmVersionedXcm;
- readonly maxWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isForceXcmVersion: boolean;
- readonly asForceXcmVersion: {
- readonly location: StagingXcmV3MultiLocation;
- readonly version: u32;
- } & Struct;
- readonly isForceDefaultXcmVersion: boolean;
- readonly asForceDefaultXcmVersion: {
- readonly maybeXcmVersion: Option<u32>;
- } & Struct;
- readonly isForceSubscribeVersionNotify: boolean;
- readonly asForceSubscribeVersionNotify: {
- readonly location: StagingXcmVersionedMultiLocation;
- } & Struct;
- readonly isForceUnsubscribeVersionNotify: boolean;
- readonly asForceUnsubscribeVersionNotify: {
- readonly location: StagingXcmVersionedMultiLocation;
- } & Struct;
- readonly isLimitedReserveTransferAssets: boolean;
- readonly asLimitedReserveTransferAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- readonly weightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isLimitedTeleportAssets: boolean;
- readonly asLimitedTeleportAssets: {
- readonly dest: StagingXcmVersionedMultiLocation;
- readonly beneficiary: StagingXcmVersionedMultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- readonly feeAssetItem: u32;
- readonly weightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isForceSuspension: boolean;
- readonly asForceSuspension: {
- readonly suspended: bool;
- } & Struct;
- readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets' | 'ForceSuspension';
- }
-
- /** @name StagingXcmVersionedXcm (225) */
- interface StagingXcmVersionedXcm extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2Xcm;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3Xcm;
- readonly type: 'V2' | 'V3';
- }
-
- /** @name StagingXcmV2Xcm (226) */
- interface StagingXcmV2Xcm extends Vec<StagingXcmV2Instruction> {}
-
- /** @name StagingXcmV2Instruction (228) */
- interface StagingXcmV2Instruction extends Enum {
- readonly isWithdrawAsset: boolean;
- readonly asWithdrawAsset: StagingXcmV2MultiassetMultiAssets;
- readonly isReserveAssetDeposited: boolean;
- readonly asReserveAssetDeposited: StagingXcmV2MultiassetMultiAssets;
- readonly isReceiveTeleportedAsset: boolean;
- readonly asReceiveTeleportedAsset: StagingXcmV2MultiassetMultiAssets;
- readonly isQueryResponse: boolean;
- readonly asQueryResponse: {
- readonly queryId: Compact<u64>;
- readonly response: StagingXcmV2Response;
- readonly maxWeight: Compact<u64>;
- } & Struct;
- readonly isTransferAsset: boolean;
- readonly asTransferAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssets;
- readonly beneficiary: StagingXcmV2MultiLocation;
- } & Struct;
- readonly isTransferReserveAsset: boolean;
- readonly asTransferReserveAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssets;
- readonly dest: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isTransact: boolean;
- readonly asTransact: {
- readonly originType: StagingXcmV2OriginKind;
- readonly requireWeightAtMost: Compact<u64>;
- readonly call: StagingXcmDoubleEncoded;
- } & Struct;
- readonly isHrmpNewChannelOpenRequest: boolean;
- readonly asHrmpNewChannelOpenRequest: {
- readonly sender: Compact<u32>;
- readonly maxMessageSize: Compact<u32>;
- readonly maxCapacity: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelAccepted: boolean;
- readonly asHrmpChannelAccepted: {
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelClosing: boolean;
- readonly asHrmpChannelClosing: {
- readonly initiator: Compact<u32>;
- readonly sender: Compact<u32>;
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isClearOrigin: boolean;
- readonly isDescendOrigin: boolean;
- readonly asDescendOrigin: StagingXcmV2MultilocationJunctions;
- readonly isReportError: boolean;
- readonly asReportError: {
- readonly queryId: Compact<u64>;
- readonly dest: StagingXcmV2MultiLocation;
- readonly maxResponseWeight: Compact<u64>;
- } & Struct;
- readonly isDepositAsset: boolean;
- readonly asDepositAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly maxAssets: Compact<u32>;
- readonly beneficiary: StagingXcmV2MultiLocation;
- } & Struct;
- readonly isDepositReserveAsset: boolean;
- readonly asDepositReserveAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly maxAssets: Compact<u32>;
- readonly dest: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isExchangeAsset: boolean;
- readonly asExchangeAsset: {
- readonly give: StagingXcmV2MultiassetMultiAssetFilter;
- readonly receive: StagingXcmV2MultiassetMultiAssets;
- } & Struct;
- readonly isInitiateReserveWithdraw: boolean;
- readonly asInitiateReserveWithdraw: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly reserve: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isInitiateTeleport: boolean;
- readonly asInitiateTeleport: {
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly dest: StagingXcmV2MultiLocation;
- readonly xcm: StagingXcmV2Xcm;
- } & Struct;
- readonly isQueryHolding: boolean;
- readonly asQueryHolding: {
- readonly queryId: Compact<u64>;
- readonly dest: StagingXcmV2MultiLocation;
- readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
- readonly maxResponseWeight: Compact<u64>;
- } & Struct;
- readonly isBuyExecution: boolean;
- readonly asBuyExecution: {
- readonly fees: StagingXcmV2MultiAsset;
- readonly weightLimit: StagingXcmV2WeightLimit;
- } & Struct;
- readonly isRefundSurplus: boolean;
- readonly isSetErrorHandler: boolean;
- readonly asSetErrorHandler: StagingXcmV2Xcm;
- readonly isSetAppendix: boolean;
- readonly asSetAppendix: StagingXcmV2Xcm;
- readonly isClearError: boolean;
- readonly isClaimAsset: boolean;
- readonly asClaimAsset: {
- readonly assets: StagingXcmV2MultiassetMultiAssets;
- readonly ticket: StagingXcmV2MultiLocation;
- } & Struct;
- readonly isTrap: boolean;
- readonly asTrap: Compact<u64>;
- readonly isSubscribeVersion: boolean;
- readonly asSubscribeVersion: {
- readonly queryId: Compact<u64>;
- readonly maxResponseWeight: Compact<u64>;
- } & Struct;
- readonly isUnsubscribeVersion: boolean;
- readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion';
- }
-
- /** @name StagingXcmV2Response (229) */
- interface StagingXcmV2Response extends Enum {
- readonly isNull: boolean;
- readonly isAssets: boolean;
- readonly asAssets: StagingXcmV2MultiassetMultiAssets;
- readonly isExecutionResult: boolean;
- readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV2TraitsError]>>;
- readonly isVersion: boolean;
- readonly asVersion: u32;
- readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version';
- }
-
- /** @name StagingXcmV2TraitsError (232) */
- interface StagingXcmV2TraitsError extends Enum {
- readonly isOverflow: boolean;
- readonly isUnimplemented: boolean;
- readonly isUntrustedReserveLocation: boolean;
- readonly isUntrustedTeleportLocation: boolean;
- readonly isMultiLocationFull: boolean;
- readonly isMultiLocationNotInvertible: boolean;
- readonly isBadOrigin: boolean;
- readonly isInvalidLocation: boolean;
- readonly isAssetNotFound: boolean;
- readonly isFailedToTransactAsset: boolean;
- readonly isNotWithdrawable: boolean;
- readonly isLocationCannotHold: boolean;
- readonly isExceedsMaxMessageSize: boolean;
- readonly isDestinationUnsupported: boolean;
- readonly isTransport: boolean;
- readonly isUnroutable: boolean;
- readonly isUnknownClaim: boolean;
- readonly isFailedToDecode: boolean;
- readonly isMaxWeightInvalid: boolean;
- readonly isNotHoldingFees: boolean;
- readonly isTooExpensive: boolean;
- readonly isTrap: boolean;
- readonly asTrap: u64;
- readonly isUnhandledXcmVersion: boolean;
- readonly isWeightLimitReached: boolean;
- readonly asWeightLimitReached: u64;
- readonly isBarrier: boolean;
- readonly isWeightNotComputable: boolean;
- readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'MultiLocationFull' | 'MultiLocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable';
- }
-
- /** @name StagingXcmV2OriginKind (233) */
- interface StagingXcmV2OriginKind extends Enum {
- readonly isNative: boolean;
- readonly isSovereignAccount: boolean;
- readonly isSuperuser: boolean;
- readonly isXcm: boolean;
- readonly type: 'Native' | 'SovereignAccount' | 'Superuser' | 'Xcm';
- }
-
- /** @name StagingXcmDoubleEncoded (234) */
- interface StagingXcmDoubleEncoded extends Struct {
- readonly encoded: Bytes;
- }
-
- /** @name StagingXcmV2MultiassetMultiAssetFilter (235) */
- interface StagingXcmV2MultiassetMultiAssetFilter extends Enum {
- readonly isDefinite: boolean;
- readonly asDefinite: StagingXcmV2MultiassetMultiAssets;
- readonly isWild: boolean;
- readonly asWild: StagingXcmV2MultiassetWildMultiAsset;
- readonly type: 'Definite' | 'Wild';
- }
-
- /** @name StagingXcmV2MultiassetWildMultiAsset (236) */
- interface StagingXcmV2MultiassetWildMultiAsset extends Enum {
- readonly isAll: boolean;
- readonly isAllOf: boolean;
- readonly asAllOf: {
- readonly id: StagingXcmV2MultiassetAssetId;
- readonly fun: StagingXcmV2MultiassetWildFungibility;
- } & Struct;
- readonly type: 'All' | 'AllOf';
- }
-
- /** @name StagingXcmV2MultiassetWildFungibility (237) */
- interface StagingXcmV2MultiassetWildFungibility extends Enum {
- readonly isFungible: boolean;
- readonly isNonFungible: boolean;
- readonly type: 'Fungible' | 'NonFungible';
- }
-
- /** @name StagingXcmV2WeightLimit (238) */
- interface StagingXcmV2WeightLimit extends Enum {
- readonly isUnlimited: boolean;
- readonly isLimited: boolean;
- readonly asLimited: Compact<u64>;
- readonly type: 'Unlimited' | 'Limited';
- }
-
- /** @name StagingXcmV3Xcm (239) */
- interface StagingXcmV3Xcm extends Vec<StagingXcmV3Instruction> {}
-
- /** @name StagingXcmV3Instruction (241) */
- interface StagingXcmV3Instruction extends Enum {
- readonly isWithdrawAsset: boolean;
- readonly asWithdrawAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isReserveAssetDeposited: boolean;
- readonly asReserveAssetDeposited: StagingXcmV3MultiassetMultiAssets;
- readonly isReceiveTeleportedAsset: boolean;
- readonly asReceiveTeleportedAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isQueryResponse: boolean;
- readonly asQueryResponse: {
- readonly queryId: Compact<u64>;
- readonly response: StagingXcmV3Response;
- readonly maxWeight: SpWeightsWeightV2Weight;
- readonly querier: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly isTransferAsset: boolean;
- readonly asTransferAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly beneficiary: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isTransferReserveAsset: boolean;
- readonly asTransferReserveAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly dest: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isTransact: boolean;
- readonly asTransact: {
- readonly originKind: StagingXcmV2OriginKind;
- readonly requireWeightAtMost: SpWeightsWeightV2Weight;
- readonly call: StagingXcmDoubleEncoded;
- } & Struct;
- readonly isHrmpNewChannelOpenRequest: boolean;
- readonly asHrmpNewChannelOpenRequest: {
- readonly sender: Compact<u32>;
- readonly maxMessageSize: Compact<u32>;
- readonly maxCapacity: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelAccepted: boolean;
- readonly asHrmpChannelAccepted: {
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isHrmpChannelClosing: boolean;
- readonly asHrmpChannelClosing: {
- readonly initiator: Compact<u32>;
- readonly sender: Compact<u32>;
- readonly recipient: Compact<u32>;
- } & Struct;
- readonly isClearOrigin: boolean;
- readonly isDescendOrigin: boolean;
- readonly asDescendOrigin: StagingXcmV3Junctions;
- readonly isReportError: boolean;
- readonly asReportError: StagingXcmV3QueryResponseInfo;
- readonly isDepositAsset: boolean;
- readonly asDepositAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly beneficiary: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isDepositReserveAsset: boolean;
- readonly asDepositReserveAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly dest: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isExchangeAsset: boolean;
- readonly asExchangeAsset: {
- readonly give: StagingXcmV3MultiassetMultiAssetFilter;
- readonly want: StagingXcmV3MultiassetMultiAssets;
- readonly maximal: bool;
- } & Struct;
- readonly isInitiateReserveWithdraw: boolean;
- readonly asInitiateReserveWithdraw: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly reserve: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isInitiateTeleport: boolean;
- readonly asInitiateTeleport: {
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- readonly dest: StagingXcmV3MultiLocation;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isReportHolding: boolean;
- readonly asReportHolding: {
- readonly responseInfo: StagingXcmV3QueryResponseInfo;
- readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
- } & Struct;
- readonly isBuyExecution: boolean;
- readonly asBuyExecution: {
- readonly fees: StagingXcmV3MultiAsset;
- readonly weightLimit: StagingXcmV3WeightLimit;
- } & Struct;
- readonly isRefundSurplus: boolean;
- readonly isSetErrorHandler: boolean;
- readonly asSetErrorHandler: StagingXcmV3Xcm;
- readonly isSetAppendix: boolean;
- readonly asSetAppendix: StagingXcmV3Xcm;
- readonly isClearError: boolean;
- readonly isClaimAsset: boolean;
- readonly asClaimAsset: {
- readonly assets: StagingXcmV3MultiassetMultiAssets;
- readonly ticket: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isTrap: boolean;
- readonly asTrap: Compact<u64>;
- readonly isSubscribeVersion: boolean;
- readonly asSubscribeVersion: {
- readonly queryId: Compact<u64>;
- readonly maxResponseWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isUnsubscribeVersion: boolean;
- readonly isBurnAsset: boolean;
- readonly asBurnAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isExpectAsset: boolean;
- readonly asExpectAsset: StagingXcmV3MultiassetMultiAssets;
- readonly isExpectOrigin: boolean;
- readonly asExpectOrigin: Option<StagingXcmV3MultiLocation>;
- readonly isExpectError: boolean;
- readonly asExpectError: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
- readonly isExpectTransactStatus: boolean;
- readonly asExpectTransactStatus: StagingXcmV3MaybeErrorCode;
- readonly isQueryPallet: boolean;
- readonly asQueryPallet: {
- readonly moduleName: Bytes;
- readonly responseInfo: StagingXcmV3QueryResponseInfo;
- } & Struct;
- readonly isExpectPallet: boolean;
- readonly asExpectPallet: {
- readonly index: Compact<u32>;
- readonly name: Bytes;
- readonly moduleName: Bytes;
- readonly crateMajor: Compact<u32>;
- readonly minCrateMinor: Compact<u32>;
- } & Struct;
- readonly isReportTransactStatus: boolean;
- readonly asReportTransactStatus: StagingXcmV3QueryResponseInfo;
- readonly isClearTransactStatus: boolean;
- readonly isUniversalOrigin: boolean;
- readonly asUniversalOrigin: StagingXcmV3Junction;
- readonly isExportMessage: boolean;
- readonly asExportMessage: {
- readonly network: StagingXcmV3JunctionNetworkId;
- readonly destination: StagingXcmV3Junctions;
- readonly xcm: StagingXcmV3Xcm;
- } & Struct;
- readonly isLockAsset: boolean;
- readonly asLockAsset: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly unlocker: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isUnlockAsset: boolean;
- readonly asUnlockAsset: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly target: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isNoteUnlockable: boolean;
- readonly asNoteUnlockable: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly owner: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isRequestUnlock: boolean;
- readonly asRequestUnlock: {
- readonly asset: StagingXcmV3MultiAsset;
- readonly locker: StagingXcmV3MultiLocation;
- } & Struct;
- readonly isSetFeesMode: boolean;
- readonly asSetFeesMode: {
- readonly jitWithdraw: bool;
- } & Struct;
- readonly isSetTopic: boolean;
- readonly asSetTopic: U8aFixed;
- readonly isClearTopic: boolean;
- readonly isAliasOrigin: boolean;
- readonly asAliasOrigin: StagingXcmV3MultiLocation;
- readonly isUnpaidExecution: boolean;
- readonly asUnpaidExecution: {
- readonly weightLimit: StagingXcmV3WeightLimit;
- readonly checkOrigin: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'ReportHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion' | 'BurnAsset' | 'ExpectAsset' | 'ExpectOrigin' | 'ExpectError' | 'ExpectTransactStatus' | 'QueryPallet' | 'ExpectPallet' | 'ReportTransactStatus' | 'ClearTransactStatus' | 'UniversalOrigin' | 'ExportMessage' | 'LockAsset' | 'UnlockAsset' | 'NoteUnlockable' | 'RequestUnlock' | 'SetFeesMode' | 'SetTopic' | 'ClearTopic' | 'AliasOrigin' | 'UnpaidExecution';
- }
-
- /** @name StagingXcmV3Response (242) */
- interface StagingXcmV3Response extends Enum {
- readonly isNull: boolean;
- readonly isAssets: boolean;
- readonly asAssets: StagingXcmV3MultiassetMultiAssets;
- readonly isExecutionResult: boolean;
- readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
- readonly isVersion: boolean;
- readonly asVersion: u32;
- readonly isPalletsInfo: boolean;
- readonly asPalletsInfo: Vec<StagingXcmV3PalletInfo>;
- readonly isDispatchResult: boolean;
- readonly asDispatchResult: StagingXcmV3MaybeErrorCode;
- readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version' | 'PalletsInfo' | 'DispatchResult';
- }
-
- /** @name StagingXcmV3TraitsError (245) */
- interface StagingXcmV3TraitsError extends Enum {
- readonly isOverflow: boolean;
- readonly isUnimplemented: boolean;
- readonly isUntrustedReserveLocation: boolean;
- readonly isUntrustedTeleportLocation: boolean;
- readonly isLocationFull: boolean;
- readonly isLocationNotInvertible: boolean;
- readonly isBadOrigin: boolean;
- readonly isInvalidLocation: boolean;
- readonly isAssetNotFound: boolean;
- readonly isFailedToTransactAsset: boolean;
- readonly isNotWithdrawable: boolean;
- readonly isLocationCannotHold: boolean;
- readonly isExceedsMaxMessageSize: boolean;
- readonly isDestinationUnsupported: boolean;
- readonly isTransport: boolean;
- readonly isUnroutable: boolean;
- readonly isUnknownClaim: boolean;
- readonly isFailedToDecode: boolean;
- readonly isMaxWeightInvalid: boolean;
- readonly isNotHoldingFees: boolean;
- readonly isTooExpensive: boolean;
- readonly isTrap: boolean;
- readonly asTrap: u64;
- readonly isExpectationFalse: boolean;
- readonly isPalletNotFound: boolean;
- readonly isNameMismatch: boolean;
- readonly isVersionIncompatible: boolean;
- readonly isHoldingWouldOverflow: boolean;
- readonly isExportError: boolean;
- readonly isReanchorFailed: boolean;
- readonly isNoDeal: boolean;
- readonly isFeesNotMet: boolean;
- readonly isLockError: boolean;
- readonly isNoPermission: boolean;
- readonly isUnanchored: boolean;
- readonly isNotDepositable: boolean;
- readonly isUnhandledXcmVersion: boolean;
- readonly isWeightLimitReached: boolean;
- readonly asWeightLimitReached: SpWeightsWeightV2Weight;
- readonly isBarrier: boolean;
- readonly isWeightNotComputable: boolean;
- readonly isExceedsStackLimit: boolean;
- readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'LocationFull' | 'LocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'ExpectationFalse' | 'PalletNotFound' | 'NameMismatch' | 'VersionIncompatible' | 'HoldingWouldOverflow' | 'ExportError' | 'ReanchorFailed' | 'NoDeal' | 'FeesNotMet' | 'LockError' | 'NoPermission' | 'Unanchored' | 'NotDepositable' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable' | 'ExceedsStackLimit';
- }
-
- /** @name StagingXcmV3PalletInfo (247) */
- interface StagingXcmV3PalletInfo extends Struct {
- readonly index: Compact<u32>;
- readonly name: Bytes;
- readonly moduleName: Bytes;
- readonly major: Compact<u32>;
- readonly minor: Compact<u32>;
- readonly patch: Compact<u32>;
- }
-
- /** @name StagingXcmV3MaybeErrorCode (250) */
- interface StagingXcmV3MaybeErrorCode extends Enum {
- readonly isSuccess: boolean;
- readonly isError: boolean;
- readonly asError: Bytes;
- readonly isTruncatedError: boolean;
- readonly asTruncatedError: Bytes;
- readonly type: 'Success' | 'Error' | 'TruncatedError';
- }
-
- /** @name StagingXcmV3QueryResponseInfo (253) */
- interface StagingXcmV3QueryResponseInfo extends Struct {
- readonly destination: StagingXcmV3MultiLocation;
- readonly queryId: Compact<u64>;
- readonly maxWeight: SpWeightsWeightV2Weight;
- }
-
- /** @name StagingXcmV3MultiassetMultiAssetFilter (254) */
- interface StagingXcmV3MultiassetMultiAssetFilter extends Enum {
- readonly isDefinite: boolean;
- readonly asDefinite: StagingXcmV3MultiassetMultiAssets;
- readonly isWild: boolean;
- readonly asWild: StagingXcmV3MultiassetWildMultiAsset;
- readonly type: 'Definite' | 'Wild';
- }
-
- /** @name StagingXcmV3MultiassetWildMultiAsset (255) */
- interface StagingXcmV3MultiassetWildMultiAsset extends Enum {
- readonly isAll: boolean;
- readonly isAllOf: boolean;
- readonly asAllOf: {
- readonly id: StagingXcmV3MultiassetAssetId;
- readonly fun: StagingXcmV3MultiassetWildFungibility;
- } & Struct;
- readonly isAllCounted: boolean;
- readonly asAllCounted: Compact<u32>;
- readonly isAllOfCounted: boolean;
- readonly asAllOfCounted: {
- readonly id: StagingXcmV3MultiassetAssetId;
- readonly fun: StagingXcmV3MultiassetWildFungibility;
- readonly count: Compact<u32>;
- } & Struct;
- readonly type: 'All' | 'AllOf' | 'AllCounted' | 'AllOfCounted';
- }
-
- /** @name StagingXcmV3MultiassetWildFungibility (256) */
- interface StagingXcmV3MultiassetWildFungibility extends Enum {
- readonly isFungible: boolean;
- readonly isNonFungible: boolean;
- readonly type: 'Fungible' | 'NonFungible';
- }
-
- /** @name CumulusPalletXcmCall (265) */
- type CumulusPalletXcmCall = Null;
-
- /** @name CumulusPalletDmpQueueCall (266) */
- interface CumulusPalletDmpQueueCall extends Enum {
- readonly isServiceOverweight: boolean;
- readonly asServiceOverweight: {
- readonly index: u64;
- readonly weightLimit: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'ServiceOverweight';
- }
-
- /** @name PalletInflationCall (267) */
- interface PalletInflationCall extends Enum {
- readonly isStartInflation: boolean;
- readonly asStartInflation: {
- readonly inflationStartRelayBlock: u32;
- } & Struct;
- readonly type: 'StartInflation';
- }
-
- /** @name PalletUniqueCall (268) */
- interface PalletUniqueCall extends Enum {
- readonly isCreateCollection: boolean;
- readonly asCreateCollection: {
- readonly collectionName: Vec<u16>;
- readonly collectionDescription: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly mode: UpDataStructsCollectionMode;
- } & Struct;
- readonly isCreateCollectionEx: boolean;
- readonly asCreateCollectionEx: {
- readonly data: UpDataStructsCreateCollectionData;
- } & Struct;
- readonly isDestroyCollection: boolean;
- readonly asDestroyCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isAddToAllowList: boolean;
- readonly asAddToAllowList: {
- readonly collectionId: u32;
- readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isRemoveFromAllowList: boolean;
- readonly asRemoveFromAllowList: {
- readonly collectionId: u32;
- readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isChangeCollectionOwner: boolean;
- readonly asChangeCollectionOwner: {
- readonly collectionId: u32;
- readonly newOwner: AccountId32;
- } & Struct;
- readonly isAddCollectionAdmin: boolean;
- readonly asAddCollectionAdmin: {
- readonly collectionId: u32;
- readonly newAdminId: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isRemoveCollectionAdmin: boolean;
- readonly asRemoveCollectionAdmin: {
- readonly collectionId: u32;
- readonly accountId: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isSetCollectionSponsor: boolean;
- readonly asSetCollectionSponsor: {
- readonly collectionId: u32;
- readonly newSponsor: AccountId32;
- } & Struct;
- readonly isConfirmSponsorship: boolean;
- readonly asConfirmSponsorship: {
- readonly collectionId: u32;
- } & Struct;
- readonly isRemoveCollectionSponsor: boolean;
- readonly asRemoveCollectionSponsor: {
- readonly collectionId: u32;
- } & Struct;
- readonly isCreateItem: boolean;
- readonly asCreateItem: {
- readonly collectionId: u32;
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly data: UpDataStructsCreateItemData;
- } & Struct;
- readonly isCreateMultipleItems: boolean;
- readonly asCreateMultipleItems: {
- readonly collectionId: u32;
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly itemsData: Vec<UpDataStructsCreateItemData>;
- } & Struct;
- readonly isSetCollectionProperties: boolean;
- readonly asSetCollectionProperties: {
- readonly collectionId: u32;
- readonly properties: Vec<UpDataStructsProperty>;
- } & Struct;
- readonly isDeleteCollectionProperties: boolean;
- readonly asDeleteCollectionProperties: {
- readonly collectionId: u32;
- readonly propertyKeys: Vec<Bytes>;
- } & Struct;
- readonly isSetTokenProperties: boolean;
- readonly asSetTokenProperties: {
- readonly collectionId: u32;
- readonly tokenId: u32;
- readonly properties: Vec<UpDataStructsProperty>;
- } & Struct;
- readonly isDeleteTokenProperties: boolean;
- readonly asDeleteTokenProperties: {
- readonly collectionId: u32;
- readonly tokenId: u32;
- readonly propertyKeys: Vec<Bytes>;
- } & Struct;
- readonly isSetTokenPropertyPermissions: boolean;
- readonly asSetTokenPropertyPermissions: {
- readonly collectionId: u32;
- readonly propertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
- } & Struct;
- readonly isCreateMultipleItemsEx: boolean;
- readonly asCreateMultipleItemsEx: {
- readonly collectionId: u32;
- readonly data: UpDataStructsCreateItemExData;
- } & Struct;
- readonly isSetTransfersEnabledFlag: boolean;
- readonly asSetTransfersEnabledFlag: {
- readonly collectionId: u32;
- readonly value: bool;
- } & Struct;
- readonly isBurnItem: boolean;
- readonly asBurnItem: {
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isBurnFrom: boolean;
- readonly asBurnFrom: {
- readonly collectionId: u32;
- readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isTransfer: boolean;
- readonly asTransfer: {
- readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isApprove: boolean;
- readonly asApprove: {
- readonly spender: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly amount: u128;
- } & Struct;
- readonly isApproveFrom: boolean;
- readonly asApproveFrom: {
- readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly to: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly amount: u128;
- } & Struct;
- readonly isTransferFrom: boolean;
- readonly asTransferFrom: {
- readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly collectionId: u32;
- readonly itemId: u32;
- readonly value: u128;
- } & Struct;
- readonly isSetCollectionLimits: boolean;
- readonly asSetCollectionLimits: {
- readonly collectionId: u32;
- readonly newLimit: UpDataStructsCollectionLimits;
- } & Struct;
- readonly isSetCollectionPermissions: boolean;
- readonly asSetCollectionPermissions: {
- readonly collectionId: u32;
- readonly newPermission: UpDataStructsCollectionPermissions;
- } & Struct;
- readonly isRepartition: boolean;
- readonly asRepartition: {
- readonly collectionId: u32;
- readonly tokenId: u32;
- readonly amount: u128;
- } & Struct;
- readonly isSetAllowanceForAll: boolean;
- readonly asSetAllowanceForAll: {
- readonly collectionId: u32;
- readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly approve: bool;
- } & Struct;
- readonly isForceRepairCollection: boolean;
- readonly asForceRepairCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isForceRepairItem: boolean;
- readonly asForceRepairItem: {
- readonly collectionId: u32;
- readonly itemId: u32;
- } & Struct;
- readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'ApproveFrom' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem';
- }
-
- /** @name UpDataStructsCollectionMode (273) */
- interface UpDataStructsCollectionMode extends Enum {
- readonly isNft: boolean;
- readonly isFungible: boolean;
- readonly asFungible: u8;
- readonly isReFungible: boolean;
- readonly type: 'Nft' | 'Fungible' | 'ReFungible';
- }
-
- /** @name UpDataStructsCreateCollectionData (274) */
- interface UpDataStructsCreateCollectionData extends Struct {
- readonly mode: UpDataStructsCollectionMode;
- readonly access: Option<UpDataStructsAccessMode>;
- readonly name: Vec<u16>;
- readonly description: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly limits: Option<UpDataStructsCollectionLimits>;
- readonly permissions: Option<UpDataStructsCollectionPermissions>;
- readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
- readonly properties: Vec<UpDataStructsProperty>;
- readonly adminList: Vec<PalletEvmAccountBasicCrossAccountIdRepr>;
- readonly pendingSponsor: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
- readonly flags: U8aFixed;
- }
-
- /** @name PalletEvmAccountBasicCrossAccountIdRepr (275) */
- interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
- readonly isSubstrate: boolean;
- readonly asSubstrate: AccountId32;
- readonly isEthereum: boolean;
- readonly asEthereum: H160;
- readonly type: 'Substrate' | 'Ethereum';
- }
-
- /** @name UpDataStructsAccessMode (277) */
- interface UpDataStructsAccessMode extends Enum {
- readonly isNormal: boolean;
- readonly isAllowList: boolean;
- readonly type: 'Normal' | 'AllowList';
- }
-
- /** @name UpDataStructsCollectionLimits (279) */
- interface UpDataStructsCollectionLimits extends Struct {
- readonly accountTokenOwnershipLimit: Option<u32>;
- readonly sponsoredDataSize: Option<u32>;
- readonly sponsoredDataRateLimit: Option<UpDataStructsSponsoringRateLimit>;
- readonly tokenLimit: Option<u32>;
- readonly sponsorTransferTimeout: Option<u32>;
- readonly sponsorApproveTimeout: Option<u32>;
- readonly ownerCanTransfer: Option<bool>;
- readonly ownerCanDestroy: Option<bool>;
- readonly transfersEnabled: Option<bool>;
- }
-
- /** @name UpDataStructsSponsoringRateLimit (281) */
- interface UpDataStructsSponsoringRateLimit extends Enum {
- readonly isSponsoringDisabled: boolean;
- readonly isBlocks: boolean;
- readonly asBlocks: u32;
- readonly type: 'SponsoringDisabled' | 'Blocks';
- }
-
- /** @name UpDataStructsCollectionPermissions (284) */
- interface UpDataStructsCollectionPermissions extends Struct {
- readonly access: Option<UpDataStructsAccessMode>;
- readonly mintMode: Option<bool>;
- readonly nesting: Option<UpDataStructsNestingPermissions>;
- }
-
- /** @name UpDataStructsNestingPermissions (286) */
- interface UpDataStructsNestingPermissions extends Struct {
- readonly tokenOwner: bool;
- readonly collectionAdmin: bool;
- readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
- }
-
- /** @name UpDataStructsOwnerRestrictedSet (288) */
- interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
-
- /** @name UpDataStructsPropertyKeyPermission (294) */
- interface UpDataStructsPropertyKeyPermission extends Struct {
- readonly key: Bytes;
- readonly permission: UpDataStructsPropertyPermission;
- }
-
- /** @name UpDataStructsPropertyPermission (296) */
- interface UpDataStructsPropertyPermission extends Struct {
- readonly mutable: bool;
- readonly collectionAdmin: bool;
- readonly tokenOwner: bool;
- }
-
- /** @name UpDataStructsProperty (299) */
- interface UpDataStructsProperty extends Struct {
- readonly key: Bytes;
- readonly value: Bytes;
- }
-
- /** @name UpDataStructsCreateItemData (304) */
- interface UpDataStructsCreateItemData extends Enum {
- readonly isNft: boolean;
- readonly asNft: UpDataStructsCreateNftData;
- readonly isFungible: boolean;
- readonly asFungible: UpDataStructsCreateFungibleData;
- readonly isReFungible: boolean;
- readonly asReFungible: UpDataStructsCreateReFungibleData;
- readonly type: 'Nft' | 'Fungible' | 'ReFungible';
- }
-
- /** @name UpDataStructsCreateNftData (305) */
- interface UpDataStructsCreateNftData extends Struct {
- readonly properties: Vec<UpDataStructsProperty>;
- }
-
- /** @name UpDataStructsCreateFungibleData (306) */
- interface UpDataStructsCreateFungibleData extends Struct {
- readonly value: u128;
- }
-
- /** @name UpDataStructsCreateReFungibleData (307) */
- interface UpDataStructsCreateReFungibleData extends Struct {
- readonly pieces: u128;
- readonly properties: Vec<UpDataStructsProperty>;
- }
-
- /** @name UpDataStructsCreateItemExData (311) */
- interface UpDataStructsCreateItemExData extends Enum {
- readonly isNft: boolean;
- readonly asNft: Vec<UpDataStructsCreateNftExData>;
- readonly isFungible: boolean;
- readonly asFungible: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
- readonly isRefungibleMultipleItems: boolean;
- readonly asRefungibleMultipleItems: Vec<UpDataStructsCreateRefungibleExSingleOwner>;
- readonly isRefungibleMultipleOwners: boolean;
- readonly asRefungibleMultipleOwners: UpDataStructsCreateRefungibleExMultipleOwners;
- readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
- }
-
- /** @name UpDataStructsCreateNftExData (313) */
- interface UpDataStructsCreateNftExData extends Struct {
- readonly properties: Vec<UpDataStructsProperty>;
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
- }
-
- /** @name UpDataStructsCreateRefungibleExSingleOwner (320) */
- interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
- readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly pieces: u128;
- readonly properties: Vec<UpDataStructsProperty>;
- }
-
- /** @name UpDataStructsCreateRefungibleExMultipleOwners (322) */
- interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
- readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
- readonly properties: Vec<UpDataStructsProperty>;
- }
-
- /** @name PalletConfigurationCall (323) */
- interface PalletConfigurationCall extends Enum {
- readonly isSetWeightToFeeCoefficientOverride: boolean;
- readonly asSetWeightToFeeCoefficientOverride: {
- readonly coeff: Option<u64>;
- } & Struct;
- readonly isSetMinGasPriceOverride: boolean;
- readonly asSetMinGasPriceOverride: {
- readonly coeff: Option<u64>;
- } & Struct;
- readonly isSetAppPromotionConfigurationOverride: boolean;
- readonly asSetAppPromotionConfigurationOverride: {
- readonly configuration: PalletConfigurationAppPromotionConfiguration;
- } & Struct;
- readonly isSetCollatorSelectionDesiredCollators: boolean;
- readonly asSetCollatorSelectionDesiredCollators: {
- readonly max: Option<u32>;
- } & Struct;
- readonly isSetCollatorSelectionLicenseBond: boolean;
- readonly asSetCollatorSelectionLicenseBond: {
- readonly amount: Option<u128>;
- } & Struct;
- readonly isSetCollatorSelectionKickThreshold: boolean;
- readonly asSetCollatorSelectionKickThreshold: {
- readonly threshold: Option<u32>;
- } & Struct;
- readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride' | 'SetAppPromotionConfigurationOverride' | 'SetCollatorSelectionDesiredCollators' | 'SetCollatorSelectionLicenseBond' | 'SetCollatorSelectionKickThreshold';
- }
-
- /** @name PalletConfigurationAppPromotionConfiguration (325) */
- interface PalletConfigurationAppPromotionConfiguration extends Struct {
- readonly recalculationInterval: Option<u32>;
- readonly pendingInterval: Option<u32>;
- readonly intervalIncome: Option<Perbill>;
- readonly maxStakersPerCalculation: Option<u8>;
- }
-
- /** @name PalletStructureCall (330) */
- type PalletStructureCall = Null;
-
- /** @name PalletAppPromotionCall (331) */
- interface PalletAppPromotionCall extends Enum {
- readonly isSetAdminAddress: boolean;
- readonly asSetAdminAddress: {
- readonly admin: PalletEvmAccountBasicCrossAccountIdRepr;
- } & Struct;
- readonly isStake: boolean;
- readonly asStake: {
- readonly amount: u128;
- } & Struct;
- readonly isUnstakeAll: boolean;
- readonly isSponsorCollection: boolean;
- readonly asSponsorCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isStopSponsoringCollection: boolean;
- readonly asStopSponsoringCollection: {
- readonly collectionId: u32;
- } & Struct;
- readonly isSponsorContract: boolean;
- readonly asSponsorContract: {
- readonly contractId: H160;
- } & Struct;
- readonly isStopSponsoringContract: boolean;
- readonly asStopSponsoringContract: {
- readonly contractId: H160;
- } & Struct;
- readonly isPayoutStakers: boolean;
- readonly asPayoutStakers: {
- readonly stakersNumber: Option<u8>;
- } & Struct;
- readonly isUnstakePartial: boolean;
- readonly asUnstakePartial: {
- readonly amount: u128;
- } & Struct;
- readonly isForceUnstake: boolean;
- readonly asForceUnstake: {
- readonly pendingBlocks: Vec<u32>;
- } & Struct;
- readonly type: 'SetAdminAddress' | 'Stake' | 'UnstakeAll' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers' | 'UnstakePartial' | 'ForceUnstake';
- }
-
- /** @name PalletForeignAssetsModuleCall (333) */
- interface PalletForeignAssetsModuleCall extends Enum {
- readonly isRegisterForeignAsset: boolean;
- readonly asRegisterForeignAsset: {
- readonly owner: AccountId32;
- readonly location: StagingXcmVersionedMultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isUpdateForeignAsset: boolean;
- readonly asUpdateForeignAsset: {
- readonly foreignAssetId: u32;
- readonly location: StagingXcmVersionedMultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset';
- }
-
- /** @name PalletForeignAssetsModuleAssetMetadata (334) */
- interface PalletForeignAssetsModuleAssetMetadata extends Struct {
- readonly name: Bytes;
- readonly symbol: Bytes;
- readonly decimals: u8;
- readonly minimalBalance: u128;
- }
-
- /** @name PalletEvmCall (337) */
- interface PalletEvmCall extends Enum {
- readonly isWithdraw: boolean;
- readonly asWithdraw: {
- readonly address: H160;
- readonly value: u128;
- } & Struct;
- readonly isCall: boolean;
- readonly asCall: {
- readonly source: H160;
- readonly target: H160;
- readonly input: Bytes;
- readonly value: U256;
- readonly gasLimit: u64;
- readonly maxFeePerGas: U256;
- readonly maxPriorityFeePerGas: Option<U256>;
- readonly nonce: Option<U256>;
- readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
- } & Struct;
- readonly isCreate: boolean;
- readonly asCreate: {
- readonly source: H160;
- readonly init: Bytes;
- readonly value: U256;
- readonly gasLimit: u64;
- readonly maxFeePerGas: U256;
- readonly maxPriorityFeePerGas: Option<U256>;
- readonly nonce: Option<U256>;
- readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
- } & Struct;
- readonly isCreate2: boolean;
- readonly asCreate2: {
- readonly source: H160;
- readonly init: Bytes;
- readonly salt: H256;
- readonly value: U256;
- readonly gasLimit: u64;
- readonly maxFeePerGas: U256;
- readonly maxPriorityFeePerGas: Option<U256>;
- readonly nonce: Option<U256>;
- readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
- } & Struct;
- readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
- }
-
- /** @name PalletEthereumCall (344) */
- interface PalletEthereumCall extends Enum {
- readonly isTransact: boolean;
- readonly asTransact: {
- readonly transaction: EthereumTransactionTransactionV2;
- } & Struct;
- readonly type: 'Transact';
- }
-
- /** @name EthereumTransactionTransactionV2 (345) */
- interface EthereumTransactionTransactionV2 extends Enum {
- readonly isLegacy: boolean;
- readonly asLegacy: EthereumTransactionLegacyTransaction;
- readonly isEip2930: boolean;
- readonly asEip2930: EthereumTransactionEip2930Transaction;
- readonly isEip1559: boolean;
- readonly asEip1559: EthereumTransactionEip1559Transaction;
- readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
- }
-
- /** @name EthereumTransactionLegacyTransaction (346) */
- interface EthereumTransactionLegacyTransaction extends Struct {
- readonly nonce: U256;
- readonly gasPrice: U256;
- readonly gasLimit: U256;
- readonly action: EthereumTransactionTransactionAction;
- readonly value: U256;
- readonly input: Bytes;
- readonly signature: EthereumTransactionTransactionSignature;
- }
-
- /** @name EthereumTransactionTransactionAction (347) */
- interface EthereumTransactionTransactionAction extends Enum {
- readonly isCall: boolean;
- readonly asCall: H160;
- readonly isCreate: boolean;
- readonly type: 'Call' | 'Create';
- }
-
- /** @name EthereumTransactionTransactionSignature (348) */
- interface EthereumTransactionTransactionSignature extends Struct {
- readonly v: u64;
- readonly r: H256;
- readonly s: H256;
- }
-
- /** @name EthereumTransactionEip2930Transaction (350) */
- interface EthereumTransactionEip2930Transaction extends Struct {
- readonly chainId: u64;
- readonly nonce: U256;
- readonly gasPrice: U256;
- readonly gasLimit: U256;
- readonly action: EthereumTransactionTransactionAction;
- readonly value: U256;
- readonly input: Bytes;
- readonly accessList: Vec<EthereumTransactionAccessListItem>;
- readonly oddYParity: bool;
- readonly r: H256;
- readonly s: H256;
- }
-
- /** @name EthereumTransactionAccessListItem (352) */
- interface EthereumTransactionAccessListItem extends Struct {
- readonly address: H160;
- readonly storageKeys: Vec<H256>;
- }
-
- /** @name EthereumTransactionEip1559Transaction (353) */
- interface EthereumTransactionEip1559Transaction extends Struct {
- readonly chainId: u64;
- readonly nonce: U256;
- readonly maxPriorityFeePerGas: U256;
- readonly maxFeePerGas: U256;
- readonly gasLimit: U256;
- readonly action: EthereumTransactionTransactionAction;
- readonly value: U256;
- readonly input: Bytes;
- readonly accessList: Vec<EthereumTransactionAccessListItem>;
- readonly oddYParity: bool;
- readonly r: H256;
- readonly s: H256;
- }
-
- /** @name PalletEvmContractHelpersCall (354) */
- interface PalletEvmContractHelpersCall extends Enum {
- readonly isMigrateFromSelfSponsoring: boolean;
- readonly asMigrateFromSelfSponsoring: {
- readonly addresses: Vec<H160>;
- } & Struct;
- readonly type: 'MigrateFromSelfSponsoring';
- }
-
- /** @name PalletEvmMigrationCall (356) */
- interface PalletEvmMigrationCall extends Enum {
- readonly isBegin: boolean;
- readonly asBegin: {
- readonly address: H160;
- } & Struct;
- readonly isSetData: boolean;
- readonly asSetData: {
- readonly address: H160;
- readonly data: Vec<ITuple<[H256, H256]>>;
- } & Struct;
- readonly isFinish: boolean;
- readonly asFinish: {
- readonly address: H160;
- readonly code: Bytes;
- } & Struct;
- readonly isInsertEthLogs: boolean;
- readonly asInsertEthLogs: {
- readonly logs: Vec<EthereumLog>;
- } & Struct;
- readonly isInsertEvents: boolean;
- readonly asInsertEvents: {
- readonly events: Vec<Bytes>;
- } & Struct;
- readonly isRemoveRmrkData: boolean;
- readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents' | 'RemoveRmrkData';
- }
-
- /** @name EthereumLog (360) */
- interface EthereumLog extends Struct {
- readonly address: H160;
- readonly topics: Vec<H256>;
- readonly data: Bytes;
- }
-
- /** @name PalletMaintenanceCall (361) */
- interface PalletMaintenanceCall extends Enum {
- readonly isEnable: boolean;
- readonly isDisable: boolean;
- readonly type: 'Enable' | 'Disable';
- }
-
- /** @name PalletUtilityCall (362) */
- interface PalletUtilityCall extends Enum {
- readonly isBatch: boolean;
- readonly asBatch: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly isAsDerivative: boolean;
- readonly asAsDerivative: {
- readonly index: u16;
- readonly call: Call;
- } & Struct;
- readonly isBatchAll: boolean;
- readonly asBatchAll: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly isDispatchAs: boolean;
- readonly asDispatchAs: {
- readonly asOrigin: OpalRuntimeOriginCaller;
- readonly call: Call;
- } & Struct;
- readonly isForceBatch: boolean;
- readonly asForceBatch: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly isWithWeight: boolean;
- readonly asWithWeight: {
- readonly call: Call;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'Batch' | 'AsDerivative' | 'BatchAll' | 'DispatchAs' | 'ForceBatch' | 'WithWeight';
- }
-
- /** @name PalletTestUtilsCall (364) */
- interface PalletTestUtilsCall extends Enum {
- readonly isEnable: boolean;
- readonly isSetTestValue: boolean;
- readonly asSetTestValue: {
- readonly value: u32;
- } & Struct;
- readonly isSetTestValueAndRollback: boolean;
- readonly asSetTestValueAndRollback: {
- readonly value: u32;
- } & Struct;
- readonly isIncTestValue: boolean;
- readonly isJustTakeFee: boolean;
- readonly isBatchAll: boolean;
- readonly asBatchAll: {
- readonly calls: Vec<Call>;
- } & Struct;
- readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'JustTakeFee' | 'BatchAll';
- }
-
- /** @name PalletSchedulerEvent (366) */
- interface PalletSchedulerEvent extends Enum {
- readonly isScheduled: boolean;
- readonly asScheduled: {
- readonly when: u32;
- readonly index: u32;
- } & Struct;
- readonly isCanceled: boolean;
- readonly asCanceled: {
- readonly when: u32;
- readonly index: u32;
- } & Struct;
- readonly isDispatched: boolean;
- readonly asDispatched: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly isCallUnavailable: boolean;
- readonly asCallUnavailable: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- } & Struct;
- readonly isPeriodicFailed: boolean;
- readonly asPeriodicFailed: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- } & Struct;
- readonly isPermanentlyOverweight: boolean;
- readonly asPermanentlyOverweight: {
- readonly task: ITuple<[u32, u32]>;
- readonly id: Option<U8aFixed>;
- } & Struct;
- readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'CallUnavailable' | 'PeriodicFailed' | 'PermanentlyOverweight';
- }
-
- /** @name CumulusPalletXcmpQueueEvent (367) */
- interface CumulusPalletXcmpQueueEvent extends Enum {
- readonly isSuccess: boolean;
- readonly asSuccess: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isFail: boolean;
- readonly asFail: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly error: StagingXcmV3TraitsError;
- readonly weight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isBadVersion: boolean;
- readonly asBadVersion: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isBadFormat: boolean;
- readonly asBadFormat: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isXcmpMessageSent: boolean;
- readonly asXcmpMessageSent: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isOverweightEnqueued: boolean;
- readonly asOverweightEnqueued: {
- readonly sender: u32;
- readonly sentAt: u32;
- readonly index: u64;
- readonly required: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isOverweightServiced: boolean;
- readonly asOverweightServiced: {
- readonly index: u64;
- readonly used: SpWeightsWeightV2Weight;
- } & Struct;
- readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced';
- }
-
- /** @name PalletXcmEvent (368) */
- interface PalletXcmEvent extends Enum {
- readonly isAttempted: boolean;
- readonly asAttempted: {
- readonly outcome: StagingXcmV3TraitsOutcome;
- } & Struct;
- readonly isSent: boolean;
- readonly asSent: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly destination: StagingXcmV3MultiLocation;
- readonly message: StagingXcmV3Xcm;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isUnexpectedResponse: boolean;
- readonly asUnexpectedResponse: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isResponseReady: boolean;
- readonly asResponseReady: {
- readonly queryId: u64;
- readonly response: StagingXcmV3Response;
- } & Struct;
- readonly isNotified: boolean;
- readonly asNotified: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- } & Struct;
- readonly isNotifyOverweight: boolean;
- readonly asNotifyOverweight: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- readonly actualWeight: SpWeightsWeightV2Weight;
- readonly maxBudgetedWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isNotifyDispatchError: boolean;
- readonly asNotifyDispatchError: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- } & Struct;
- readonly isNotifyDecodeFailed: boolean;
- readonly asNotifyDecodeFailed: {
- readonly queryId: u64;
- readonly palletIndex: u8;
- readonly callIndex: u8;
- } & Struct;
- readonly isInvalidResponder: boolean;
- readonly asInvalidResponder: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- readonly expectedLocation: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly isInvalidResponderVersion: boolean;
- readonly asInvalidResponderVersion: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isResponseTaken: boolean;
- readonly asResponseTaken: {
- readonly queryId: u64;
- } & Struct;
- readonly isAssetsTrapped: boolean;
- readonly asAssetsTrapped: {
- readonly hash_: H256;
- readonly origin: StagingXcmV3MultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- } & Struct;
- readonly isVersionChangeNotified: boolean;
- readonly asVersionChangeNotified: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly result: u32;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isSupportedVersionChanged: boolean;
- readonly asSupportedVersionChanged: {
- readonly location: StagingXcmV3MultiLocation;
- readonly version: u32;
- } & Struct;
- readonly isNotifyTargetSendFail: boolean;
- readonly asNotifyTargetSendFail: {
- readonly location: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- readonly error: StagingXcmV3TraitsError;
- } & Struct;
- readonly isNotifyTargetMigrationFail: boolean;
- readonly asNotifyTargetMigrationFail: {
- readonly location: StagingXcmVersionedMultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isInvalidQuerierVersion: boolean;
- readonly asInvalidQuerierVersion: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- } & Struct;
- readonly isInvalidQuerier: boolean;
- readonly asInvalidQuerier: {
- readonly origin: StagingXcmV3MultiLocation;
- readonly queryId: u64;
- readonly expectedQuerier: StagingXcmV3MultiLocation;
- readonly maybeActualQuerier: Option<StagingXcmV3MultiLocation>;
- } & Struct;
- readonly isVersionNotifyStarted: boolean;
- readonly asVersionNotifyStarted: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isVersionNotifyRequested: boolean;
- readonly asVersionNotifyRequested: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isVersionNotifyUnrequested: boolean;
- readonly asVersionNotifyUnrequested: {
- readonly destination: StagingXcmV3MultiLocation;
- readonly cost: StagingXcmV3MultiassetMultiAssets;
- readonly messageId: U8aFixed;
- } & Struct;
- readonly isFeesPaid: boolean;
- readonly asFeesPaid: {
- readonly paying: StagingXcmV3MultiLocation;
- readonly fees: StagingXcmV3MultiassetMultiAssets;
- } & Struct;
- readonly isAssetsClaimed: boolean;
- readonly asAssetsClaimed: {
- readonly hash_: H256;
- readonly origin: StagingXcmV3MultiLocation;
- readonly assets: StagingXcmVersionedMultiAssets;
- } & Struct;
- readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail' | 'InvalidQuerierVersion' | 'InvalidQuerier' | 'VersionNotifyStarted' | 'VersionNotifyRequested' | 'VersionNotifyUnrequested' | 'FeesPaid' | 'AssetsClaimed';
- }
-
- /** @name StagingXcmV3TraitsOutcome (369) */
- interface StagingXcmV3TraitsOutcome extends Enum {
- readonly isComplete: boolean;
- readonly asComplete: SpWeightsWeightV2Weight;
- readonly isIncomplete: boolean;
- readonly asIncomplete: ITuple<[SpWeightsWeightV2Weight, StagingXcmV3TraitsError]>;
- readonly isError: boolean;
- readonly asError: StagingXcmV3TraitsError;
- readonly type: 'Complete' | 'Incomplete' | 'Error';
- }
-
- /** @name CumulusPalletXcmEvent (370) */
- interface CumulusPalletXcmEvent extends Enum {
- readonly isInvalidFormat: boolean;
- readonly asInvalidFormat: U8aFixed;
- readonly isUnsupportedVersion: boolean;
- readonly asUnsupportedVersion: U8aFixed;
- readonly isExecutedDownward: boolean;
- readonly asExecutedDownward: ITuple<[U8aFixed, StagingXcmV3TraitsOutcome]>;
- readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward';
- }
-
- /** @name CumulusPalletDmpQueueEvent (371) */
- interface CumulusPalletDmpQueueEvent extends Enum {
- readonly isInvalidFormat: boolean;
- readonly asInvalidFormat: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isUnsupportedVersion: boolean;
- readonly asUnsupportedVersion: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly isExecutedDownward: boolean;
- readonly asExecutedDownward: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly outcome: StagingXcmV3TraitsOutcome;
- } & Struct;
- readonly isWeightExhausted: boolean;
- readonly asWeightExhausted: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly remainingWeight: SpWeightsWeightV2Weight;
- readonly requiredWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isOverweightEnqueued: boolean;
- readonly asOverweightEnqueued: {
- readonly messageHash: U8aFixed;
- readonly messageId: U8aFixed;
- readonly overweightIndex: u64;
- readonly requiredWeight: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isOverweightServiced: boolean;
- readonly asOverweightServiced: {
- readonly overweightIndex: u64;
- readonly weightUsed: SpWeightsWeightV2Weight;
- } & Struct;
- readonly isMaxMessagesExhausted: boolean;
- readonly asMaxMessagesExhausted: {
- readonly messageHash: U8aFixed;
- } & Struct;
- readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced' | 'MaxMessagesExhausted';
- }
-
- /** @name PalletConfigurationEvent (372) */
- interface PalletConfigurationEvent extends Enum {
- readonly isNewDesiredCollators: boolean;
- readonly asNewDesiredCollators: {
- readonly desiredCollators: Option<u32>;
- } & Struct;
- readonly isNewCollatorLicenseBond: boolean;
- readonly asNewCollatorLicenseBond: {
- readonly bondCost: Option<u128>;
- } & Struct;
- readonly isNewCollatorKickThreshold: boolean;
- readonly asNewCollatorKickThreshold: {
- readonly lengthInBlocks: Option<u32>;
- } & Struct;
- readonly type: 'NewDesiredCollators' | 'NewCollatorLicenseBond' | 'NewCollatorKickThreshold';
- }
-
- /** @name PalletCommonEvent (373) */
- interface PalletCommonEvent extends Enum {
- readonly isCollectionCreated: boolean;
- readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
- readonly isCollectionDestroyed: boolean;
- readonly asCollectionDestroyed: u32;
- readonly isItemCreated: boolean;
- readonly asItemCreated: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isItemDestroyed: boolean;
- readonly asItemDestroyed: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isTransfer: boolean;
- readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isApproved: boolean;
- readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
- readonly isApprovedForAll: boolean;
- readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
- readonly isCollectionPropertySet: boolean;
- readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
- readonly isCollectionPropertyDeleted: boolean;
- readonly asCollectionPropertyDeleted: ITuple<[u32, Bytes]>;
- readonly isTokenPropertySet: boolean;
- readonly asTokenPropertySet: ITuple<[u32, u32, Bytes]>;
- readonly isTokenPropertyDeleted: boolean;
- readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
- readonly isPropertyPermissionSet: boolean;
- readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
- readonly isAllowListAddressAdded: boolean;
- readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isAllowListAddressRemoved: boolean;
- readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isCollectionAdminAdded: boolean;
- readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isCollectionAdminRemoved: boolean;
- readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
- readonly isCollectionLimitSet: boolean;
- readonly asCollectionLimitSet: u32;
- readonly isCollectionOwnerChanged: boolean;
- readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>;
- readonly isCollectionPermissionSet: boolean;
- readonly asCollectionPermissionSet: u32;
- readonly isCollectionSponsorSet: boolean;
- readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
- readonly isSponsorshipConfirmed: boolean;
- readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
- readonly isCollectionSponsorRemoved: boolean;
- readonly asCollectionSponsorRemoved: u32;
- readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved';
- }
-
- /** @name PalletStructureEvent (374) */
- interface PalletStructureEvent extends Enum {
- readonly isExecuted: boolean;
- readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
- readonly type: 'Executed';
- }
-
- /** @name PalletAppPromotionEvent (375) */
- interface PalletAppPromotionEvent extends Enum {
- readonly isStakingRecalculation: boolean;
- readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
- readonly isStake: boolean;
- readonly asStake: ITuple<[AccountId32, u128]>;
- readonly isUnstake: boolean;
- readonly asUnstake: ITuple<[AccountId32, u128]>;
- readonly isSetAdmin: boolean;
- readonly asSetAdmin: AccountId32;
- readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
- }
-
- /** @name PalletForeignAssetsModuleEvent (376) */
- interface PalletForeignAssetsModuleEvent extends Enum {
- readonly isForeignAssetRegistered: boolean;
- readonly asForeignAssetRegistered: {
- readonly assetId: u32;
- readonly assetAddress: StagingXcmV3MultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isForeignAssetUpdated: boolean;
- readonly asForeignAssetUpdated: {
- readonly assetId: u32;
- readonly assetAddress: StagingXcmV3MultiLocation;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isAssetRegistered: boolean;
- readonly asAssetRegistered: {
- readonly assetId: PalletForeignAssetsAssetId;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly isAssetUpdated: boolean;
- readonly asAssetUpdated: {
- readonly assetId: PalletForeignAssetsAssetId;
- readonly metadata: PalletForeignAssetsModuleAssetMetadata;
- } & Struct;
- readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated';
- }
-
- /** @name PalletEvmEvent (377) */
- interface PalletEvmEvent extends Enum {
- readonly isLog: boolean;
- readonly asLog: {
- readonly log: EthereumLog;
- } & Struct;
- readonly isCreated: boolean;
- readonly asCreated: {
- readonly address: H160;
- } & Struct;
- readonly isCreatedFailed: boolean;
- readonly asCreatedFailed: {
- readonly address: H160;
- } & Struct;
- readonly isExecuted: boolean;
- readonly asExecuted: {
- readonly address: H160;
- } & Struct;
- readonly isExecutedFailed: boolean;
- readonly asExecutedFailed: {
- readonly address: H160;
- } & Struct;
- readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
- }
-
- /** @name PalletEthereumEvent (378) */
- interface PalletEthereumEvent extends Enum {
- readonly isExecuted: boolean;
- readonly asExecuted: {
- readonly from: H160;
- readonly to: H160;
- readonly transactionHash: H256;
- readonly exitReason: EvmCoreErrorExitReason;
- readonly extraData: Bytes;
- } & Struct;
- readonly type: 'Executed';
- }
-
- /** @name EvmCoreErrorExitReason (379) */
- interface EvmCoreErrorExitReason extends Enum {
- readonly isSucceed: boolean;
- readonly asSucceed: EvmCoreErrorExitSucceed;
- readonly isError: boolean;
- readonly asError: EvmCoreErrorExitError;
- readonly isRevert: boolean;
- readonly asRevert: EvmCoreErrorExitRevert;
- readonly isFatal: boolean;
- readonly asFatal: EvmCoreErrorExitFatal;
- readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
- }
-
- /** @name EvmCoreErrorExitSucceed (380) */
- interface EvmCoreErrorExitSucceed extends Enum {
- readonly isStopped: boolean;
- readonly isReturned: boolean;
- readonly isSuicided: boolean;
- readonly type: 'Stopped' | 'Returned' | 'Suicided';
- }
-
- /** @name EvmCoreErrorExitError (381) */
- interface EvmCoreErrorExitError extends Enum {
- readonly isStackUnderflow: boolean;
- readonly isStackOverflow: boolean;
- readonly isInvalidJump: boolean;
- readonly isInvalidRange: boolean;
- readonly isDesignatedInvalid: boolean;
- readonly isCallTooDeep: boolean;
- readonly isCreateCollision: boolean;
- readonly isCreateContractLimit: boolean;
- readonly isOutOfOffset: boolean;
- readonly isOutOfGas: boolean;
- readonly isOutOfFund: boolean;
- readonly isPcUnderflow: boolean;
- readonly isCreateEmpty: boolean;
- readonly isOther: boolean;
- readonly asOther: Text;
- readonly isMaxNonce: boolean;
- readonly isInvalidCode: boolean;
- readonly asInvalidCode: u8;
- readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'MaxNonce' | 'InvalidCode';
- }
-
- /** @name EvmCoreErrorExitRevert (385) */
- interface EvmCoreErrorExitRevert extends Enum {
- readonly isReverted: boolean;
- readonly type: 'Reverted';
- }
-
- /** @name EvmCoreErrorExitFatal (386) */
- interface EvmCoreErrorExitFatal extends Enum {
- readonly isNotSupported: boolean;
- readonly isUnhandledInterrupt: boolean;
- readonly isCallErrorAsFatal: boolean;
- readonly asCallErrorAsFatal: EvmCoreErrorExitError;
- readonly isOther: boolean;
- readonly asOther: Text;
- readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
- }
-
- /** @name PalletEvmContractHelpersEvent (387) */
- interface PalletEvmContractHelpersEvent extends Enum {
- readonly isContractSponsorSet: boolean;
- readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
- readonly isContractSponsorshipConfirmed: boolean;
- readonly asContractSponsorshipConfirmed: ITuple<[H160, AccountId32]>;
- readonly isContractSponsorRemoved: boolean;
- readonly asContractSponsorRemoved: H160;
- readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
- }
-
- /** @name PalletEvmMigrationEvent (388) */
- interface PalletEvmMigrationEvent extends Enum {
- readonly isTestEvent: boolean;
- readonly type: 'TestEvent';
- }
-
- /** @name PalletMaintenanceEvent (389) */
- interface PalletMaintenanceEvent extends Enum {
- readonly isMaintenanceEnabled: boolean;
- readonly isMaintenanceDisabled: boolean;
- readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled';
- }
-
- /** @name PalletUtilityEvent (390) */
- interface PalletUtilityEvent extends Enum {
- readonly isBatchInterrupted: boolean;
- readonly asBatchInterrupted: {
- readonly index: u32;
- readonly error: SpRuntimeDispatchError;
- } & Struct;
- readonly isBatchCompleted: boolean;
- readonly isBatchCompletedWithErrors: boolean;
- readonly isItemCompleted: boolean;
- readonly isItemFailed: boolean;
- readonly asItemFailed: {
- readonly error: SpRuntimeDispatchError;
- } & Struct;
- readonly isDispatchedAs: boolean;
- readonly asDispatchedAs: {
- readonly result: Result<Null, SpRuntimeDispatchError>;
- } & Struct;
- readonly type: 'BatchInterrupted' | 'BatchCompleted' | 'BatchCompletedWithErrors' | 'ItemCompleted' | 'ItemFailed' | 'DispatchedAs';
- }
-
- /** @name PalletTestUtilsEvent (391) */
- interface PalletTestUtilsEvent extends Enum {
- readonly isValueIsSet: boolean;
- readonly isShouldRollback: boolean;
- readonly isBatchCompleted: boolean;
- readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
- }
-
- /** @name FrameSystemPhase (392) */
- interface FrameSystemPhase extends Enum {
- readonly isApplyExtrinsic: boolean;
- readonly asApplyExtrinsic: u32;
- readonly isFinalization: boolean;
- readonly isInitialization: boolean;
- readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
- }
-
- /** @name FrameSystemLastRuntimeUpgradeInfo (394) */
- interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
- readonly specVersion: Compact<u32>;
- readonly specName: Text;
- }
-
- /** @name FrameSystemLimitsBlockWeights (395) */
- interface FrameSystemLimitsBlockWeights extends Struct {
- readonly baseBlock: SpWeightsWeightV2Weight;
- readonly maxBlock: SpWeightsWeightV2Weight;
- readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
- }
-
- /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (396) */
- interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct {
- readonly normal: FrameSystemLimitsWeightsPerClass;
- readonly operational: FrameSystemLimitsWeightsPerClass;
- readonly mandatory: FrameSystemLimitsWeightsPerClass;
- }
-
- /** @name FrameSystemLimitsWeightsPerClass (397) */
- interface FrameSystemLimitsWeightsPerClass extends Struct {
- readonly baseExtrinsic: SpWeightsWeightV2Weight;
- readonly maxExtrinsic: Option<SpWeightsWeightV2Weight>;
- readonly maxTotal: Option<SpWeightsWeightV2Weight>;
- readonly reserved: Option<SpWeightsWeightV2Weight>;
- }
-
- /** @name FrameSystemLimitsBlockLength (399) */
- interface FrameSystemLimitsBlockLength extends Struct {
- readonly max: FrameSupportDispatchPerDispatchClassU32;
- }
-
- /** @name FrameSupportDispatchPerDispatchClassU32 (400) */
- interface FrameSupportDispatchPerDispatchClassU32 extends Struct {
- readonly normal: u32;
- readonly operational: u32;
- readonly mandatory: u32;
- }
-
- /** @name SpWeightsRuntimeDbWeight (401) */
- interface SpWeightsRuntimeDbWeight extends Struct {
- readonly read: u64;
- readonly write: u64;
- }
-
- /** @name SpVersionRuntimeVersion (402) */
- interface SpVersionRuntimeVersion extends Struct {
- readonly specName: Text;
- readonly implName: Text;
- readonly authoringVersion: u32;
- readonly specVersion: u32;
- readonly implVersion: u32;
- readonly apis: Vec<ITuple<[U8aFixed, u32]>>;
- readonly transactionVersion: u32;
- readonly stateVersion: u8;
- }
-
- /** @name FrameSystemError (406) */
- interface FrameSystemError extends Enum {
- readonly isInvalidSpecName: boolean;
- readonly isSpecVersionNeedsToIncrease: boolean;
- readonly isFailedToExtractRuntimeVersion: boolean;
- readonly isNonDefaultComposite: boolean;
- readonly isNonZeroRefCount: boolean;
- readonly isCallFiltered: boolean;
- readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
- }
-
- /** @name CumulusPalletParachainSystemUnincludedSegmentAncestor (408) */
- interface CumulusPalletParachainSystemUnincludedSegmentAncestor extends Struct {
- readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
- readonly paraHeadHash: Option<H256>;
- readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
- }
-
- /** @name CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth (409) */
- interface CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth extends Struct {
- readonly umpMsgCount: u32;
- readonly umpTotalBytes: u32;
- readonly hrmpOutgoing: BTreeMap<u32, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate>;
- }
-
- /** @name CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate (411) */
- interface CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate extends Struct {
- readonly msgCount: u32;
- readonly totalBytes: u32;
- }
-
- /** @name PolkadotPrimitivesV5UpgradeGoAhead (415) */
- interface PolkadotPrimitivesV5UpgradeGoAhead extends Enum {
- readonly isAbort: boolean;
- readonly isGoAhead: boolean;
- readonly type: 'Abort' | 'GoAhead';
- }
-
- /** @name CumulusPalletParachainSystemUnincludedSegmentSegmentTracker (416) */
- interface CumulusPalletParachainSystemUnincludedSegmentSegmentTracker extends Struct {
- readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
- readonly hrmpWatermark: Option<u32>;
- readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
- }
-
- /** @name PolkadotPrimitivesV5UpgradeRestriction (418) */
- interface PolkadotPrimitivesV5UpgradeRestriction extends Enum {
- readonly isPresent: boolean;
- readonly type: 'Present';
- }
-
- /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (419) */
- interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
- readonly dmqMqcHead: H256;
- readonly relayDispatchQueueRemainingCapacity: CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity;
- readonly ingressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
- readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
- }
-
- /** @name CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity (420) */
- interface CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity extends Struct {
- readonly remainingCount: u32;
- readonly remainingSize: u32;
- }
-
- /** @name PolkadotPrimitivesV5AbridgedHrmpChannel (423) */
- interface PolkadotPrimitivesV5AbridgedHrmpChannel extends Struct {
- readonly maxCapacity: u32;
- readonly maxTotalSize: u32;
- readonly maxMessageSize: u32;
- readonly msgCount: u32;
- readonly totalSize: u32;
- readonly mqcHead: Option<H256>;
- }
-
- /** @name PolkadotPrimitivesV5AbridgedHostConfiguration (424) */
- interface PolkadotPrimitivesV5AbridgedHostConfiguration extends Struct {
- readonly maxCodeSize: u32;
- readonly maxHeadDataSize: u32;
- readonly maxUpwardQueueCount: u32;
- readonly maxUpwardQueueSize: u32;
- readonly maxUpwardMessageSize: u32;
- readonly maxUpwardMessageNumPerCandidate: u32;
- readonly hrmpMaxMessageNumPerCandidate: u32;
- readonly validationUpgradeCooldown: u32;
- readonly validationUpgradeDelay: u32;
- readonly asyncBackingParams: PolkadotPrimitivesVstagingAsyncBackingParams;
- }
-
- /** @name PolkadotPrimitivesVstagingAsyncBackingParams (425) */
- interface PolkadotPrimitivesVstagingAsyncBackingParams extends Struct {
- readonly maxCandidateDepth: u32;
- readonly allowedAncestryLen: u32;
- }
-
- /** @name PolkadotCorePrimitivesOutboundHrmpMessage (431) */
- interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
- readonly recipient: u32;
- readonly data: Bytes;
- }
-
- /** @name CumulusPalletParachainSystemCodeUpgradeAuthorization (432) */
- interface CumulusPalletParachainSystemCodeUpgradeAuthorization extends Struct {
- readonly codeHash: H256;
- readonly checkVersion: bool;
- }
-
- /** @name CumulusPalletParachainSystemError (433) */
- interface CumulusPalletParachainSystemError extends Enum {
- readonly isOverlappingUpgrades: boolean;
- readonly isProhibitedByPolkadot: boolean;
- readonly isTooBig: boolean;
- readonly isValidationDataNotAvailable: boolean;
- readonly isHostConfigurationNotAvailable: boolean;
- readonly isNotScheduled: boolean;
- readonly isNothingAuthorized: boolean;
- readonly isUnauthorized: boolean;
- readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
- }
-
- /** @name PalletCollatorSelectionError (435) */
- interface PalletCollatorSelectionError extends Enum {
- readonly isTooManyCandidates: boolean;
- readonly isUnknown: boolean;
- readonly isPermission: boolean;
- readonly isAlreadyHoldingLicense: boolean;
- readonly isNoLicense: boolean;
- readonly isAlreadyCandidate: boolean;
- readonly isNotCandidate: boolean;
- readonly isTooManyInvulnerables: boolean;
- readonly isTooFewInvulnerables: boolean;
- readonly isAlreadyInvulnerable: boolean;
- readonly isNotInvulnerable: boolean;
- readonly isNoAssociatedValidatorId: boolean;
- readonly isValidatorNotRegistered: boolean;
- readonly type: 'TooManyCandidates' | 'Unknown' | 'Permission' | 'AlreadyHoldingLicense' | 'NoLicense' | 'AlreadyCandidate' | 'NotCandidate' | 'TooManyInvulnerables' | 'TooFewInvulnerables' | 'AlreadyInvulnerable' | 'NotInvulnerable' | 'NoAssociatedValidatorId' | 'ValidatorNotRegistered';
- }
-
- /** @name SpCoreCryptoKeyTypeId (439) */
- interface SpCoreCryptoKeyTypeId extends U8aFixed {}
-
- /** @name PalletSessionError (440) */
- interface PalletSessionError extends Enum {
- readonly isInvalidProof: boolean;
- readonly isNoAssociatedValidatorId: boolean;
- readonly isDuplicatedKey: boolean;
- readonly isNoKeys: boolean;
- readonly isNoAccount: boolean;
- readonly type: 'InvalidProof' | 'NoAssociatedValidatorId' | 'DuplicatedKey' | 'NoKeys' | 'NoAccount';
- }
-
- /** @name PalletBalancesBalanceLock (446) */
- interface PalletBalancesBalanceLock extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
- readonly reasons: PalletBalancesReasons;
- }
-
- /** @name PalletBalancesReasons (447) */
- interface PalletBalancesReasons extends Enum {
- readonly isFee: boolean;
- readonly isMisc: boolean;
- readonly isAll: boolean;
- readonly type: 'Fee' | 'Misc' | 'All';
- }
-
- /** @name PalletBalancesReserveData (450) */
- interface PalletBalancesReserveData extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
- }
-
- /** @name OpalRuntimeRuntimeHoldReason (454) */
- interface OpalRuntimeRuntimeHoldReason extends Enum {
- readonly isCollatorSelection: boolean;
- readonly asCollatorSelection: PalletCollatorSelectionHoldReason;
- readonly type: 'CollatorSelection';
- }
-
- /** @name PalletCollatorSelectionHoldReason (455) */
- interface PalletCollatorSelectionHoldReason extends Enum {
- readonly isLicenseBond: boolean;
- readonly type: 'LicenseBond';
- }
-
- /** @name PalletBalancesIdAmount (458) */
- interface PalletBalancesIdAmount extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
- }
-
- /** @name PalletBalancesError (460) */
- interface PalletBalancesError extends Enum {
- readonly isVestingBalance: boolean;
- readonly isLiquidityRestrictions: boolean;
- readonly isInsufficientBalance: boolean;
- readonly isExistentialDeposit: boolean;
- readonly isExpendability: boolean;
- readonly isExistingVestingSchedule: boolean;
- readonly isDeadAccount: boolean;
- readonly isTooManyReserves: boolean;
- readonly isTooManyHolds: boolean;
- readonly isTooManyFreezes: boolean;
- readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'Expendability' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves' | 'TooManyHolds' | 'TooManyFreezes';
- }
-
- /** @name PalletTransactionPaymentReleases (462) */
- interface PalletTransactionPaymentReleases extends Enum {
- readonly isV1Ancient: boolean;
- readonly isV2: boolean;
- readonly type: 'V1Ancient' | 'V2';
- }
-
- /** @name PalletTreasuryProposal (463) */
- interface PalletTreasuryProposal extends Struct {
- readonly proposer: AccountId32;
- readonly value: u128;
- readonly beneficiary: AccountId32;
- readonly bond: u128;
- }
-
- /** @name FrameSupportPalletId (466) */
- interface FrameSupportPalletId extends U8aFixed {}
-
- /** @name PalletTreasuryError (467) */
- interface PalletTreasuryError extends Enum {
- readonly isInsufficientProposersBalance: boolean;
- readonly isInvalidIndex: boolean;
- readonly isTooManyApprovals: boolean;
- readonly isInsufficientPermission: boolean;
- readonly isProposalNotApproved: boolean;
- readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
- }
-
- /** @name PalletSudoError (468) */
- interface PalletSudoError extends Enum {
- readonly isRequireSudo: boolean;
- readonly type: 'RequireSudo';
- }
-
- /** @name OrmlVestingModuleError (470) */
- interface OrmlVestingModuleError extends Enum {
- readonly isZeroVestingPeriod: boolean;
- readonly isZeroVestingPeriodCount: boolean;
- readonly isInsufficientBalanceToLock: boolean;
- readonly isTooManyVestingSchedules: boolean;
- readonly isAmountLow: boolean;
- readonly isMaxVestingSchedulesExceeded: boolean;
- readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
- }
-
- /** @name OrmlXtokensModuleError (471) */
- interface OrmlXtokensModuleError extends Enum {
- readonly isAssetHasNoReserve: boolean;
- readonly isNotCrossChainTransfer: boolean;
- readonly isInvalidDest: boolean;
- readonly isNotCrossChainTransferableCurrency: boolean;
- readonly isUnweighableMessage: boolean;
- readonly isXcmExecutionFailed: boolean;
- readonly isCannotReanchor: boolean;
- readonly isInvalidAncestry: boolean;
- readonly isInvalidAsset: boolean;
- readonly isDestinationNotInvertible: boolean;
- readonly isBadVersion: boolean;
- readonly isDistinctReserveForAssetAndFee: boolean;
- readonly isZeroFee: boolean;
- readonly isZeroAmount: boolean;
- readonly isTooManyAssetsBeingSent: boolean;
- readonly isAssetIndexNonExistent: boolean;
- readonly isFeeNotEnough: boolean;
- readonly isNotSupportedMultiLocation: boolean;
- readonly isMinXcmFeeNotDefined: boolean;
- readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined';
- }
-
- /** @name OrmlTokensBalanceLock (474) */
- interface OrmlTokensBalanceLock extends Struct {
- readonly id: U8aFixed;
- readonly amount: u128;
- }
-
- /** @name OrmlTokensAccountData (476) */
- interface OrmlTokensAccountData extends Struct {
- readonly free: u128;
- readonly reserved: u128;
- readonly frozen: u128;
- }
-
- /** @name OrmlTokensReserveData (478) */
- interface OrmlTokensReserveData extends Struct {
- readonly id: Null;
- readonly amount: u128;
- }
-
- /** @name OrmlTokensModuleError (480) */
- interface OrmlTokensModuleError extends Enum {
- readonly isBalanceTooLow: boolean;
- readonly isAmountIntoBalanceFailed: boolean;
- readonly isLiquidityRestrictions: boolean;
- readonly isMaxLocksExceeded: boolean;
- readonly isKeepAlive: boolean;
- readonly isExistentialDeposit: boolean;
- readonly isDeadAccount: boolean;
- readonly isTooManyReserves: boolean;
- readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves';
- }
-
- /** @name PalletIdentityRegistrarInfo (485) */
- interface PalletIdentityRegistrarInfo extends Struct {
- readonly account: AccountId32;
- readonly fee: u128;
- readonly fields: PalletIdentityBitFlags;
- }
-
- /** @name PalletIdentityError (487) */
- interface PalletIdentityError extends Enum {
- readonly isTooManySubAccounts: boolean;
- readonly isNotFound: boolean;
- readonly isNotNamed: boolean;
- readonly isEmptyIndex: boolean;
- readonly isFeeChanged: boolean;
- readonly isNoIdentity: boolean;
- readonly isStickyJudgement: boolean;
- readonly isJudgementGiven: boolean;
- readonly isInvalidJudgement: boolean;
- readonly isInvalidIndex: boolean;
- readonly isInvalidTarget: boolean;
- readonly isTooManyFields: boolean;
- readonly isTooManyRegistrars: boolean;
- readonly isAlreadyClaimed: boolean;
- readonly isNotSub: boolean;
- readonly isNotOwned: boolean;
- readonly isJudgementForDifferentIdentity: boolean;
- readonly isJudgementPaymentFailed: boolean;
- readonly type: 'TooManySubAccounts' | 'NotFound' | 'NotNamed' | 'EmptyIndex' | 'FeeChanged' | 'NoIdentity' | 'StickyJudgement' | 'JudgementGiven' | 'InvalidJudgement' | 'InvalidIndex' | 'InvalidTarget' | 'TooManyFields' | 'TooManyRegistrars' | 'AlreadyClaimed' | 'NotSub' | 'NotOwned' | 'JudgementForDifferentIdentity' | 'JudgementPaymentFailed';
- }
-
- /** @name PalletPreimageRequestStatus (488) */
- interface PalletPreimageRequestStatus extends Enum {
- readonly isUnrequested: boolean;
- readonly asUnrequested: {
- readonly deposit: ITuple<[AccountId32, u128]>;
- readonly len: u32;
- } & Struct;
- readonly isRequested: boolean;
- readonly asRequested: {
- readonly deposit: Option<ITuple<[AccountId32, u128]>>;
- readonly count: u32;
- readonly len: Option<u32>;
- } & Struct;
- readonly type: 'Unrequested' | 'Requested';
- }
-
- /** @name PalletPreimageError (493) */
- interface PalletPreimageError extends Enum {
- readonly isTooBig: boolean;
- readonly isAlreadyNoted: boolean;
- readonly isNotAuthorized: boolean;
- readonly isNotNoted: boolean;
- readonly isRequested: boolean;
- readonly isNotRequested: boolean;
- readonly type: 'TooBig' | 'AlreadyNoted' | 'NotAuthorized' | 'NotNoted' | 'Requested' | 'NotRequested';
- }
-
- /** @name PalletDemocracyReferendumInfo (499) */
- interface PalletDemocracyReferendumInfo extends Enum {
- readonly isOngoing: boolean;
- readonly asOngoing: PalletDemocracyReferendumStatus;
- readonly isFinished: boolean;
- readonly asFinished: {
- readonly approved: bool;
- readonly end: u32;
- } & Struct;
- readonly type: 'Ongoing' | 'Finished';
- }
-
- /** @name PalletDemocracyReferendumStatus (500) */
- interface PalletDemocracyReferendumStatus extends Struct {
- readonly end: u32;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly threshold: PalletDemocracyVoteThreshold;
- readonly delay: u32;
- readonly tally: PalletDemocracyTally;
- }
-
- /** @name PalletDemocracyTally (501) */
- interface PalletDemocracyTally extends Struct {
- readonly ayes: u128;
- readonly nays: u128;
- readonly turnout: u128;
- }
-
- /** @name PalletDemocracyVoteVoting (502) */
- interface PalletDemocracyVoteVoting extends Enum {
- readonly isDirect: boolean;
- readonly asDirect: {
- readonly votes: Vec<ITuple<[u32, PalletDemocracyVoteAccountVote]>>;
- readonly delegations: PalletDemocracyDelegations;
- readonly prior: PalletDemocracyVotePriorLock;
- } & Struct;
- readonly isDelegating: boolean;
- readonly asDelegating: {
- readonly balance: u128;
- readonly target: AccountId32;
- readonly conviction: PalletDemocracyConviction;
- readonly delegations: PalletDemocracyDelegations;
- readonly prior: PalletDemocracyVotePriorLock;
- } & Struct;
- readonly type: 'Direct' | 'Delegating';
- }
-
- /** @name PalletDemocracyDelegations (506) */
- interface PalletDemocracyDelegations extends Struct {
- readonly votes: u128;
- readonly capital: u128;
- }
-
- /** @name PalletDemocracyVotePriorLock (507) */
- interface PalletDemocracyVotePriorLock extends ITuple<[u32, u128]> {}
-
- /** @name PalletDemocracyError (510) */
- interface PalletDemocracyError extends Enum {
- readonly isValueLow: boolean;
- readonly isProposalMissing: boolean;
- readonly isAlreadyCanceled: boolean;
- readonly isDuplicateProposal: boolean;
- readonly isProposalBlacklisted: boolean;
- readonly isNotSimpleMajority: boolean;
- readonly isInvalidHash: boolean;
- readonly isNoProposal: boolean;
- readonly isAlreadyVetoed: boolean;
- readonly isReferendumInvalid: boolean;
- readonly isNoneWaiting: boolean;
- readonly isNotVoter: boolean;
- readonly isNoPermission: boolean;
- readonly isAlreadyDelegating: boolean;
- readonly isInsufficientFunds: boolean;
- readonly isNotDelegating: boolean;
- readonly isVotesExist: boolean;
- readonly isInstantNotAllowed: boolean;
- readonly isNonsense: boolean;
- readonly isWrongUpperBound: boolean;
- readonly isMaxVotesReached: boolean;
- readonly isTooMany: boolean;
- readonly isVotingPeriodLow: boolean;
- readonly isPreimageNotExist: boolean;
- readonly type: 'ValueLow' | 'ProposalMissing' | 'AlreadyCanceled' | 'DuplicateProposal' | 'ProposalBlacklisted' | 'NotSimpleMajority' | 'InvalidHash' | 'NoProposal' | 'AlreadyVetoed' | 'ReferendumInvalid' | 'NoneWaiting' | 'NotVoter' | 'NoPermission' | 'AlreadyDelegating' | 'InsufficientFunds' | 'NotDelegating' | 'VotesExist' | 'InstantNotAllowed' | 'Nonsense' | 'WrongUpperBound' | 'MaxVotesReached' | 'TooMany' | 'VotingPeriodLow' | 'PreimageNotExist';
- }
-
- /** @name PalletCollectiveVotes (512) */
- interface PalletCollectiveVotes extends Struct {
- readonly index: u32;
- readonly threshold: u32;
- readonly ayes: Vec<AccountId32>;
- readonly nays: Vec<AccountId32>;
- readonly end: u32;
- }
-
- /** @name PalletCollectiveError (513) */
- interface PalletCollectiveError extends Enum {
- readonly isNotMember: boolean;
- readonly isDuplicateProposal: boolean;
- readonly isProposalMissing: boolean;
- readonly isWrongIndex: boolean;
- readonly isDuplicateVote: boolean;
- readonly isAlreadyInitialized: boolean;
- readonly isTooEarly: boolean;
- readonly isTooManyProposals: boolean;
- readonly isWrongProposalWeight: boolean;
- readonly isWrongProposalLength: boolean;
- readonly isPrimeAccountNotMember: boolean;
- readonly type: 'NotMember' | 'DuplicateProposal' | 'ProposalMissing' | 'WrongIndex' | 'DuplicateVote' | 'AlreadyInitialized' | 'TooEarly' | 'TooManyProposals' | 'WrongProposalWeight' | 'WrongProposalLength' | 'PrimeAccountNotMember';
- }
-
- /** @name PalletMembershipError (517) */
- interface PalletMembershipError extends Enum {
- readonly isAlreadyMember: boolean;
- readonly isNotMember: boolean;
- readonly isTooManyMembers: boolean;
- readonly type: 'AlreadyMember' | 'NotMember' | 'TooManyMembers';
- }
-
- /** @name PalletRankedCollectiveMemberRecord (520) */
- interface PalletRankedCollectiveMemberRecord extends Struct {
- readonly rank: u16;
- }
-
- /** @name PalletRankedCollectiveError (525) */
- interface PalletRankedCollectiveError extends Enum {
- readonly isAlreadyMember: boolean;
- readonly isNotMember: boolean;
- readonly isNotPolling: boolean;
- readonly isOngoing: boolean;
- readonly isNoneRemaining: boolean;
- readonly isCorruption: boolean;
- readonly isRankTooLow: boolean;
- readonly isInvalidWitness: boolean;
- readonly isNoPermission: boolean;
- readonly type: 'AlreadyMember' | 'NotMember' | 'NotPolling' | 'Ongoing' | 'NoneRemaining' | 'Corruption' | 'RankTooLow' | 'InvalidWitness' | 'NoPermission';
- }
-
- /** @name PalletReferendaReferendumInfo (526) */
- interface PalletReferendaReferendumInfo extends Enum {
- readonly isOngoing: boolean;
- readonly asOngoing: PalletReferendaReferendumStatus;
- readonly isApproved: boolean;
- readonly asApproved: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isRejected: boolean;
- readonly asRejected: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isCancelled: boolean;
- readonly asCancelled: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isTimedOut: boolean;
- readonly asTimedOut: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
- readonly isKilled: boolean;
- readonly asKilled: u32;
- readonly type: 'Ongoing' | 'Approved' | 'Rejected' | 'Cancelled' | 'TimedOut' | 'Killed';
- }
-
- /** @name PalletReferendaReferendumStatus (527) */
- interface PalletReferendaReferendumStatus extends Struct {
- readonly track: u16;
- readonly origin: OpalRuntimeOriginCaller;
- readonly proposal: FrameSupportPreimagesBounded;
- readonly enactment: FrameSupportScheduleDispatchTime;
- readonly submitted: u32;
- readonly submissionDeposit: PalletReferendaDeposit;
- readonly decisionDeposit: Option<PalletReferendaDeposit>;
- readonly deciding: Option<PalletReferendaDecidingStatus>;
- readonly tally: PalletRankedCollectiveTally;
- readonly inQueue: bool;
- readonly alarm: Option<ITuple<[u32, ITuple<[u32, u32]>]>>;
- }
-
- /** @name PalletReferendaDeposit (528) */
- interface PalletReferendaDeposit extends Struct {
- readonly who: AccountId32;
- readonly amount: u128;
- }
-
- /** @name PalletReferendaDecidingStatus (531) */
- interface PalletReferendaDecidingStatus extends Struct {
- readonly since: u32;
- readonly confirming: Option<u32>;
- }
-
- /** @name PalletReferendaTrackInfo (537) */
- interface PalletReferendaTrackInfo extends Struct {
- readonly name: Text;
- readonly maxDeciding: u32;
- readonly decisionDeposit: u128;
- readonly preparePeriod: u32;
- readonly decisionPeriod: u32;
- readonly confirmPeriod: u32;
- readonly minEnactmentPeriod: u32;
- readonly minApproval: PalletReferendaCurve;
- readonly minSupport: PalletReferendaCurve;
- }
-
- /** @name PalletReferendaCurve (538) */
- interface PalletReferendaCurve extends Enum {
- readonly isLinearDecreasing: boolean;
- readonly asLinearDecreasing: {
- readonly length: Perbill;
- readonly floor: Perbill;
- readonly ceil: Perbill;
- } & Struct;
- readonly isSteppedDecreasing: boolean;
- readonly asSteppedDecreasing: {
- readonly begin: Perbill;
- readonly end: Perbill;
- readonly step: Perbill;
- readonly period: Perbill;
- } & Struct;
- readonly isReciprocal: boolean;
- readonly asReciprocal: {
- readonly factor: i64;
- readonly xOffset: i64;
- readonly yOffset: i64;
- } & Struct;
- readonly type: 'LinearDecreasing' | 'SteppedDecreasing' | 'Reciprocal';
- }
-
- /** @name PalletReferendaError (541) */
- interface PalletReferendaError extends Enum {
- readonly isNotOngoing: boolean;
- readonly isHasDeposit: boolean;
- readonly isBadTrack: boolean;
- readonly isFull: boolean;
- readonly isQueueEmpty: boolean;
- readonly isBadReferendum: boolean;
- readonly isNothingToDo: boolean;
- readonly isNoTrack: boolean;
- readonly isUnfinished: boolean;
- readonly isNoPermission: boolean;
- readonly isNoDeposit: boolean;
- readonly isBadStatus: boolean;
- readonly isPreimageNotExist: boolean;
- readonly type: 'NotOngoing' | 'HasDeposit' | 'BadTrack' | 'Full' | 'QueueEmpty' | 'BadReferendum' | 'NothingToDo' | 'NoTrack' | 'Unfinished' | 'NoPermission' | 'NoDeposit' | 'BadStatus' | 'PreimageNotExist';
- }
-
- /** @name PalletSchedulerScheduled (544) */
- interface PalletSchedulerScheduled extends Struct {
- readonly maybeId: Option<U8aFixed>;
- readonly priority: u8;
- readonly call: FrameSupportPreimagesBounded;
- readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
- readonly origin: OpalRuntimeOriginCaller;
- }
-
- /** @name PalletSchedulerError (546) */
- interface PalletSchedulerError extends Enum {
- readonly isFailedToSchedule: boolean;
- readonly isNotFound: boolean;
- readonly isTargetBlockNumberInPast: boolean;
- readonly isRescheduleNoChange: boolean;
- readonly isNamed: boolean;
- readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange' | 'Named';
- }
-
- /** @name CumulusPalletXcmpQueueInboundChannelDetails (548) */
- interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
- readonly sender: u32;
- readonly state: CumulusPalletXcmpQueueInboundState;
- readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat]>>;
- }
-
- /** @name CumulusPalletXcmpQueueInboundState (549) */
- interface CumulusPalletXcmpQueueInboundState extends Enum {
- readonly isOk: boolean;
- readonly isSuspended: boolean;
- readonly type: 'Ok' | 'Suspended';
- }
-
- /** @name PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat (552) */
- interface PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat extends Enum {
- readonly isConcatenatedVersionedXcm: boolean;
- readonly isConcatenatedEncodedBlob: boolean;
- readonly isSignals: boolean;
- readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
- }
-
- /** @name CumulusPalletXcmpQueueOutboundChannelDetails (555) */
- interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
- readonly recipient: u32;
- readonly state: CumulusPalletXcmpQueueOutboundState;
- readonly signalsExist: bool;
- readonly firstIndex: u16;
- readonly lastIndex: u16;
- }
-
- /** @name CumulusPalletXcmpQueueOutboundState (556) */
- interface CumulusPalletXcmpQueueOutboundState extends Enum {
- readonly isOk: boolean;
- readonly isSuspended: boolean;
- readonly type: 'Ok' | 'Suspended';
- }
-
- /** @name CumulusPalletXcmpQueueQueueConfigData (558) */
- interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
- readonly suspendThreshold: u32;
- readonly dropThreshold: u32;
- readonly resumeThreshold: u32;
- readonly thresholdWeight: SpWeightsWeightV2Weight;
- readonly weightRestrictDecay: SpWeightsWeightV2Weight;
- readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight;
- }
-
- /** @name CumulusPalletXcmpQueueError (560) */
- interface CumulusPalletXcmpQueueError extends Enum {
- readonly isFailedToSend: boolean;
- readonly isBadXcmOrigin: boolean;
- readonly isBadXcm: boolean;
- readonly isBadOverweightIndex: boolean;
- readonly isWeightOverLimit: boolean;
- readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
- }
-
- /** @name PalletXcmQueryStatus (561) */
- interface PalletXcmQueryStatus extends Enum {
- readonly isPending: boolean;
- readonly asPending: {
- readonly responder: StagingXcmVersionedMultiLocation;
- readonly maybeMatchQuerier: Option<StagingXcmVersionedMultiLocation>;
- readonly maybeNotify: Option<ITuple<[u8, u8]>>;
- readonly timeout: u32;
- } & Struct;
- readonly isVersionNotifier: boolean;
- readonly asVersionNotifier: {
- readonly origin: StagingXcmVersionedMultiLocation;
- readonly isActive: bool;
- } & Struct;
- readonly isReady: boolean;
- readonly asReady: {
- readonly response: StagingXcmVersionedResponse;
- readonly at: u32;
- } & Struct;
- readonly type: 'Pending' | 'VersionNotifier' | 'Ready';
- }
-
- /** @name StagingXcmVersionedResponse (565) */
- interface StagingXcmVersionedResponse extends Enum {
- readonly isV2: boolean;
- readonly asV2: StagingXcmV2Response;
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3Response;
- readonly type: 'V2' | 'V3';
- }
-
- /** @name PalletXcmVersionMigrationStage (571) */
- interface PalletXcmVersionMigrationStage extends Enum {
- readonly isMigrateSupportedVersion: boolean;
- readonly isMigrateVersionNotifiers: boolean;
- readonly isNotifyCurrentTargets: boolean;
- readonly asNotifyCurrentTargets: Option<Bytes>;
- readonly isMigrateAndNotifyOldTargets: boolean;
- readonly type: 'MigrateSupportedVersion' | 'MigrateVersionNotifiers' | 'NotifyCurrentTargets' | 'MigrateAndNotifyOldTargets';
- }
-
- /** @name StagingXcmVersionedAssetId (574) */
- interface StagingXcmVersionedAssetId extends Enum {
- readonly isV3: boolean;
- readonly asV3: StagingXcmV3MultiassetAssetId;
- readonly type: 'V3';
- }
-
- /** @name PalletXcmRemoteLockedFungibleRecord (575) */
- interface PalletXcmRemoteLockedFungibleRecord extends Struct {
- readonly amount: u128;
- readonly owner: StagingXcmVersionedMultiLocation;
- readonly locker: StagingXcmVersionedMultiLocation;
- readonly consumers: Vec<ITuple<[Null, u128]>>;
- }
-
- /** @name PalletXcmError (582) */
- interface PalletXcmError extends Enum {
- readonly isUnreachable: boolean;
- readonly isSendFailure: boolean;
- readonly isFiltered: boolean;
- readonly isUnweighableMessage: boolean;
- readonly isDestinationNotInvertible: boolean;
- readonly isEmpty: boolean;
- readonly isCannotReanchor: boolean;
- readonly isTooManyAssets: boolean;
- readonly isInvalidOrigin: boolean;
- readonly isBadVersion: boolean;
- readonly isBadLocation: boolean;
- readonly isNoSubscription: boolean;
- readonly isAlreadySubscribed: boolean;
- readonly isInvalidAsset: boolean;
- readonly isLowBalance: boolean;
- readonly isTooManyLocks: boolean;
- readonly isAccountNotSovereign: boolean;
- readonly isFeesNotMet: boolean;
- readonly isLockNotFound: boolean;
- readonly isInUse: boolean;
- readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed' | 'InvalidAsset' | 'LowBalance' | 'TooManyLocks' | 'AccountNotSovereign' | 'FeesNotMet' | 'LockNotFound' | 'InUse';
- }
-
- /** @name CumulusPalletXcmError (583) */
- type CumulusPalletXcmError = Null;
-
- /** @name CumulusPalletDmpQueueConfigData (584) */
- interface CumulusPalletDmpQueueConfigData extends Struct {
- readonly maxIndividual: SpWeightsWeightV2Weight;
- }
-
- /** @name CumulusPalletDmpQueuePageIndexData (585) */
- interface CumulusPalletDmpQueuePageIndexData extends Struct {
- readonly beginUsed: u32;
- readonly endUsed: u32;
- readonly overweightCount: u64;
- }
-
- /** @name CumulusPalletDmpQueueError (588) */
- interface CumulusPalletDmpQueueError extends Enum {
- readonly isUnknown: boolean;
- readonly isOverLimit: boolean;
- readonly type: 'Unknown' | 'OverLimit';
- }
-
- /** @name PalletUniqueError (592) */
- interface PalletUniqueError extends Enum {
- readonly isCollectionDecimalPointLimitExceeded: boolean;
- readonly isEmptyArgument: boolean;
- readonly isRepartitionCalledOnNonRefungibleCollection: boolean;
- readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
- }
-
- /** @name PalletConfigurationError (593) */
- interface PalletConfigurationError extends Enum {
- readonly isInconsistentConfiguration: boolean;
- readonly type: 'InconsistentConfiguration';
- }
-
- /** @name UpDataStructsCollection (594) */
- interface UpDataStructsCollection extends Struct {
- readonly owner: AccountId32;
- readonly mode: UpDataStructsCollectionMode;
- readonly name: Vec<u16>;
- readonly description: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
- readonly limits: UpDataStructsCollectionLimits;
- readonly permissions: UpDataStructsCollectionPermissions;
- readonly flags: U8aFixed;
- }
-
- /** @name UpDataStructsSponsorshipStateAccountId32 (595) */
- interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
- readonly isDisabled: boolean;
- readonly isUnconfirmed: boolean;
- readonly asUnconfirmed: AccountId32;
- readonly isConfirmed: boolean;
- readonly asConfirmed: AccountId32;
- readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
- }
-
- /** @name UpDataStructsProperties (596) */
- interface UpDataStructsProperties extends Struct {
- readonly map: UpDataStructsPropertiesMapBoundedVec;
- readonly consumedSpace: u32;
- readonly reserved: u32;
- }
-
- /** @name UpDataStructsPropertiesMapBoundedVec (597) */
- interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
-
- /** @name UpDataStructsPropertiesMapPropertyPermission (602) */
- interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
-
- /** @name UpDataStructsCollectionStats (609) */
- interface UpDataStructsCollectionStats extends Struct {
- readonly created: u32;
- readonly destroyed: u32;
- readonly alive: u32;
- }
-
- /** @name UpDataStructsTokenChild (610) */
- interface UpDataStructsTokenChild extends Struct {
- readonly token: u32;
- readonly collection: u32;
- }
-
- /** @name PhantomTypeUpDataStructs (611) */
- interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, UpPovEstimateRpcPovInfo]>> {}
-
- /** @name UpDataStructsTokenData (613) */
- interface UpDataStructsTokenData extends Struct {
- readonly properties: Vec<UpDataStructsProperty>;
- readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
- readonly pieces: u128;
- }
-
- /** @name UpDataStructsRpcCollection (614) */
- interface UpDataStructsRpcCollection extends Struct {
- readonly owner: AccountId32;
- readonly mode: UpDataStructsCollectionMode;
- readonly name: Vec<u16>;
- readonly description: Vec<u16>;
- readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
- readonly limits: UpDataStructsCollectionLimits;
- readonly permissions: UpDataStructsCollectionPermissions;
- readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
- readonly properties: Vec<UpDataStructsProperty>;
- readonly readOnly: bool;
- readonly flags: UpDataStructsRpcCollectionFlags;
- }
-
- /** @name UpDataStructsRpcCollectionFlags (615) */
- interface UpDataStructsRpcCollectionFlags extends Struct {
- readonly foreign: bool;
- readonly erc721metadata: bool;
- }
-
- /** @name UpPovEstimateRpcPovInfo (616) */
- interface UpPovEstimateRpcPovInfo extends Struct {
- readonly proofSize: u64;
- readonly compactProofSize: u64;
- readonly compressedProofSize: u64;
- readonly results: Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>;
- readonly keyValues: Vec<UpPovEstimateRpcTrieKeyValue>;
- }
-
- /** @name SpRuntimeTransactionValidityTransactionValidityError (619) */
- interface SpRuntimeTransactionValidityTransactionValidityError extends Enum {
- readonly isInvalid: boolean;
- readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction;
- readonly isUnknown: boolean;
- readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction;
- readonly type: 'Invalid' | 'Unknown';
- }
-
- /** @name SpRuntimeTransactionValidityInvalidTransaction (620) */
- interface SpRuntimeTransactionValidityInvalidTransaction extends Enum {
- readonly isCall: boolean;
- readonly isPayment: boolean;
- readonly isFuture: boolean;
- readonly isStale: boolean;
- readonly isBadProof: boolean;
- readonly isAncientBirthBlock: boolean;
- readonly isExhaustsResources: boolean;
- readonly isCustom: boolean;
- readonly asCustom: u8;
- readonly isBadMandatory: boolean;
- readonly isMandatoryValidation: boolean;
- readonly isBadSigner: boolean;
- readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner';
- }
-
- /** @name SpRuntimeTransactionValidityUnknownTransaction (621) */
- interface SpRuntimeTransactionValidityUnknownTransaction extends Enum {
- readonly isCannotLookup: boolean;
- readonly isNoUnsignedValidator: boolean;
- readonly isCustom: boolean;
- readonly asCustom: u8;
- readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom';
- }
-
- /** @name UpPovEstimateRpcTrieKeyValue (623) */
- interface UpPovEstimateRpcTrieKeyValue extends Struct {
- readonly key: Bytes;
- readonly value: Bytes;
- }
-
- /** @name PalletCommonError (625) */
- interface PalletCommonError extends Enum {
- readonly isCollectionNotFound: boolean;
- readonly isMustBeTokenOwner: boolean;
- readonly isNoPermission: boolean;
- readonly isCantDestroyNotEmptyCollection: boolean;
- readonly isPublicMintingNotAllowed: boolean;
- readonly isAddressNotInAllowlist: boolean;
- readonly isCollectionNameLimitExceeded: boolean;
- readonly isCollectionDescriptionLimitExceeded: boolean;
- readonly isCollectionTokenPrefixLimitExceeded: boolean;
- readonly isTotalCollectionsLimitExceeded: boolean;
- readonly isCollectionAdminCountExceeded: boolean;
- readonly isCollectionLimitBoundsExceeded: boolean;
- readonly isOwnerPermissionsCantBeReverted: boolean;
- readonly isTransferNotAllowed: boolean;
- readonly isAccountTokenLimitExceeded: boolean;
- readonly isCollectionTokenLimitExceeded: boolean;
- readonly isMetadataFlagFrozen: boolean;
- readonly isTokenNotFound: boolean;
- readonly isTokenValueTooLow: boolean;
- readonly isApprovedValueTooLow: boolean;
- readonly isCantApproveMoreThanOwned: boolean;
- readonly isAddressIsNotEthMirror: boolean;
- readonly isAddressIsZero: boolean;
- readonly isUnsupportedOperation: boolean;
- readonly isNotSufficientFounds: boolean;
- readonly isUserIsNotAllowedToNest: boolean;
- readonly isSourceCollectionIsNotAllowedToNest: boolean;
- readonly isCollectionFieldSizeExceeded: boolean;
- readonly isNoSpaceForProperty: boolean;
- readonly isPropertyLimitReached: boolean;
- readonly isPropertyKeyIsTooLong: boolean;
- readonly isInvalidCharacterInPropertyKey: boolean;
- readonly isEmptyPropertyKey: boolean;
- readonly isCollectionIsExternal: boolean;
- readonly isCollectionIsInternal: boolean;
- readonly isConfirmSponsorshipFail: boolean;
- readonly isUserIsNotCollectionAdmin: boolean;
- readonly isFungibleItemsHaveNoId: boolean;
- readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsNotEthMirror' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin' | 'FungibleItemsHaveNoId';
- }
-
- /** @name PalletFungibleError (627) */
- interface PalletFungibleError extends Enum {
- readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
- readonly isFungibleItemsDontHaveData: boolean;
- readonly isFungibleDisallowsNesting: boolean;
- readonly isSettingPropertiesNotAllowed: boolean;
- readonly isSettingAllowanceForAllNotAllowed: boolean;
- readonly isFungibleTokensAreAlwaysValid: boolean;
- readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid';
- }
-
- /** @name PalletRefungibleError (632) */
- interface PalletRefungibleError extends Enum {
- readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
- readonly isWrongRefungiblePieces: boolean;
- readonly isRepartitionWhileNotOwningAllPieces: boolean;
- readonly isRefungibleDisallowsNesting: boolean;
- readonly isSettingPropertiesNotAllowed: boolean;
- readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
- }
-
- /** @name PalletNonfungibleItemData (633) */
- interface PalletNonfungibleItemData extends Struct {
- readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
- }
-
- /** @name UpDataStructsPropertyScope (635) */
- interface UpDataStructsPropertyScope extends Enum {
- readonly isNone: boolean;
- readonly isRmrk: boolean;
- readonly type: 'None' | 'Rmrk';
- }
-
- /** @name PalletNonfungibleError (638) */
- interface PalletNonfungibleError extends Enum {
- readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
- readonly isNonfungibleItemsHaveNoAmount: boolean;
- readonly isCantBurnNftWithChildren: boolean;
- readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
- }
-
- /** @name PalletStructureError (639) */
- interface PalletStructureError extends Enum {
- readonly isOuroborosDetected: boolean;
- readonly isDepthLimit: boolean;
- readonly isBreadthLimit: boolean;
- readonly isTokenNotFound: boolean;
- readonly isCantNestTokenUnderCollection: boolean;
- readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound' | 'CantNestTokenUnderCollection';
- }
-
- /** @name PalletAppPromotionError (644) */
- interface PalletAppPromotionError extends Enum {
- readonly isAdminNotSet: boolean;
- readonly isNoPermission: boolean;
- readonly isNotSufficientFunds: boolean;
- readonly isPendingForBlockOverflow: boolean;
- readonly isSponsorNotSet: boolean;
- readonly isInsufficientStakedBalance: boolean;
- readonly isInconsistencyState: boolean;
- readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'InsufficientStakedBalance' | 'InconsistencyState';
- }
-
- /** @name PalletForeignAssetsModuleError (645) */
- interface PalletForeignAssetsModuleError extends Enum {
- readonly isBadLocation: boolean;
- readonly isMultiLocationExisted: boolean;
- readonly isAssetIdNotExists: boolean;
- readonly isAssetIdExisted: boolean;
- readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
- }
-
- /** @name PalletEvmCodeMetadata (646) */
- interface PalletEvmCodeMetadata extends Struct {
- readonly size_: u64;
- readonly hash_: H256;
- }
-
- /** @name PalletEvmError (648) */
- interface PalletEvmError extends Enum {
- readonly isBalanceLow: boolean;
- readonly isFeeOverflow: boolean;
- readonly isPaymentOverflow: boolean;
- readonly isWithdrawFailed: boolean;
- readonly isGasPriceTooLow: boolean;
- readonly isInvalidNonce: boolean;
- readonly isGasLimitTooLow: boolean;
- readonly isGasLimitTooHigh: boolean;
- readonly isUndefined: boolean;
- readonly isReentrancy: boolean;
- readonly isTransactionMustComeFromEOA: boolean;
- readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA';
- }
-
- /** @name FpRpcTransactionStatus (651) */
- interface FpRpcTransactionStatus extends Struct {
- readonly transactionHash: H256;
- readonly transactionIndex: u32;
- readonly from: H160;
- readonly to: Option<H160>;
- readonly contractAddress: Option<H160>;
- readonly logs: Vec<EthereumLog>;
- readonly logsBloom: EthbloomBloom;
- }
-
- /** @name EthbloomBloom (653) */
- interface EthbloomBloom extends U8aFixed {}
-
- /** @name EthereumReceiptReceiptV3 (655) */
- interface EthereumReceiptReceiptV3 extends Enum {
- readonly isLegacy: boolean;
- readonly asLegacy: EthereumReceiptEip658ReceiptData;
- readonly isEip2930: boolean;
- readonly asEip2930: EthereumReceiptEip658ReceiptData;
- readonly isEip1559: boolean;
- readonly asEip1559: EthereumReceiptEip658ReceiptData;
- readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
- }
-
- /** @name EthereumReceiptEip658ReceiptData (656) */
- interface EthereumReceiptEip658ReceiptData extends Struct {
- readonly statusCode: u8;
- readonly usedGas: U256;
- readonly logsBloom: EthbloomBloom;
- readonly logs: Vec<EthereumLog>;
- }
-
- /** @name EthereumBlock (657) */
- interface EthereumBlock extends Struct {
- readonly header: EthereumHeader;
- readonly transactions: Vec<EthereumTransactionTransactionV2>;
- readonly ommers: Vec<EthereumHeader>;
- }
-
- /** @name EthereumHeader (658) */
- interface EthereumHeader extends Struct {
- readonly parentHash: H256;
- readonly ommersHash: H256;
- readonly beneficiary: H160;
- readonly stateRoot: H256;
- readonly transactionsRoot: H256;
- readonly receiptsRoot: H256;
- readonly logsBloom: EthbloomBloom;
- readonly difficulty: U256;
- readonly number: U256;
- readonly gasLimit: U256;
- readonly gasUsed: U256;
- readonly timestamp: u64;
- readonly extraData: Bytes;
- readonly mixHash: H256;
- readonly nonce: EthereumTypesHashH64;
- }
-
- /** @name EthereumTypesHashH64 (659) */
- interface EthereumTypesHashH64 extends U8aFixed {}
-
- /** @name PalletEthereumError (664) */
- interface PalletEthereumError extends Enum {
- readonly isInvalidSignature: boolean;
- readonly isPreLogExists: boolean;
- readonly type: 'InvalidSignature' | 'PreLogExists';
- }
-
- /** @name PalletEvmCoderSubstrateError (665) */
- interface PalletEvmCoderSubstrateError extends Enum {
- readonly isOutOfGas: boolean;
- readonly isOutOfFund: boolean;
- readonly type: 'OutOfGas' | 'OutOfFund';
- }
-
- /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (666) */
- interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
- readonly isDisabled: boolean;
- readonly isUnconfirmed: boolean;
- readonly asUnconfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly isConfirmed: boolean;
- readonly asConfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
- readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
- }
-
- /** @name PalletEvmContractHelpersSponsoringModeT (667) */
- interface PalletEvmContractHelpersSponsoringModeT extends Enum {
- readonly isDisabled: boolean;
- readonly isAllowlisted: boolean;
- readonly isGenerous: boolean;
- readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
- }
-
- /** @name PalletEvmContractHelpersError (673) */
- interface PalletEvmContractHelpersError extends Enum {
- readonly isNoPermission: boolean;
- readonly isNoPendingSponsor: boolean;
- readonly isTooManyMethodsHaveSponsoredLimit: boolean;
- readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
- }
-
- /** @name PalletEvmMigrationError (674) */
- interface PalletEvmMigrationError extends Enum {
- readonly isAccountNotEmpty: boolean;
- readonly isAccountIsNotMigrating: boolean;
- readonly isBadEvent: boolean;
- readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
- }
-
- /** @name PalletMaintenanceError (675) */
- type PalletMaintenanceError = Null;
-
- /** @name PalletUtilityError (676) */
- interface PalletUtilityError extends Enum {
- readonly isTooManyCalls: boolean;
- readonly type: 'TooManyCalls';
- }
-
- /** @name PalletTestUtilsError (677) */
- interface PalletTestUtilsError extends Enum {
- readonly isTestPalletDisabled: boolean;
- readonly isTriggerRollback: boolean;
- readonly type: 'TestPalletDisabled' | 'TriggerRollback';
- }
-
- /** @name SpRuntimeMultiSignature (679) */
- interface SpRuntimeMultiSignature extends Enum {
- readonly isEd25519: boolean;
- readonly asEd25519: SpCoreEd25519Signature;
- readonly isSr25519: boolean;
- readonly asSr25519: SpCoreSr25519Signature;
- readonly isEcdsa: boolean;
- readonly asEcdsa: SpCoreEcdsaSignature;
- readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
- }
-
- /** @name SpCoreEd25519Signature (680) */
- interface SpCoreEd25519Signature extends U8aFixed {}
-
- /** @name SpCoreSr25519Signature (682) */
- interface SpCoreSr25519Signature extends U8aFixed {}
-
- /** @name SpCoreEcdsaSignature (683) */
- interface SpCoreEcdsaSignature extends U8aFixed {}
-
- /** @name FrameSystemExtensionsCheckSpecVersion (686) */
- type FrameSystemExtensionsCheckSpecVersion = Null;
-
- /** @name FrameSystemExtensionsCheckTxVersion (687) */
- type FrameSystemExtensionsCheckTxVersion = Null;
-
- /** @name FrameSystemExtensionsCheckGenesis (688) */
- type FrameSystemExtensionsCheckGenesis = Null;
-
- /** @name FrameSystemExtensionsCheckNonce (691) */
- interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
-
- /** @name FrameSystemExtensionsCheckWeight (692) */
- type FrameSystemExtensionsCheckWeight = Null;
-
- /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (693) */
- type OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance = Null;
-
- /** @name OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls (694) */
- type OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls = Null;
-
- /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (695) */
- interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
-
- /** @name OpalRuntimeRuntime (696) */
- type OpalRuntimeRuntime = Null;
-
- /** @name PalletEthereumFakeTransactionFinalizer (697) */
- type PalletEthereumFakeTransactionFinalizer = Null;
-
-} // declare module
js-packages/types/src/types.tsdiffbeforeafterboth--- a/js-packages/types/src/types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './appPromotion/types.js';
-export * from './default/types.js';
-export * from './povinfo/types.js';
-export * from './unique/types.js';
js-packages/types/src/unique/definitions.tsdiffbeforeafterboth--- a/js-packages/types/src/unique/definitions.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-type RpcParam = {
- name: string;
- type: string;
- isOptional?: true;
-};
-
-const CROSS_ACCOUNT_ID_TYPE = 'PalletEvmAccountBasicCrossAccountIdRepr';
-
-const collectionParam = {name: 'collection', type: 'u32'};
-const tokenParam = {name: 'tokenId', type: 'u32'};
-const propertyKeysParam = {name: 'propertyKeys', type: 'Option<Vec<String>>', isOptional: true};
-const crossAccountParam = (name = 'account') => ({name, type: CROSS_ACCOUNT_ID_TYPE});
-const atParam = {name: 'at', type: 'Hash', isOptional: true};
-
-const fun = (description: string, params: RpcParam[], type: string) => ({
- description,
- params: [...params, atParam],
- type,
-});
-
-export default {
- types: {},
- rpc: {
- accountTokens: fun(
- 'Get tokens owned by an account in a collection',
- [collectionParam, crossAccountParam()],
- 'Vec<u32>',
- ),
- collectionTokens: fun(
- 'Get tokens contained within a collection',
- [collectionParam],
- 'Vec<u32>',
- ),
- tokenExists: fun(
- 'Check if the token exists',
- [collectionParam, tokenParam],
- 'bool',
- ),
-
- tokenOwner: fun(
- 'Get the token owner',
- [collectionParam, tokenParam],
- `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
- ),
- topmostTokenOwner: fun(
- 'Get the topmost token owner in the hierarchy of a possibly nested token',
- [collectionParam, tokenParam],
- `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
- ),
- tokenOwners: fun(
- 'Returns 10 tokens owners in no particular order',
- [collectionParam, tokenParam],
- `Vec<${CROSS_ACCOUNT_ID_TYPE}>`,
- ),
- tokenChildren: fun(
- 'Get tokens nested directly into the token',
- [collectionParam, tokenParam],
- 'Vec<UpDataStructsTokenChild>',
- ),
-
- collectionProperties: fun(
- 'Get collection properties, optionally limited to the provided keys',
- [collectionParam, propertyKeysParam],
- 'Vec<UpDataStructsProperty>',
- ),
- tokenProperties: fun(
- 'Get token properties, optionally limited to the provided keys',
- [collectionParam, tokenParam, propertyKeysParam],
- 'Vec<UpDataStructsProperty>',
- ),
- propertyPermissions: fun(
- 'Get property permissions, optionally limited to the provided keys',
- [collectionParam, propertyKeysParam],
- 'Vec<UpDataStructsPropertyKeyPermission>',
- ),
-
- constMetadata: fun(
- 'Get token constant metadata',
- [collectionParam, tokenParam],
- 'Vec<u8>',
- ),
- variableMetadata: fun(
- 'Get token variable metadata',
- [collectionParam, tokenParam],
- 'Vec<u8>',
- ),
-
- tokenData: fun(
- 'Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT',
- [collectionParam, tokenParam, propertyKeysParam],
- 'UpDataStructsTokenData',
- ),
- totalSupply: fun(
- 'Get the amount of distinctive tokens present in a collection',
- [collectionParam],
- 'u32',
- ),
-
- accountBalance: fun(
- 'Get the amount of any user tokens owned by an account',
- [collectionParam, crossAccountParam()],
- 'u32',
- ),
- balance: fun(
- 'Get the amount of a specific token owned by an account',
- [collectionParam, crossAccountParam(), tokenParam],
- 'u128',
- ),
- allowance: fun(
- 'Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor',
- [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam],
- 'u128',
- ),
-
- adminlist: fun(
- 'Get the list of admin accounts of a collection',
- [collectionParam],
- 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
- ),
- allowlist: fun(
- 'Get the list of accounts allowed to operate within a collection',
- [collectionParam],
- 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
- ),
- allowed: fun(
- 'Check if a user is allowed to operate within a collection',
- [collectionParam, crossAccountParam()],
- 'bool',
- ),
-
- lastTokenId: fun(
- 'Get the last token ID created in a collection',
- [collectionParam],
- 'u32',
- ),
- collectionById: fun(
- 'Get a collection by the specified ID',
- [collectionParam],
- 'Option<UpDataStructsRpcCollection>',
- ),
- collectionStats: fun(
- 'Get chain stats about collections',
- [],
- 'UpDataStructsCollectionStats',
- ),
-
- nextSponsored: fun(
- 'Get the number of blocks until sponsoring a transaction is available',
- [collectionParam, crossAccountParam(), tokenParam],
- 'Option<u64>',
- ),
- effectiveCollectionLimits: fun(
- 'Get effective collection limits',
- [collectionParam],
- 'Option<UpDataStructsCollectionLimits>',
- ),
- totalPieces: fun(
- 'Get the total amount of pieces of an RFT',
- [collectionParam, tokenParam],
- 'Option<u128>',
- ),
- allowanceForAll: fun(
- 'Tells whether the given `owner` approves the `operator`.',
- [collectionParam, crossAccountParam('owner'), crossAccountParam('operator')],
- 'Option<bool>',
- ),
- },
-};
js-packages/types/src/unique/index.tsdiffbeforeafterboth--- a/js-packages/types/src/unique/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './types.js';
js-packages/types/src/unique/types.tsdiffbeforeafterboth--- a/js-packages/types/src/unique/types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export type PHANTOM_UNIQUE = 'unique';
js-packages/types/tsconfig.jsondiffbeforeafterboth--- a/js-packages/types/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "extends": "../tsconfig.packages.json",
- "compilerOptions": {
- "rootDir": "./src",
- "outDir": "dist"
- }
-}
\ No newline at end of file
js-packages/types/types-lookup.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/types-lookup.ts
@@ -0,0 +1,5540 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+// import type lookup before we augment - in some environments
+// this is required to allow for ambient/previous definitions
+import '@polkadot/types/lookup';
+
+import type { Data } from '@polkadot/types';
+import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Set, Struct, Text, U256, U8aFixed, Vec, bool, i64, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { ITuple } from '@polkadot/types-codec/types';
+import type { Vote } from '@polkadot/types/interfaces/elections';
+import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
+import type { Event } from '@polkadot/types/interfaces/system';
+
+declare module '@polkadot/types/lookup' {
+ /** @name FrameSystemAccountInfo (3) */
+ interface FrameSystemAccountInfo extends Struct {
+ readonly nonce: u32;
+ readonly consumers: u32;
+ readonly providers: u32;
+ readonly sufficients: u32;
+ readonly data: PalletBalancesAccountData;
+ }
+
+ /** @name PalletBalancesAccountData (5) */
+ interface PalletBalancesAccountData extends Struct {
+ readonly free: u128;
+ readonly reserved: u128;
+ readonly frozen: u128;
+ readonly flags: u128;
+ }
+
+ /** @name FrameSupportDispatchPerDispatchClassWeight (8) */
+ interface FrameSupportDispatchPerDispatchClassWeight extends Struct {
+ readonly normal: SpWeightsWeightV2Weight;
+ readonly operational: SpWeightsWeightV2Weight;
+ readonly mandatory: SpWeightsWeightV2Weight;
+ }
+
+ /** @name SpWeightsWeightV2Weight (9) */
+ interface SpWeightsWeightV2Weight extends Struct {
+ readonly refTime: Compact<u64>;
+ readonly proofSize: Compact<u64>;
+ }
+
+ /** @name SpRuntimeDigest (14) */
+ interface SpRuntimeDigest extends Struct {
+ readonly logs: Vec<SpRuntimeDigestDigestItem>;
+ }
+
+ /** @name SpRuntimeDigestDigestItem (16) */
+ interface SpRuntimeDigestDigestItem extends Enum {
+ readonly isOther: boolean;
+ readonly asOther: Bytes;
+ readonly isConsensus: boolean;
+ readonly asConsensus: ITuple<[U8aFixed, Bytes]>;
+ readonly isSeal: boolean;
+ readonly asSeal: ITuple<[U8aFixed, Bytes]>;
+ readonly isPreRuntime: boolean;
+ readonly asPreRuntime: ITuple<[U8aFixed, Bytes]>;
+ readonly isRuntimeEnvironmentUpdated: boolean;
+ readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated';
+ }
+
+ /** @name FrameSystemEventRecord (19) */
+ interface FrameSystemEventRecord extends Struct {
+ readonly phase: FrameSystemPhase;
+ readonly event: Event;
+ readonly topics: Vec<H256>;
+ }
+
+ /** @name FrameSystemEvent (21) */
+ interface FrameSystemEvent extends Enum {
+ readonly isExtrinsicSuccess: boolean;
+ readonly asExtrinsicSuccess: {
+ readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
+ } & Struct;
+ readonly isExtrinsicFailed: boolean;
+ readonly asExtrinsicFailed: {
+ readonly dispatchError: SpRuntimeDispatchError;
+ readonly dispatchInfo: FrameSupportDispatchDispatchInfo;
+ } & Struct;
+ readonly isCodeUpdated: boolean;
+ readonly isNewAccount: boolean;
+ readonly asNewAccount: {
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isKilledAccount: boolean;
+ readonly asKilledAccount: {
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isRemarked: boolean;
+ readonly asRemarked: {
+ readonly sender: AccountId32;
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked';
+ }
+
+ /** @name FrameSupportDispatchDispatchInfo (22) */
+ interface FrameSupportDispatchDispatchInfo extends Struct {
+ readonly weight: SpWeightsWeightV2Weight;
+ readonly class: FrameSupportDispatchDispatchClass;
+ readonly paysFee: FrameSupportDispatchPays;
+ }
+
+ /** @name FrameSupportDispatchDispatchClass (23) */
+ interface FrameSupportDispatchDispatchClass extends Enum {
+ readonly isNormal: boolean;
+ readonly isOperational: boolean;
+ readonly isMandatory: boolean;
+ readonly type: 'Normal' | 'Operational' | 'Mandatory';
+ }
+
+ /** @name FrameSupportDispatchPays (24) */
+ interface FrameSupportDispatchPays extends Enum {
+ readonly isYes: boolean;
+ readonly isNo: boolean;
+ readonly type: 'Yes' | 'No';
+ }
+
+ /** @name SpRuntimeDispatchError (25) */
+ interface SpRuntimeDispatchError extends Enum {
+ readonly isOther: boolean;
+ readonly isCannotLookup: boolean;
+ readonly isBadOrigin: boolean;
+ readonly isModule: boolean;
+ readonly asModule: SpRuntimeModuleError;
+ readonly isConsumerRemaining: boolean;
+ readonly isNoProviders: boolean;
+ readonly isTooManyConsumers: boolean;
+ readonly isToken: boolean;
+ readonly asToken: SpRuntimeTokenError;
+ readonly isArithmetic: boolean;
+ readonly asArithmetic: SpArithmeticArithmeticError;
+ readonly isTransactional: boolean;
+ readonly asTransactional: SpRuntimeTransactionalError;
+ readonly isExhausted: boolean;
+ readonly isCorruption: boolean;
+ readonly isUnavailable: boolean;
+ readonly isRootNotAllowed: boolean;
+ readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional' | 'Exhausted' | 'Corruption' | 'Unavailable' | 'RootNotAllowed';
+ }
+
+ /** @name SpRuntimeModuleError (26) */
+ interface SpRuntimeModuleError extends Struct {
+ readonly index: u8;
+ readonly error: U8aFixed;
+ }
+
+ /** @name SpRuntimeTokenError (27) */
+ interface SpRuntimeTokenError extends Enum {
+ readonly isFundsUnavailable: boolean;
+ readonly isOnlyProvider: boolean;
+ readonly isBelowMinimum: boolean;
+ readonly isCannotCreate: boolean;
+ readonly isUnknownAsset: boolean;
+ readonly isFrozen: boolean;
+ readonly isUnsupported: boolean;
+ readonly isCannotCreateHold: boolean;
+ readonly isNotExpendable: boolean;
+ readonly isBlocked: boolean;
+ readonly type: 'FundsUnavailable' | 'OnlyProvider' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported' | 'CannotCreateHold' | 'NotExpendable' | 'Blocked';
+ }
+
+ /** @name SpArithmeticArithmeticError (28) */
+ interface SpArithmeticArithmeticError extends Enum {
+ readonly isUnderflow: boolean;
+ readonly isOverflow: boolean;
+ readonly isDivisionByZero: boolean;
+ readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero';
+ }
+
+ /** @name SpRuntimeTransactionalError (29) */
+ interface SpRuntimeTransactionalError extends Enum {
+ readonly isLimitReached: boolean;
+ readonly isNoLayer: boolean;
+ readonly type: 'LimitReached' | 'NoLayer';
+ }
+
+ /** @name PalletStateTrieMigrationEvent (30) */
+ interface PalletStateTrieMigrationEvent extends Enum {
+ readonly isMigrated: boolean;
+ readonly asMigrated: {
+ readonly top: u32;
+ readonly child: u32;
+ readonly compute: PalletStateTrieMigrationMigrationCompute;
+ } & Struct;
+ readonly isSlashed: boolean;
+ readonly asSlashed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isAutoMigrationFinished: boolean;
+ readonly isHalted: boolean;
+ readonly asHalted: {
+ readonly error: PalletStateTrieMigrationError;
+ } & Struct;
+ readonly type: 'Migrated' | 'Slashed' | 'AutoMigrationFinished' | 'Halted';
+ }
+
+ /** @name PalletStateTrieMigrationMigrationCompute (31) */
+ interface PalletStateTrieMigrationMigrationCompute extends Enum {
+ readonly isSigned: boolean;
+ readonly isAuto: boolean;
+ readonly type: 'Signed' | 'Auto';
+ }
+
+ /** @name PalletStateTrieMigrationError (32) */
+ interface PalletStateTrieMigrationError extends Enum {
+ readonly isMaxSignedLimits: boolean;
+ readonly isKeyTooLong: boolean;
+ readonly isNotEnoughFunds: boolean;
+ readonly isBadWitness: boolean;
+ readonly isSignedMigrationNotAllowed: boolean;
+ readonly isBadChildRoot: boolean;
+ readonly type: 'MaxSignedLimits' | 'KeyTooLong' | 'NotEnoughFunds' | 'BadWitness' | 'SignedMigrationNotAllowed' | 'BadChildRoot';
+ }
+
+ /** @name CumulusPalletParachainSystemEvent (33) */
+ interface CumulusPalletParachainSystemEvent extends Enum {
+ readonly isValidationFunctionStored: boolean;
+ readonly isValidationFunctionApplied: boolean;
+ readonly asValidationFunctionApplied: {
+ readonly relayChainBlockNum: u32;
+ } & Struct;
+ readonly isValidationFunctionDiscarded: boolean;
+ readonly isUpgradeAuthorized: boolean;
+ readonly asUpgradeAuthorized: {
+ readonly codeHash: H256;
+ } & Struct;
+ readonly isDownwardMessagesReceived: boolean;
+ readonly asDownwardMessagesReceived: {
+ readonly count: u32;
+ } & Struct;
+ readonly isDownwardMessagesProcessed: boolean;
+ readonly asDownwardMessagesProcessed: {
+ readonly weightUsed: SpWeightsWeightV2Weight;
+ readonly dmqHead: H256;
+ } & Struct;
+ readonly isUpwardMessageSent: boolean;
+ readonly asUpwardMessageSent: {
+ readonly messageHash: Option<U8aFixed>;
+ } & Struct;
+ readonly type: 'ValidationFunctionStored' | 'ValidationFunctionApplied' | 'ValidationFunctionDiscarded' | 'UpgradeAuthorized' | 'DownwardMessagesReceived' | 'DownwardMessagesProcessed' | 'UpwardMessageSent';
+ }
+
+ /** @name PalletCollatorSelectionEvent (35) */
+ interface PalletCollatorSelectionEvent extends Enum {
+ readonly isInvulnerableAdded: boolean;
+ readonly asInvulnerableAdded: {
+ readonly invulnerable: AccountId32;
+ } & Struct;
+ readonly isInvulnerableRemoved: boolean;
+ readonly asInvulnerableRemoved: {
+ readonly invulnerable: AccountId32;
+ } & Struct;
+ readonly isLicenseObtained: boolean;
+ readonly asLicenseObtained: {
+ readonly accountId: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isLicenseReleased: boolean;
+ readonly asLicenseReleased: {
+ readonly accountId: AccountId32;
+ readonly depositReturned: u128;
+ } & Struct;
+ readonly isCandidateAdded: boolean;
+ readonly asCandidateAdded: {
+ readonly accountId: AccountId32;
+ } & Struct;
+ readonly isCandidateRemoved: boolean;
+ readonly asCandidateRemoved: {
+ readonly accountId: AccountId32;
+ } & Struct;
+ readonly type: 'InvulnerableAdded' | 'InvulnerableRemoved' | 'LicenseObtained' | 'LicenseReleased' | 'CandidateAdded' | 'CandidateRemoved';
+ }
+
+ /** @name PalletSessionEvent (36) */
+ interface PalletSessionEvent extends Enum {
+ readonly isNewSession: boolean;
+ readonly asNewSession: {
+ readonly sessionIndex: u32;
+ } & Struct;
+ readonly type: 'NewSession';
+ }
+
+ /** @name PalletBalancesEvent (37) */
+ interface PalletBalancesEvent extends Enum {
+ readonly isEndowed: boolean;
+ readonly asEndowed: {
+ readonly account: AccountId32;
+ readonly freeBalance: u128;
+ } & Struct;
+ readonly isDustLost: boolean;
+ readonly asDustLost: {
+ readonly account: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isBalanceSet: boolean;
+ readonly asBalanceSet: {
+ readonly who: AccountId32;
+ readonly free: u128;
+ } & Struct;
+ readonly isReserved: boolean;
+ readonly asReserved: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnreserved: boolean;
+ readonly asUnreserved: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isReserveRepatriated: boolean;
+ readonly asReserveRepatriated: {
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ readonly destinationStatus: FrameSupportTokensMiscBalanceStatus;
+ } & Struct;
+ readonly isDeposit: boolean;
+ readonly asDeposit: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isWithdraw: boolean;
+ readonly asWithdraw: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSlashed: boolean;
+ readonly asSlashed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isMinted: boolean;
+ readonly asMinted: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isBurned: boolean;
+ readonly asBurned: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSuspended: boolean;
+ readonly asSuspended: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isRestored: boolean;
+ readonly asRestored: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUpgraded: boolean;
+ readonly asUpgraded: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isIssued: boolean;
+ readonly asIssued: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isRescinded: boolean;
+ readonly asRescinded: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isLocked: boolean;
+ readonly asLocked: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnlocked: boolean;
+ readonly asUnlocked: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isFrozen: boolean;
+ readonly asFrozen: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isThawed: boolean;
+ readonly asThawed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'BalanceSet' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'Deposit' | 'Withdraw' | 'Slashed' | 'Minted' | 'Burned' | 'Suspended' | 'Restored' | 'Upgraded' | 'Issued' | 'Rescinded' | 'Locked' | 'Unlocked' | 'Frozen' | 'Thawed';
+ }
+
+ /** @name FrameSupportTokensMiscBalanceStatus (38) */
+ interface FrameSupportTokensMiscBalanceStatus extends Enum {
+ readonly isFree: boolean;
+ readonly isReserved: boolean;
+ readonly type: 'Free' | 'Reserved';
+ }
+
+ /** @name PalletTransactionPaymentEvent (39) */
+ interface PalletTransactionPaymentEvent extends Enum {
+ readonly isTransactionFeePaid: boolean;
+ readonly asTransactionFeePaid: {
+ readonly who: AccountId32;
+ readonly actualFee: u128;
+ readonly tip: u128;
+ } & Struct;
+ readonly type: 'TransactionFeePaid';
+ }
+
+ /** @name PalletTreasuryEvent (40) */
+ interface PalletTreasuryEvent extends Enum {
+ readonly isProposed: boolean;
+ readonly asProposed: {
+ readonly proposalIndex: u32;
+ } & Struct;
+ readonly isSpending: boolean;
+ readonly asSpending: {
+ readonly budgetRemaining: u128;
+ } & Struct;
+ readonly isAwarded: boolean;
+ readonly asAwarded: {
+ readonly proposalIndex: u32;
+ readonly award: u128;
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isRejected: boolean;
+ readonly asRejected: {
+ readonly proposalIndex: u32;
+ readonly slashed: u128;
+ } & Struct;
+ readonly isBurnt: boolean;
+ readonly asBurnt: {
+ readonly burntFunds: u128;
+ } & Struct;
+ readonly isRollover: boolean;
+ readonly asRollover: {
+ readonly rolloverBalance: u128;
+ } & Struct;
+ readonly isDeposit: boolean;
+ readonly asDeposit: {
+ readonly value: u128;
+ } & Struct;
+ readonly isSpendApproved: boolean;
+ readonly asSpendApproved: {
+ readonly proposalIndex: u32;
+ readonly amount: u128;
+ readonly beneficiary: AccountId32;
+ } & Struct;
+ readonly isUpdatedInactive: boolean;
+ readonly asUpdatedInactive: {
+ readonly reactivated: u128;
+ readonly deactivated: u128;
+ } & Struct;
+ readonly type: 'Proposed' | 'Spending' | 'Awarded' | 'Rejected' | 'Burnt' | 'Rollover' | 'Deposit' | 'SpendApproved' | 'UpdatedInactive';
+ }
+
+ /** @name PalletSudoEvent (41) */
+ interface PalletSudoEvent extends Enum {
+ readonly isSudid: boolean;
+ readonly asSudid: {
+ readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isKeyChanged: boolean;
+ readonly asKeyChanged: {
+ readonly oldSudoer: Option<AccountId32>;
+ } & Struct;
+ readonly isSudoAsDone: boolean;
+ readonly asSudoAsDone: {
+ readonly sudoResult: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone';
+ }
+
+ /** @name OrmlVestingModuleEvent (45) */
+ interface OrmlVestingModuleEvent extends Enum {
+ readonly isVestingScheduleAdded: boolean;
+ readonly asVestingScheduleAdded: {
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly vestingSchedule: OrmlVestingVestingSchedule;
+ } & Struct;
+ readonly isClaimed: boolean;
+ readonly asClaimed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isVestingSchedulesUpdated: boolean;
+ readonly asVestingSchedulesUpdated: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated';
+ }
+
+ /** @name OrmlVestingVestingSchedule (46) */
+ interface OrmlVestingVestingSchedule extends Struct {
+ readonly start: u32;
+ readonly period: u32;
+ readonly periodCount: u32;
+ readonly perPeriod: Compact<u128>;
+ }
+
+ /** @name OrmlXtokensModuleEvent (48) */
+ interface OrmlXtokensModuleEvent extends Enum {
+ readonly isTransferredMultiAssets: boolean;
+ readonly asTransferredMultiAssets: {
+ readonly sender: AccountId32;
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly fee: StagingXcmV3MultiAsset;
+ readonly dest: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly type: 'TransferredMultiAssets';
+ }
+
+ /** @name StagingXcmV3MultiassetMultiAssets (49) */
+ interface StagingXcmV3MultiassetMultiAssets extends Vec<StagingXcmV3MultiAsset> {}
+
+ /** @name StagingXcmV3MultiAsset (51) */
+ interface StagingXcmV3MultiAsset extends Struct {
+ readonly id: StagingXcmV3MultiassetAssetId;
+ readonly fun: StagingXcmV3MultiassetFungibility;
+ }
+
+ /** @name StagingXcmV3MultiassetAssetId (52) */
+ interface StagingXcmV3MultiassetAssetId extends Enum {
+ readonly isConcrete: boolean;
+ readonly asConcrete: StagingXcmV3MultiLocation;
+ readonly isAbstract: boolean;
+ readonly asAbstract: U8aFixed;
+ readonly type: 'Concrete' | 'Abstract';
+ }
+
+ /** @name StagingXcmV3MultiLocation (53) */
+ interface StagingXcmV3MultiLocation extends Struct {
+ readonly parents: u8;
+ readonly interior: StagingXcmV3Junctions;
+ }
+
+ /** @name StagingXcmV3Junctions (54) */
+ interface StagingXcmV3Junctions extends Enum {
+ readonly isHere: boolean;
+ readonly isX1: boolean;
+ readonly asX1: StagingXcmV3Junction;
+ readonly isX2: boolean;
+ readonly asX2: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX3: boolean;
+ readonly asX3: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX4: boolean;
+ readonly asX4: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX5: boolean;
+ readonly asX5: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX6: boolean;
+ readonly asX6: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX7: boolean;
+ readonly asX7: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly isX8: boolean;
+ readonly asX8: ITuple<[StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction, StagingXcmV3Junction]>;
+ readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
+ }
+
+ /** @name StagingXcmV3Junction (55) */
+ interface StagingXcmV3Junction extends Enum {
+ readonly isParachain: boolean;
+ readonly asParachain: Compact<u32>;
+ readonly isAccountId32: boolean;
+ readonly asAccountId32: {
+ readonly network: Option<StagingXcmV3JunctionNetworkId>;
+ readonly id: U8aFixed;
+ } & Struct;
+ readonly isAccountIndex64: boolean;
+ readonly asAccountIndex64: {
+ readonly network: Option<StagingXcmV3JunctionNetworkId>;
+ readonly index: Compact<u64>;
+ } & Struct;
+ readonly isAccountKey20: boolean;
+ readonly asAccountKey20: {
+ readonly network: Option<StagingXcmV3JunctionNetworkId>;
+ readonly key: U8aFixed;
+ } & Struct;
+ readonly isPalletInstance: boolean;
+ readonly asPalletInstance: u8;
+ readonly isGeneralIndex: boolean;
+ readonly asGeneralIndex: Compact<u128>;
+ readonly isGeneralKey: boolean;
+ readonly asGeneralKey: {
+ readonly length: u8;
+ readonly data: U8aFixed;
+ } & Struct;
+ readonly isOnlyChild: boolean;
+ readonly isPlurality: boolean;
+ readonly asPlurality: {
+ readonly id: StagingXcmV3JunctionBodyId;
+ readonly part: StagingXcmV3JunctionBodyPart;
+ } & Struct;
+ readonly isGlobalConsensus: boolean;
+ readonly asGlobalConsensus: StagingXcmV3JunctionNetworkId;
+ readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality' | 'GlobalConsensus';
+ }
+
+ /** @name StagingXcmV3JunctionNetworkId (58) */
+ interface StagingXcmV3JunctionNetworkId extends Enum {
+ readonly isByGenesis: boolean;
+ readonly asByGenesis: U8aFixed;
+ readonly isByFork: boolean;
+ readonly asByFork: {
+ readonly blockNumber: u64;
+ readonly blockHash: U8aFixed;
+ } & Struct;
+ readonly isPolkadot: boolean;
+ readonly isKusama: boolean;
+ readonly isWestend: boolean;
+ readonly isRococo: boolean;
+ readonly isWococo: boolean;
+ readonly isEthereum: boolean;
+ readonly asEthereum: {
+ readonly chainId: Compact<u64>;
+ } & Struct;
+ readonly isBitcoinCore: boolean;
+ readonly isBitcoinCash: boolean;
+ readonly type: 'ByGenesis' | 'ByFork' | 'Polkadot' | 'Kusama' | 'Westend' | 'Rococo' | 'Wococo' | 'Ethereum' | 'BitcoinCore' | 'BitcoinCash';
+ }
+
+ /** @name StagingXcmV3JunctionBodyId (60) */
+ interface StagingXcmV3JunctionBodyId extends Enum {
+ readonly isUnit: boolean;
+ readonly isMoniker: boolean;
+ readonly asMoniker: U8aFixed;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u32>;
+ readonly isExecutive: boolean;
+ readonly isTechnical: boolean;
+ readonly isLegislative: boolean;
+ readonly isJudicial: boolean;
+ readonly isDefense: boolean;
+ readonly isAdministration: boolean;
+ readonly isTreasury: boolean;
+ readonly type: 'Unit' | 'Moniker' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
+ }
+
+ /** @name StagingXcmV3JunctionBodyPart (61) */
+ interface StagingXcmV3JunctionBodyPart extends Enum {
+ readonly isVoice: boolean;
+ readonly isMembers: boolean;
+ readonly asMembers: {
+ readonly count: Compact<u32>;
+ } & Struct;
+ readonly isFraction: boolean;
+ readonly asFraction: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isAtLeastProportion: boolean;
+ readonly asAtLeastProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isMoreThanProportion: boolean;
+ readonly asMoreThanProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
+ }
+
+ /** @name StagingXcmV3MultiassetFungibility (62) */
+ interface StagingXcmV3MultiassetFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly asFungible: Compact<u128>;
+ readonly isNonFungible: boolean;
+ readonly asNonFungible: StagingXcmV3MultiassetAssetInstance;
+ readonly type: 'Fungible' | 'NonFungible';
+ }
+
+ /** @name StagingXcmV3MultiassetAssetInstance (63) */
+ interface StagingXcmV3MultiassetAssetInstance extends Enum {
+ readonly isUndefined: boolean;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u128>;
+ readonly isArray4: boolean;
+ readonly asArray4: U8aFixed;
+ readonly isArray8: boolean;
+ readonly asArray8: U8aFixed;
+ readonly isArray16: boolean;
+ readonly asArray16: U8aFixed;
+ readonly isArray32: boolean;
+ readonly asArray32: U8aFixed;
+ readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32';
+ }
+
+ /** @name OrmlTokensModuleEvent (66) */
+ interface OrmlTokensModuleEvent extends Enum {
+ readonly isEndowed: boolean;
+ readonly asEndowed: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDustLost: boolean;
+ readonly asDustLost: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isReserved: boolean;
+ readonly asReserved: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnreserved: boolean;
+ readonly asUnreserved: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isReserveRepatriated: boolean;
+ readonly asReserveRepatriated: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly from: AccountId32;
+ readonly to: AccountId32;
+ readonly amount: u128;
+ readonly status: FrameSupportTokensMiscBalanceStatus;
+ } & Struct;
+ readonly isBalanceSet: boolean;
+ readonly asBalanceSet: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly free: u128;
+ readonly reserved: u128;
+ } & Struct;
+ readonly isTotalIssuanceSet: boolean;
+ readonly asTotalIssuanceSet: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ } & Struct;
+ readonly isWithdrawn: boolean;
+ readonly asWithdrawn: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSlashed: boolean;
+ readonly asSlashed: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly freeAmount: u128;
+ readonly reservedAmount: u128;
+ } & Struct;
+ readonly isDeposited: boolean;
+ readonly asDeposited: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isLockSet: boolean;
+ readonly asLockSet: {
+ readonly lockId: U8aFixed;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isLockRemoved: boolean;
+ readonly asLockRemoved: {
+ readonly lockId: U8aFixed;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isLocked: boolean;
+ readonly asLocked: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnlocked: boolean;
+ readonly asUnlocked: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isIssued: boolean;
+ readonly asIssued: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ } & Struct;
+ readonly isRescinded: boolean;
+ readonly asRescinded: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ } & Struct;
+ readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'BalanceSet' | 'TotalIssuanceSet' | 'Withdrawn' | 'Slashed' | 'Deposited' | 'LockSet' | 'LockRemoved' | 'Locked' | 'Unlocked' | 'Issued' | 'Rescinded';
+ }
+
+ /** @name PalletForeignAssetsAssetId (67) */
+ interface PalletForeignAssetsAssetId extends Enum {
+ readonly isForeignAssetId: boolean;
+ readonly asForeignAssetId: u32;
+ readonly isNativeAssetId: boolean;
+ readonly asNativeAssetId: PalletForeignAssetsNativeCurrency;
+ readonly type: 'ForeignAssetId' | 'NativeAssetId';
+ }
+
+ /** @name PalletForeignAssetsNativeCurrency (68) */
+ interface PalletForeignAssetsNativeCurrency extends Enum {
+ readonly isHere: boolean;
+ readonly isParent: boolean;
+ readonly type: 'Here' | 'Parent';
+ }
+
+ /** @name PalletIdentityEvent (69) */
+ interface PalletIdentityEvent extends Enum {
+ readonly isIdentitySet: boolean;
+ readonly asIdentitySet: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isIdentityCleared: boolean;
+ readonly asIdentityCleared: {
+ readonly who: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isIdentityKilled: boolean;
+ readonly asIdentityKilled: {
+ readonly who: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isIdentitiesInserted: boolean;
+ readonly asIdentitiesInserted: {
+ readonly amount: u32;
+ } & Struct;
+ readonly isIdentitiesRemoved: boolean;
+ readonly asIdentitiesRemoved: {
+ readonly amount: u32;
+ } & Struct;
+ readonly isJudgementRequested: boolean;
+ readonly asJudgementRequested: {
+ readonly who: AccountId32;
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isJudgementUnrequested: boolean;
+ readonly asJudgementUnrequested: {
+ readonly who: AccountId32;
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isJudgementGiven: boolean;
+ readonly asJudgementGiven: {
+ readonly target: AccountId32;
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isRegistrarAdded: boolean;
+ readonly asRegistrarAdded: {
+ readonly registrarIndex: u32;
+ } & Struct;
+ readonly isSubIdentityAdded: boolean;
+ readonly asSubIdentityAdded: {
+ readonly sub: AccountId32;
+ readonly main: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isSubIdentityRemoved: boolean;
+ readonly asSubIdentityRemoved: {
+ readonly sub: AccountId32;
+ readonly main: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isSubIdentityRevoked: boolean;
+ readonly asSubIdentityRevoked: {
+ readonly sub: AccountId32;
+ readonly main: AccountId32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isSubIdentitiesInserted: boolean;
+ readonly asSubIdentitiesInserted: {
+ readonly amount: u32;
+ } & Struct;
+ readonly type: 'IdentitySet' | 'IdentityCleared' | 'IdentityKilled' | 'IdentitiesInserted' | 'IdentitiesRemoved' | 'JudgementRequested' | 'JudgementUnrequested' | 'JudgementGiven' | 'RegistrarAdded' | 'SubIdentityAdded' | 'SubIdentityRemoved' | 'SubIdentityRevoked' | 'SubIdentitiesInserted';
+ }
+
+ /** @name PalletPreimageEvent (70) */
+ interface PalletPreimageEvent extends Enum {
+ readonly isNoted: boolean;
+ readonly asNoted: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isRequested: boolean;
+ readonly asRequested: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isCleared: boolean;
+ readonly asCleared: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'Noted' | 'Requested' | 'Cleared';
+ }
+
+ /** @name PalletDemocracyEvent (71) */
+ interface PalletDemocracyEvent extends Enum {
+ readonly isProposed: boolean;
+ readonly asProposed: {
+ readonly proposalIndex: u32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isTabled: boolean;
+ readonly asTabled: {
+ readonly proposalIndex: u32;
+ readonly deposit: u128;
+ } & Struct;
+ readonly isExternalTabled: boolean;
+ readonly isStarted: boolean;
+ readonly asStarted: {
+ readonly refIndex: u32;
+ readonly threshold: PalletDemocracyVoteThreshold;
+ } & Struct;
+ readonly isPassed: boolean;
+ readonly asPassed: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isNotPassed: boolean;
+ readonly asNotPassed: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isCancelled: boolean;
+ readonly asCancelled: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isDelegated: boolean;
+ readonly asDelegated: {
+ readonly who: AccountId32;
+ readonly target: AccountId32;
+ } & Struct;
+ readonly isUndelegated: boolean;
+ readonly asUndelegated: {
+ readonly account: AccountId32;
+ } & Struct;
+ readonly isVetoed: boolean;
+ readonly asVetoed: {
+ readonly who: AccountId32;
+ readonly proposalHash: H256;
+ readonly until: u32;
+ } & Struct;
+ readonly isBlacklisted: boolean;
+ readonly asBlacklisted: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isVoted: boolean;
+ readonly asVoted: {
+ readonly voter: AccountId32;
+ readonly refIndex: u32;
+ readonly vote: PalletDemocracyVoteAccountVote;
+ } & Struct;
+ readonly isSeconded: boolean;
+ readonly asSeconded: {
+ readonly seconder: AccountId32;
+ readonly propIndex: u32;
+ } & Struct;
+ readonly isProposalCanceled: boolean;
+ readonly asProposalCanceled: {
+ readonly propIndex: u32;
+ } & Struct;
+ readonly isMetadataSet: boolean;
+ readonly asMetadataSet: {
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly hash_: H256;
+ } & Struct;
+ readonly isMetadataCleared: boolean;
+ readonly asMetadataCleared: {
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly hash_: H256;
+ } & Struct;
+ readonly isMetadataTransferred: boolean;
+ readonly asMetadataTransferred: {
+ readonly prevOwner: PalletDemocracyMetadataOwner;
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'Proposed' | 'Tabled' | 'ExternalTabled' | 'Started' | 'Passed' | 'NotPassed' | 'Cancelled' | 'Delegated' | 'Undelegated' | 'Vetoed' | 'Blacklisted' | 'Voted' | 'Seconded' | 'ProposalCanceled' | 'MetadataSet' | 'MetadataCleared' | 'MetadataTransferred';
+ }
+
+ /** @name PalletDemocracyVoteThreshold (72) */
+ interface PalletDemocracyVoteThreshold extends Enum {
+ readonly isSuperMajorityApprove: boolean;
+ readonly isSuperMajorityAgainst: boolean;
+ readonly isSimpleMajority: boolean;
+ readonly type: 'SuperMajorityApprove' | 'SuperMajorityAgainst' | 'SimpleMajority';
+ }
+
+ /** @name PalletDemocracyVoteAccountVote (73) */
+ interface PalletDemocracyVoteAccountVote extends Enum {
+ readonly isStandard: boolean;
+ readonly asStandard: {
+ readonly vote: Vote;
+ readonly balance: u128;
+ } & Struct;
+ readonly isSplit: boolean;
+ readonly asSplit: {
+ readonly aye: u128;
+ readonly nay: u128;
+ } & Struct;
+ readonly type: 'Standard' | 'Split';
+ }
+
+ /** @name PalletDemocracyMetadataOwner (75) */
+ interface PalletDemocracyMetadataOwner extends Enum {
+ readonly isExternal: boolean;
+ readonly isProposal: boolean;
+ readonly asProposal: u32;
+ readonly isReferendum: boolean;
+ readonly asReferendum: u32;
+ readonly type: 'External' | 'Proposal' | 'Referendum';
+ }
+
+ /** @name PalletCollectiveEvent (76) */
+ interface PalletCollectiveEvent extends Enum {
+ readonly isProposed: boolean;
+ readonly asProposed: {
+ readonly account: AccountId32;
+ readonly proposalIndex: u32;
+ readonly proposalHash: H256;
+ readonly threshold: u32;
+ } & Struct;
+ readonly isVoted: boolean;
+ readonly asVoted: {
+ readonly account: AccountId32;
+ readonly proposalHash: H256;
+ readonly voted: bool;
+ readonly yes: u32;
+ readonly no: u32;
+ } & Struct;
+ readonly isApproved: boolean;
+ readonly asApproved: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isDisapproved: boolean;
+ readonly asDisapproved: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isExecuted: boolean;
+ readonly asExecuted: {
+ readonly proposalHash: H256;
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isMemberExecuted: boolean;
+ readonly asMemberExecuted: {
+ readonly proposalHash: H256;
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isClosed: boolean;
+ readonly asClosed: {
+ readonly proposalHash: H256;
+ readonly yes: u32;
+ readonly no: u32;
+ } & Struct;
+ readonly type: 'Proposed' | 'Voted' | 'Approved' | 'Disapproved' | 'Executed' | 'MemberExecuted' | 'Closed';
+ }
+
+ /** @name PalletMembershipEvent (79) */
+ interface PalletMembershipEvent extends Enum {
+ readonly isMemberAdded: boolean;
+ readonly isMemberRemoved: boolean;
+ readonly isMembersSwapped: boolean;
+ readonly isMembersReset: boolean;
+ readonly isKeyChanged: boolean;
+ readonly isDummy: boolean;
+ readonly type: 'MemberAdded' | 'MemberRemoved' | 'MembersSwapped' | 'MembersReset' | 'KeyChanged' | 'Dummy';
+ }
+
+ /** @name PalletRankedCollectiveEvent (81) */
+ interface PalletRankedCollectiveEvent extends Enum {
+ readonly isMemberAdded: boolean;
+ readonly asMemberAdded: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isRankChanged: boolean;
+ readonly asRankChanged: {
+ readonly who: AccountId32;
+ readonly rank: u16;
+ } & Struct;
+ readonly isMemberRemoved: boolean;
+ readonly asMemberRemoved: {
+ readonly who: AccountId32;
+ readonly rank: u16;
+ } & Struct;
+ readonly isVoted: boolean;
+ readonly asVoted: {
+ readonly who: AccountId32;
+ readonly poll: u32;
+ readonly vote: PalletRankedCollectiveVoteRecord;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly type: 'MemberAdded' | 'RankChanged' | 'MemberRemoved' | 'Voted';
+ }
+
+ /** @name PalletRankedCollectiveVoteRecord (83) */
+ interface PalletRankedCollectiveVoteRecord extends Enum {
+ readonly isAye: boolean;
+ readonly asAye: u32;
+ readonly isNay: boolean;
+ readonly asNay: u32;
+ readonly type: 'Aye' | 'Nay';
+ }
+
+ /** @name PalletRankedCollectiveTally (84) */
+ interface PalletRankedCollectiveTally extends Struct {
+ readonly bareAyes: u32;
+ readonly ayes: u32;
+ readonly nays: u32;
+ }
+
+ /** @name PalletReferendaEvent (85) */
+ interface PalletReferendaEvent extends Enum {
+ readonly isSubmitted: boolean;
+ readonly asSubmitted: {
+ readonly index: u32;
+ readonly track: u16;
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isDecisionDepositPlaced: boolean;
+ readonly asDecisionDepositPlaced: {
+ readonly index: u32;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDecisionDepositRefunded: boolean;
+ readonly asDecisionDepositRefunded: {
+ readonly index: u32;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDepositSlashed: boolean;
+ readonly asDepositSlashed: {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isDecisionStarted: boolean;
+ readonly asDecisionStarted: {
+ readonly index: u32;
+ readonly track: u16;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isConfirmStarted: boolean;
+ readonly asConfirmStarted: {
+ readonly index: u32;
+ } & Struct;
+ readonly isConfirmAborted: boolean;
+ readonly asConfirmAborted: {
+ readonly index: u32;
+ } & Struct;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isApproved: boolean;
+ readonly asApproved: {
+ readonly index: u32;
+ } & Struct;
+ readonly isRejected: boolean;
+ readonly asRejected: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isTimedOut: boolean;
+ readonly asTimedOut: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isCancelled: boolean;
+ readonly asCancelled: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isKilled: boolean;
+ readonly asKilled: {
+ readonly index: u32;
+ readonly tally: PalletRankedCollectiveTally;
+ } & Struct;
+ readonly isSubmissionDepositRefunded: boolean;
+ readonly asSubmissionDepositRefunded: {
+ readonly index: u32;
+ readonly who: AccountId32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isMetadataSet: boolean;
+ readonly asMetadataSet: {
+ readonly index: u32;
+ readonly hash_: H256;
+ } & Struct;
+ readonly isMetadataCleared: boolean;
+ readonly asMetadataCleared: {
+ readonly index: u32;
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'Submitted' | 'DecisionDepositPlaced' | 'DecisionDepositRefunded' | 'DepositSlashed' | 'DecisionStarted' | 'ConfirmStarted' | 'ConfirmAborted' | 'Confirmed' | 'Approved' | 'Rejected' | 'TimedOut' | 'Cancelled' | 'Killed' | 'SubmissionDepositRefunded' | 'MetadataSet' | 'MetadataCleared';
+ }
+
+ /** @name FrameSupportPreimagesBounded (86) */
+ interface FrameSupportPreimagesBounded extends Enum {
+ readonly isLegacy: boolean;
+ readonly asLegacy: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isInline: boolean;
+ readonly asInline: Bytes;
+ readonly isLookup: boolean;
+ readonly asLookup: {
+ readonly hash_: H256;
+ readonly len: u32;
+ } & Struct;
+ readonly type: 'Legacy' | 'Inline' | 'Lookup';
+ }
+
+ /** @name FrameSystemCall (88) */
+ interface FrameSystemCall extends Enum {
+ readonly isRemark: boolean;
+ readonly asRemark: {
+ readonly remark: Bytes;
+ } & Struct;
+ readonly isSetHeapPages: boolean;
+ readonly asSetHeapPages: {
+ readonly pages: u64;
+ } & Struct;
+ readonly isSetCode: boolean;
+ readonly asSetCode: {
+ readonly code: Bytes;
+ } & Struct;
+ readonly isSetCodeWithoutChecks: boolean;
+ readonly asSetCodeWithoutChecks: {
+ readonly code: Bytes;
+ } & Struct;
+ readonly isSetStorage: boolean;
+ readonly asSetStorage: {
+ readonly items: Vec<ITuple<[Bytes, Bytes]>>;
+ } & Struct;
+ readonly isKillStorage: boolean;
+ readonly asKillStorage: {
+ readonly keys_: Vec<Bytes>;
+ } & Struct;
+ readonly isKillPrefix: boolean;
+ readonly asKillPrefix: {
+ readonly prefix: Bytes;
+ readonly subkeys: u32;
+ } & Struct;
+ readonly isRemarkWithEvent: boolean;
+ readonly asRemarkWithEvent: {
+ readonly remark: Bytes;
+ } & Struct;
+ readonly type: 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
+ }
+
+ /** @name PalletStateTrieMigrationCall (92) */
+ interface PalletStateTrieMigrationCall extends Enum {
+ readonly isControlAutoMigration: boolean;
+ readonly asControlAutoMigration: {
+ readonly maybeConfig: Option<PalletStateTrieMigrationMigrationLimits>;
+ } & Struct;
+ readonly isContinueMigrate: boolean;
+ readonly asContinueMigrate: {
+ readonly limits: PalletStateTrieMigrationMigrationLimits;
+ readonly realSizeUpper: u32;
+ readonly witnessTask: PalletStateTrieMigrationMigrationTask;
+ } & Struct;
+ readonly isMigrateCustomTop: boolean;
+ readonly asMigrateCustomTop: {
+ readonly keys_: Vec<Bytes>;
+ readonly witnessSize: u32;
+ } & Struct;
+ readonly isMigrateCustomChild: boolean;
+ readonly asMigrateCustomChild: {
+ readonly root: Bytes;
+ readonly childKeys: Vec<Bytes>;
+ readonly totalSize: u32;
+ } & Struct;
+ readonly isSetSignedMaxLimits: boolean;
+ readonly asSetSignedMaxLimits: {
+ readonly limits: PalletStateTrieMigrationMigrationLimits;
+ } & Struct;
+ readonly isForceSetProgress: boolean;
+ readonly asForceSetProgress: {
+ readonly progressTop: PalletStateTrieMigrationProgress;
+ readonly progressChild: PalletStateTrieMigrationProgress;
+ } & Struct;
+ readonly type: 'ControlAutoMigration' | 'ContinueMigrate' | 'MigrateCustomTop' | 'MigrateCustomChild' | 'SetSignedMaxLimits' | 'ForceSetProgress';
+ }
+
+ /** @name PalletStateTrieMigrationMigrationLimits (94) */
+ interface PalletStateTrieMigrationMigrationLimits extends Struct {
+ readonly size_: u32;
+ readonly item: u32;
+ }
+
+ /** @name PalletStateTrieMigrationMigrationTask (95) */
+ interface PalletStateTrieMigrationMigrationTask extends Struct {
+ readonly progressTop: PalletStateTrieMigrationProgress;
+ readonly progressChild: PalletStateTrieMigrationProgress;
+ readonly size_: u32;
+ readonly topItems: u32;
+ readonly childItems: u32;
+ }
+
+ /** @name PalletStateTrieMigrationProgress (96) */
+ interface PalletStateTrieMigrationProgress extends Enum {
+ readonly isToStart: boolean;
+ readonly isLastKey: boolean;
+ readonly asLastKey: Bytes;
+ readonly isComplete: boolean;
+ readonly type: 'ToStart' | 'LastKey' | 'Complete';
+ }
+
+ /** @name CumulusPalletParachainSystemCall (98) */
+ interface CumulusPalletParachainSystemCall extends Enum {
+ readonly isSetValidationData: boolean;
+ readonly asSetValidationData: {
+ readonly data: CumulusPrimitivesParachainInherentParachainInherentData;
+ } & Struct;
+ readonly isSudoSendUpwardMessage: boolean;
+ readonly asSudoSendUpwardMessage: {
+ readonly message: Bytes;
+ } & Struct;
+ readonly isAuthorizeUpgrade: boolean;
+ readonly asAuthorizeUpgrade: {
+ readonly codeHash: H256;
+ readonly checkVersion: bool;
+ } & Struct;
+ readonly isEnactAuthorizedUpgrade: boolean;
+ readonly asEnactAuthorizedUpgrade: {
+ readonly code: Bytes;
+ } & Struct;
+ readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
+ }
+
+ /** @name CumulusPrimitivesParachainInherentParachainInherentData (99) */
+ interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
+ readonly validationData: PolkadotPrimitivesV5PersistedValidationData;
+ readonly relayChainState: SpTrieStorageProof;
+ readonly downwardMessages: Vec<PolkadotCorePrimitivesInboundDownwardMessage>;
+ readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
+ }
+
+ /** @name PolkadotPrimitivesV5PersistedValidationData (100) */
+ interface PolkadotPrimitivesV5PersistedValidationData extends Struct {
+ readonly parentHead: Bytes;
+ readonly relayParentNumber: u32;
+ readonly relayParentStorageRoot: H256;
+ readonly maxPovSize: u32;
+ }
+
+ /** @name SpTrieStorageProof (102) */
+ interface SpTrieStorageProof extends Struct {
+ readonly trieNodes: BTreeSet<Bytes>;
+ }
+
+ /** @name PolkadotCorePrimitivesInboundDownwardMessage (105) */
+ interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
+ readonly sentAt: u32;
+ readonly msg: Bytes;
+ }
+
+ /** @name PolkadotCorePrimitivesInboundHrmpMessage (109) */
+ interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
+ readonly sentAt: u32;
+ readonly data: Bytes;
+ }
+
+ /** @name ParachainInfoCall (112) */
+ type ParachainInfoCall = Null;
+
+ /** @name PalletCollatorSelectionCall (113) */
+ interface PalletCollatorSelectionCall extends Enum {
+ readonly isAddInvulnerable: boolean;
+ readonly asAddInvulnerable: {
+ readonly new_: AccountId32;
+ } & Struct;
+ readonly isRemoveInvulnerable: boolean;
+ readonly asRemoveInvulnerable: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly isGetLicense: boolean;
+ readonly isOnboard: boolean;
+ readonly isOffboard: boolean;
+ readonly isReleaseLicense: boolean;
+ readonly isForceReleaseLicense: boolean;
+ readonly asForceReleaseLicense: {
+ readonly who: AccountId32;
+ } & Struct;
+ readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceReleaseLicense';
+ }
+
+ /** @name PalletSessionCall (114) */
+ interface PalletSessionCall extends Enum {
+ readonly isSetKeys: boolean;
+ readonly asSetKeys: {
+ readonly keys_: OpalRuntimeRuntimeCommonSessionKeys;
+ readonly proof: Bytes;
+ } & Struct;
+ readonly isPurgeKeys: boolean;
+ readonly type: 'SetKeys' | 'PurgeKeys';
+ }
+
+ /** @name OpalRuntimeRuntimeCommonSessionKeys (115) */
+ interface OpalRuntimeRuntimeCommonSessionKeys extends Struct {
+ readonly aura: SpConsensusAuraSr25519AppSr25519Public;
+ }
+
+ /** @name SpConsensusAuraSr25519AppSr25519Public (116) */
+ interface SpConsensusAuraSr25519AppSr25519Public extends SpCoreSr25519Public {}
+
+ /** @name SpCoreSr25519Public (117) */
+ interface SpCoreSr25519Public extends U8aFixed {}
+
+ /** @name PalletBalancesCall (118) */
+ interface PalletBalancesCall extends Enum {
+ readonly isTransferAllowDeath: boolean;
+ readonly asTransferAllowDeath: {
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isSetBalanceDeprecated: boolean;
+ readonly asSetBalanceDeprecated: {
+ readonly who: MultiAddress;
+ readonly newFree: Compact<u128>;
+ readonly oldReserved: Compact<u128>;
+ } & Struct;
+ readonly isForceTransfer: boolean;
+ readonly asForceTransfer: {
+ readonly source: MultiAddress;
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isTransferKeepAlive: boolean;
+ readonly asTransferKeepAlive: {
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isTransferAll: boolean;
+ readonly asTransferAll: {
+ readonly dest: MultiAddress;
+ readonly keepAlive: bool;
+ } & Struct;
+ readonly isForceUnreserve: boolean;
+ readonly asForceUnreserve: {
+ readonly who: MultiAddress;
+ readonly amount: u128;
+ } & Struct;
+ readonly isUpgradeAccounts: boolean;
+ readonly asUpgradeAccounts: {
+ readonly who: Vec<AccountId32>;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly dest: MultiAddress;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isForceSetBalance: boolean;
+ readonly asForceSetBalance: {
+ readonly who: MultiAddress;
+ readonly newFree: Compact<u128>;
+ } & Struct;
+ readonly type: 'TransferAllowDeath' | 'SetBalanceDeprecated' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve' | 'UpgradeAccounts' | 'Transfer' | 'ForceSetBalance';
+ }
+
+ /** @name PalletTimestampCall (122) */
+ interface PalletTimestampCall extends Enum {
+ readonly isSet: boolean;
+ readonly asSet: {
+ readonly now: Compact<u64>;
+ } & Struct;
+ readonly type: 'Set';
+ }
+
+ /** @name PalletTreasuryCall (123) */
+ interface PalletTreasuryCall extends Enum {
+ readonly isProposeSpend: boolean;
+ readonly asProposeSpend: {
+ readonly value: Compact<u128>;
+ readonly beneficiary: MultiAddress;
+ } & Struct;
+ readonly isRejectProposal: boolean;
+ readonly asRejectProposal: {
+ readonly proposalId: Compact<u32>;
+ } & Struct;
+ readonly isApproveProposal: boolean;
+ readonly asApproveProposal: {
+ readonly proposalId: Compact<u32>;
+ } & Struct;
+ readonly isSpend: boolean;
+ readonly asSpend: {
+ readonly amount: Compact<u128>;
+ readonly beneficiary: MultiAddress;
+ } & Struct;
+ readonly isRemoveApproval: boolean;
+ readonly asRemoveApproval: {
+ readonly proposalId: Compact<u32>;
+ } & Struct;
+ readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
+ }
+
+ /** @name PalletSudoCall (124) */
+ interface PalletSudoCall extends Enum {
+ readonly isSudo: boolean;
+ readonly asSudo: {
+ readonly call: Call;
+ } & Struct;
+ readonly isSudoUncheckedWeight: boolean;
+ readonly asSudoUncheckedWeight: {
+ readonly call: Call;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isSetKey: boolean;
+ readonly asSetKey: {
+ readonly new_: MultiAddress;
+ } & Struct;
+ readonly isSudoAs: boolean;
+ readonly asSudoAs: {
+ readonly who: MultiAddress;
+ readonly call: Call;
+ } & Struct;
+ readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
+ }
+
+ /** @name OrmlVestingModuleCall (125) */
+ interface OrmlVestingModuleCall extends Enum {
+ readonly isClaim: boolean;
+ readonly isVestedTransfer: boolean;
+ readonly asVestedTransfer: {
+ readonly dest: MultiAddress;
+ readonly schedule: OrmlVestingVestingSchedule;
+ } & Struct;
+ readonly isUpdateVestingSchedules: boolean;
+ readonly asUpdateVestingSchedules: {
+ readonly who: MultiAddress;
+ readonly vestingSchedules: Vec<OrmlVestingVestingSchedule>;
+ } & Struct;
+ readonly isClaimFor: boolean;
+ readonly asClaimFor: {
+ readonly dest: MultiAddress;
+ } & Struct;
+ readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
+ }
+
+ /** @name OrmlXtokensModuleCall (127) */
+ interface OrmlXtokensModuleCall extends Enum {
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMultiasset: boolean;
+ readonly asTransferMultiasset: {
+ readonly asset: StagingXcmVersionedMultiAsset;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferWithFee: boolean;
+ readonly asTransferWithFee: {
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: u128;
+ readonly fee: u128;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMultiassetWithFee: boolean;
+ readonly asTransferMultiassetWithFee: {
+ readonly asset: StagingXcmVersionedMultiAsset;
+ readonly fee: StagingXcmVersionedMultiAsset;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMulticurrencies: boolean;
+ readonly asTransferMulticurrencies: {
+ readonly currencies: Vec<ITuple<[PalletForeignAssetsAssetId, u128]>>;
+ readonly feeItem: u32;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isTransferMultiassets: boolean;
+ readonly asTransferMultiassets: {
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeItem: u32;
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly destWeightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets';
+ }
+
+ /** @name StagingXcmVersionedMultiLocation (128) */
+ interface StagingXcmVersionedMultiLocation extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2MultiLocation;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiLocation;
+ readonly type: 'V2' | 'V3';
+ }
+
+ /** @name StagingXcmV2MultiLocation (129) */
+ interface StagingXcmV2MultiLocation extends Struct {
+ readonly parents: u8;
+ readonly interior: StagingXcmV2MultilocationJunctions;
+ }
+
+ /** @name StagingXcmV2MultilocationJunctions (130) */
+ interface StagingXcmV2MultilocationJunctions extends Enum {
+ readonly isHere: boolean;
+ readonly isX1: boolean;
+ readonly asX1: StagingXcmV2Junction;
+ readonly isX2: boolean;
+ readonly asX2: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX3: boolean;
+ readonly asX3: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX4: boolean;
+ readonly asX4: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX5: boolean;
+ readonly asX5: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX6: boolean;
+ readonly asX6: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX7: boolean;
+ readonly asX7: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly isX8: boolean;
+ readonly asX8: ITuple<[StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction, StagingXcmV2Junction]>;
+ readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8';
+ }
+
+ /** @name StagingXcmV2Junction (131) */
+ interface StagingXcmV2Junction extends Enum {
+ readonly isParachain: boolean;
+ readonly asParachain: Compact<u32>;
+ readonly isAccountId32: boolean;
+ readonly asAccountId32: {
+ readonly network: StagingXcmV2NetworkId;
+ readonly id: U8aFixed;
+ } & Struct;
+ readonly isAccountIndex64: boolean;
+ readonly asAccountIndex64: {
+ readonly network: StagingXcmV2NetworkId;
+ readonly index: Compact<u64>;
+ } & Struct;
+ readonly isAccountKey20: boolean;
+ readonly asAccountKey20: {
+ readonly network: StagingXcmV2NetworkId;
+ readonly key: U8aFixed;
+ } & Struct;
+ readonly isPalletInstance: boolean;
+ readonly asPalletInstance: u8;
+ readonly isGeneralIndex: boolean;
+ readonly asGeneralIndex: Compact<u128>;
+ readonly isGeneralKey: boolean;
+ readonly asGeneralKey: Bytes;
+ readonly isOnlyChild: boolean;
+ readonly isPlurality: boolean;
+ readonly asPlurality: {
+ readonly id: StagingXcmV2BodyId;
+ readonly part: StagingXcmV2BodyPart;
+ } & Struct;
+ readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality';
+ }
+
+ /** @name StagingXcmV2NetworkId (132) */
+ interface StagingXcmV2NetworkId extends Enum {
+ readonly isAny: boolean;
+ readonly isNamed: boolean;
+ readonly asNamed: Bytes;
+ readonly isPolkadot: boolean;
+ readonly isKusama: boolean;
+ readonly type: 'Any' | 'Named' | 'Polkadot' | 'Kusama';
+ }
+
+ /** @name StagingXcmV2BodyId (134) */
+ interface StagingXcmV2BodyId extends Enum {
+ readonly isUnit: boolean;
+ readonly isNamed: boolean;
+ readonly asNamed: Bytes;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u32>;
+ readonly isExecutive: boolean;
+ readonly isTechnical: boolean;
+ readonly isLegislative: boolean;
+ readonly isJudicial: boolean;
+ readonly isDefense: boolean;
+ readonly isAdministration: boolean;
+ readonly isTreasury: boolean;
+ readonly type: 'Unit' | 'Named' | 'Index' | 'Executive' | 'Technical' | 'Legislative' | 'Judicial' | 'Defense' | 'Administration' | 'Treasury';
+ }
+
+ /** @name StagingXcmV2BodyPart (135) */
+ interface StagingXcmV2BodyPart extends Enum {
+ readonly isVoice: boolean;
+ readonly isMembers: boolean;
+ readonly asMembers: {
+ readonly count: Compact<u32>;
+ } & Struct;
+ readonly isFraction: boolean;
+ readonly asFraction: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isAtLeastProportion: boolean;
+ readonly asAtLeastProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly isMoreThanProportion: boolean;
+ readonly asMoreThanProportion: {
+ readonly nom: Compact<u32>;
+ readonly denom: Compact<u32>;
+ } & Struct;
+ readonly type: 'Voice' | 'Members' | 'Fraction' | 'AtLeastProportion' | 'MoreThanProportion';
+ }
+
+ /** @name StagingXcmV3WeightLimit (136) */
+ interface StagingXcmV3WeightLimit extends Enum {
+ readonly isUnlimited: boolean;
+ readonly isLimited: boolean;
+ readonly asLimited: SpWeightsWeightV2Weight;
+ readonly type: 'Unlimited' | 'Limited';
+ }
+
+ /** @name StagingXcmVersionedMultiAsset (137) */
+ interface StagingXcmVersionedMultiAsset extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2MultiAsset;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiAsset;
+ readonly type: 'V2' | 'V3';
+ }
+
+ /** @name StagingXcmV2MultiAsset (138) */
+ interface StagingXcmV2MultiAsset extends Struct {
+ readonly id: StagingXcmV2MultiassetAssetId;
+ readonly fun: StagingXcmV2MultiassetFungibility;
+ }
+
+ /** @name StagingXcmV2MultiassetAssetId (139) */
+ interface StagingXcmV2MultiassetAssetId extends Enum {
+ readonly isConcrete: boolean;
+ readonly asConcrete: StagingXcmV2MultiLocation;
+ readonly isAbstract: boolean;
+ readonly asAbstract: Bytes;
+ readonly type: 'Concrete' | 'Abstract';
+ }
+
+ /** @name StagingXcmV2MultiassetFungibility (140) */
+ interface StagingXcmV2MultiassetFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly asFungible: Compact<u128>;
+ readonly isNonFungible: boolean;
+ readonly asNonFungible: StagingXcmV2MultiassetAssetInstance;
+ readonly type: 'Fungible' | 'NonFungible';
+ }
+
+ /** @name StagingXcmV2MultiassetAssetInstance (141) */
+ interface StagingXcmV2MultiassetAssetInstance extends Enum {
+ readonly isUndefined: boolean;
+ readonly isIndex: boolean;
+ readonly asIndex: Compact<u128>;
+ readonly isArray4: boolean;
+ readonly asArray4: U8aFixed;
+ readonly isArray8: boolean;
+ readonly asArray8: U8aFixed;
+ readonly isArray16: boolean;
+ readonly asArray16: U8aFixed;
+ readonly isArray32: boolean;
+ readonly asArray32: U8aFixed;
+ readonly isBlob: boolean;
+ readonly asBlob: Bytes;
+ readonly type: 'Undefined' | 'Index' | 'Array4' | 'Array8' | 'Array16' | 'Array32' | 'Blob';
+ }
+
+ /** @name StagingXcmVersionedMultiAssets (144) */
+ interface StagingXcmVersionedMultiAssets extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2MultiassetMultiAssets;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiassetMultiAssets;
+ readonly type: 'V2' | 'V3';
+ }
+
+ /** @name StagingXcmV2MultiassetMultiAssets (145) */
+ interface StagingXcmV2MultiassetMultiAssets extends Vec<StagingXcmV2MultiAsset> {}
+
+ /** @name OrmlTokensModuleCall (147) */
+ interface OrmlTokensModuleCall extends Enum {
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: Compact<u128>;
+ } & Struct;
+ readonly isTransferAll: boolean;
+ readonly asTransferAll: {
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly keepAlive: bool;
+ } & Struct;
+ readonly isTransferKeepAlive: boolean;
+ readonly asTransferKeepAlive: {
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: Compact<u128>;
+ } & Struct;
+ readonly isForceTransfer: boolean;
+ readonly asForceTransfer: {
+ readonly source: MultiAddress;
+ readonly dest: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly amount: Compact<u128>;
+ } & Struct;
+ readonly isSetBalance: boolean;
+ readonly asSetBalance: {
+ readonly who: MultiAddress;
+ readonly currencyId: PalletForeignAssetsAssetId;
+ readonly newFree: Compact<u128>;
+ readonly newReserved: Compact<u128>;
+ } & Struct;
+ readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance';
+ }
+
+ /** @name PalletIdentityCall (148) */
+ interface PalletIdentityCall extends Enum {
+ readonly isAddRegistrar: boolean;
+ readonly asAddRegistrar: {
+ readonly account: MultiAddress;
+ } & Struct;
+ readonly isSetIdentity: boolean;
+ readonly asSetIdentity: {
+ readonly info: PalletIdentityIdentityInfo;
+ } & Struct;
+ readonly isSetSubs: boolean;
+ readonly asSetSubs: {
+ readonly subs: Vec<ITuple<[AccountId32, Data]>>;
+ } & Struct;
+ readonly isClearIdentity: boolean;
+ readonly isRequestJudgement: boolean;
+ readonly asRequestJudgement: {
+ readonly regIndex: Compact<u32>;
+ readonly maxFee: Compact<u128>;
+ } & Struct;
+ readonly isCancelRequest: boolean;
+ readonly asCancelRequest: {
+ readonly regIndex: u32;
+ } & Struct;
+ readonly isSetFee: boolean;
+ readonly asSetFee: {
+ readonly index: Compact<u32>;
+ readonly fee: Compact<u128>;
+ } & Struct;
+ readonly isSetAccountId: boolean;
+ readonly asSetAccountId: {
+ readonly index: Compact<u32>;
+ readonly new_: MultiAddress;
+ } & Struct;
+ readonly isSetFields: boolean;
+ readonly asSetFields: {
+ readonly index: Compact<u32>;
+ readonly fields: PalletIdentityBitFlags;
+ } & Struct;
+ readonly isProvideJudgement: boolean;
+ readonly asProvideJudgement: {
+ readonly regIndex: Compact<u32>;
+ readonly target: MultiAddress;
+ readonly judgement: PalletIdentityJudgement;
+ readonly identity: H256;
+ } & Struct;
+ readonly isKillIdentity: boolean;
+ readonly asKillIdentity: {
+ readonly target: MultiAddress;
+ } & Struct;
+ readonly isAddSub: boolean;
+ readonly asAddSub: {
+ readonly sub: MultiAddress;
+ readonly data: Data;
+ } & Struct;
+ readonly isRenameSub: boolean;
+ readonly asRenameSub: {
+ readonly sub: MultiAddress;
+ readonly data: Data;
+ } & Struct;
+ readonly isRemoveSub: boolean;
+ readonly asRemoveSub: {
+ readonly sub: MultiAddress;
+ } & Struct;
+ readonly isQuitSub: boolean;
+ readonly isForceInsertIdentities: boolean;
+ readonly asForceInsertIdentities: {
+ readonly identities: Vec<ITuple<[AccountId32, PalletIdentityRegistration]>>;
+ } & Struct;
+ readonly isForceRemoveIdentities: boolean;
+ readonly asForceRemoveIdentities: {
+ readonly identities: Vec<AccountId32>;
+ } & Struct;
+ readonly isForceSetSubs: boolean;
+ readonly asForceSetSubs: {
+ readonly subs: Vec<ITuple<[AccountId32, ITuple<[u128, Vec<ITuple<[AccountId32, Data]>>]>]>>;
+ } & Struct;
+ readonly type: 'AddRegistrar' | 'SetIdentity' | 'SetSubs' | 'ClearIdentity' | 'RequestJudgement' | 'CancelRequest' | 'SetFee' | 'SetAccountId' | 'SetFields' | 'ProvideJudgement' | 'KillIdentity' | 'AddSub' | 'RenameSub' | 'RemoveSub' | 'QuitSub' | 'ForceInsertIdentities' | 'ForceRemoveIdentities' | 'ForceSetSubs';
+ }
+
+ /** @name PalletIdentityIdentityInfo (149) */
+ interface PalletIdentityIdentityInfo extends Struct {
+ readonly additional: Vec<ITuple<[Data, Data]>>;
+ readonly display: Data;
+ readonly legal: Data;
+ readonly web: Data;
+ readonly riot: Data;
+ readonly email: Data;
+ readonly pgpFingerprint: Option<U8aFixed>;
+ readonly image: Data;
+ readonly twitter: Data;
+ }
+
+ /** @name PalletIdentityBitFlags (185) */
+ interface PalletIdentityBitFlags extends Set {
+ readonly isDisplay: boolean;
+ readonly isLegal: boolean;
+ readonly isWeb: boolean;
+ readonly isRiot: boolean;
+ readonly isEmail: boolean;
+ readonly isPgpFingerprint: boolean;
+ readonly isImage: boolean;
+ readonly isTwitter: boolean;
+ }
+
+ /** @name PalletIdentityIdentityField (186) */
+ interface PalletIdentityIdentityField extends Enum {
+ readonly isDisplay: boolean;
+ readonly isLegal: boolean;
+ readonly isWeb: boolean;
+ readonly isRiot: boolean;
+ readonly isEmail: boolean;
+ readonly isPgpFingerprint: boolean;
+ readonly isImage: boolean;
+ readonly isTwitter: boolean;
+ readonly type: 'Display' | 'Legal' | 'Web' | 'Riot' | 'Email' | 'PgpFingerprint' | 'Image' | 'Twitter';
+ }
+
+ /** @name PalletIdentityJudgement (187) */
+ interface PalletIdentityJudgement extends Enum {
+ readonly isUnknown: boolean;
+ readonly isFeePaid: boolean;
+ readonly asFeePaid: u128;
+ readonly isReasonable: boolean;
+ readonly isKnownGood: boolean;
+ readonly isOutOfDate: boolean;
+ readonly isLowQuality: boolean;
+ readonly isErroneous: boolean;
+ readonly type: 'Unknown' | 'FeePaid' | 'Reasonable' | 'KnownGood' | 'OutOfDate' | 'LowQuality' | 'Erroneous';
+ }
+
+ /** @name PalletIdentityRegistration (190) */
+ interface PalletIdentityRegistration extends Struct {
+ readonly judgements: Vec<ITuple<[u32, PalletIdentityJudgement]>>;
+ readonly deposit: u128;
+ readonly info: PalletIdentityIdentityInfo;
+ }
+
+ /** @name PalletPreimageCall (198) */
+ interface PalletPreimageCall extends Enum {
+ readonly isNotePreimage: boolean;
+ readonly asNotePreimage: {
+ readonly bytes: Bytes;
+ } & Struct;
+ readonly isUnnotePreimage: boolean;
+ readonly asUnnotePreimage: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isRequestPreimage: boolean;
+ readonly asRequestPreimage: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly isUnrequestPreimage: boolean;
+ readonly asUnrequestPreimage: {
+ readonly hash_: H256;
+ } & Struct;
+ readonly type: 'NotePreimage' | 'UnnotePreimage' | 'RequestPreimage' | 'UnrequestPreimage';
+ }
+
+ /** @name PalletDemocracyCall (199) */
+ interface PalletDemocracyCall extends Enum {
+ readonly isPropose: boolean;
+ readonly asPropose: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly value: Compact<u128>;
+ } & Struct;
+ readonly isSecond: boolean;
+ readonly asSecond: {
+ readonly proposal: Compact<u32>;
+ } & Struct;
+ readonly isVote: boolean;
+ readonly asVote: {
+ readonly refIndex: Compact<u32>;
+ readonly vote: PalletDemocracyVoteAccountVote;
+ } & Struct;
+ readonly isEmergencyCancel: boolean;
+ readonly asEmergencyCancel: {
+ readonly refIndex: u32;
+ } & Struct;
+ readonly isExternalPropose: boolean;
+ readonly asExternalPropose: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isExternalProposeMajority: boolean;
+ readonly asExternalProposeMajority: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isExternalProposeDefault: boolean;
+ readonly asExternalProposeDefault: {
+ readonly proposal: FrameSupportPreimagesBounded;
+ } & Struct;
+ readonly isFastTrack: boolean;
+ readonly asFastTrack: {
+ readonly proposalHash: H256;
+ readonly votingPeriod: u32;
+ readonly delay: u32;
+ } & Struct;
+ readonly isVetoExternal: boolean;
+ readonly asVetoExternal: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isCancelReferendum: boolean;
+ readonly asCancelReferendum: {
+ readonly refIndex: Compact<u32>;
+ } & Struct;
+ readonly isDelegate: boolean;
+ readonly asDelegate: {
+ readonly to: MultiAddress;
+ readonly conviction: PalletDemocracyConviction;
+ readonly balance: u128;
+ } & Struct;
+ readonly isUndelegate: boolean;
+ readonly isClearPublicProposals: boolean;
+ readonly isUnlock: boolean;
+ readonly asUnlock: {
+ readonly target: MultiAddress;
+ } & Struct;
+ readonly isRemoveVote: boolean;
+ readonly asRemoveVote: {
+ readonly index: u32;
+ } & Struct;
+ readonly isRemoveOtherVote: boolean;
+ readonly asRemoveOtherVote: {
+ readonly target: MultiAddress;
+ readonly index: u32;
+ } & Struct;
+ readonly isBlacklist: boolean;
+ readonly asBlacklist: {
+ readonly proposalHash: H256;
+ readonly maybeRefIndex: Option<u32>;
+ } & Struct;
+ readonly isCancelProposal: boolean;
+ readonly asCancelProposal: {
+ readonly propIndex: Compact<u32>;
+ } & Struct;
+ readonly isSetMetadata: boolean;
+ readonly asSetMetadata: {
+ readonly owner: PalletDemocracyMetadataOwner;
+ readonly maybeHash: Option<H256>;
+ } & Struct;
+ readonly type: 'Propose' | 'Second' | 'Vote' | 'EmergencyCancel' | 'ExternalPropose' | 'ExternalProposeMajority' | 'ExternalProposeDefault' | 'FastTrack' | 'VetoExternal' | 'CancelReferendum' | 'Delegate' | 'Undelegate' | 'ClearPublicProposals' | 'Unlock' | 'RemoveVote' | 'RemoveOtherVote' | 'Blacklist' | 'CancelProposal' | 'SetMetadata';
+ }
+
+ /** @name PalletDemocracyConviction (200) */
+ interface PalletDemocracyConviction extends Enum {
+ readonly isNone: boolean;
+ readonly isLocked1x: boolean;
+ readonly isLocked2x: boolean;
+ readonly isLocked3x: boolean;
+ readonly isLocked4x: boolean;
+ readonly isLocked5x: boolean;
+ readonly isLocked6x: boolean;
+ readonly type: 'None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x' | 'Locked6x';
+ }
+
+ /** @name PalletCollectiveCall (203) */
+ interface PalletCollectiveCall extends Enum {
+ readonly isSetMembers: boolean;
+ readonly asSetMembers: {
+ readonly newMembers: Vec<AccountId32>;
+ readonly prime: Option<AccountId32>;
+ readonly oldCount: u32;
+ } & Struct;
+ readonly isExecute: boolean;
+ readonly asExecute: {
+ readonly proposal: Call;
+ readonly lengthBound: Compact<u32>;
+ } & Struct;
+ readonly isPropose: boolean;
+ readonly asPropose: {
+ readonly threshold: Compact<u32>;
+ readonly proposal: Call;
+ readonly lengthBound: Compact<u32>;
+ } & Struct;
+ readonly isVote: boolean;
+ readonly asVote: {
+ readonly proposal: H256;
+ readonly index: Compact<u32>;
+ readonly approve: bool;
+ } & Struct;
+ readonly isDisapproveProposal: boolean;
+ readonly asDisapproveProposal: {
+ readonly proposalHash: H256;
+ } & Struct;
+ readonly isClose: boolean;
+ readonly asClose: {
+ readonly proposalHash: H256;
+ readonly index: Compact<u32>;
+ readonly proposalWeightBound: SpWeightsWeightV2Weight;
+ readonly lengthBound: Compact<u32>;
+ } & Struct;
+ readonly type: 'SetMembers' | 'Execute' | 'Propose' | 'Vote' | 'DisapproveProposal' | 'Close';
+ }
+
+ /** @name PalletMembershipCall (205) */
+ interface PalletMembershipCall extends Enum {
+ readonly isAddMember: boolean;
+ readonly asAddMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isRemoveMember: boolean;
+ readonly asRemoveMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isSwapMember: boolean;
+ readonly asSwapMember: {
+ readonly remove: MultiAddress;
+ readonly add: MultiAddress;
+ } & Struct;
+ readonly isResetMembers: boolean;
+ readonly asResetMembers: {
+ readonly members: Vec<AccountId32>;
+ } & Struct;
+ readonly isChangeKey: boolean;
+ readonly asChangeKey: {
+ readonly new_: MultiAddress;
+ } & Struct;
+ readonly isSetPrime: boolean;
+ readonly asSetPrime: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isClearPrime: boolean;
+ readonly type: 'AddMember' | 'RemoveMember' | 'SwapMember' | 'ResetMembers' | 'ChangeKey' | 'SetPrime' | 'ClearPrime';
+ }
+
+ /** @name PalletRankedCollectiveCall (207) */
+ interface PalletRankedCollectiveCall extends Enum {
+ readonly isAddMember: boolean;
+ readonly asAddMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isPromoteMember: boolean;
+ readonly asPromoteMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isDemoteMember: boolean;
+ readonly asDemoteMember: {
+ readonly who: MultiAddress;
+ } & Struct;
+ readonly isRemoveMember: boolean;
+ readonly asRemoveMember: {
+ readonly who: MultiAddress;
+ readonly minRank: u16;
+ } & Struct;
+ readonly isVote: boolean;
+ readonly asVote: {
+ readonly poll: u32;
+ readonly aye: bool;
+ } & Struct;
+ readonly isCleanupPoll: boolean;
+ readonly asCleanupPoll: {
+ readonly pollIndex: u32;
+ readonly max: u32;
+ } & Struct;
+ readonly type: 'AddMember' | 'PromoteMember' | 'DemoteMember' | 'RemoveMember' | 'Vote' | 'CleanupPoll';
+ }
+
+ /** @name PalletReferendaCall (208) */
+ interface PalletReferendaCall extends Enum {
+ readonly isSubmit: boolean;
+ readonly asSubmit: {
+ readonly proposalOrigin: OpalRuntimeOriginCaller;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly enactmentMoment: FrameSupportScheduleDispatchTime;
+ } & Struct;
+ readonly isPlaceDecisionDeposit: boolean;
+ readonly asPlaceDecisionDeposit: {
+ readonly index: u32;
+ } & Struct;
+ readonly isRefundDecisionDeposit: boolean;
+ readonly asRefundDecisionDeposit: {
+ readonly index: u32;
+ } & Struct;
+ readonly isCancel: boolean;
+ readonly asCancel: {
+ readonly index: u32;
+ } & Struct;
+ readonly isKill: boolean;
+ readonly asKill: {
+ readonly index: u32;
+ } & Struct;
+ readonly isNudgeReferendum: boolean;
+ readonly asNudgeReferendum: {
+ readonly index: u32;
+ } & Struct;
+ readonly isOneFewerDeciding: boolean;
+ readonly asOneFewerDeciding: {
+ readonly track: u16;
+ } & Struct;
+ readonly isRefundSubmissionDeposit: boolean;
+ readonly asRefundSubmissionDeposit: {
+ readonly index: u32;
+ } & Struct;
+ readonly isSetMetadata: boolean;
+ readonly asSetMetadata: {
+ readonly index: u32;
+ readonly maybeHash: Option<H256>;
+ } & Struct;
+ readonly type: 'Submit' | 'PlaceDecisionDeposit' | 'RefundDecisionDeposit' | 'Cancel' | 'Kill' | 'NudgeReferendum' | 'OneFewerDeciding' | 'RefundSubmissionDeposit' | 'SetMetadata';
+ }
+
+ /** @name OpalRuntimeOriginCaller (209) */
+ interface OpalRuntimeOriginCaller extends Enum {
+ readonly isSystem: boolean;
+ readonly asSystem: FrameSupportDispatchRawOrigin;
+ readonly isVoid: boolean;
+ readonly isCouncil: boolean;
+ readonly asCouncil: PalletCollectiveRawOrigin;
+ readonly isTechnicalCommittee: boolean;
+ readonly asTechnicalCommittee: PalletCollectiveRawOrigin;
+ readonly isPolkadotXcm: boolean;
+ readonly asPolkadotXcm: PalletXcmOrigin;
+ readonly isCumulusXcm: boolean;
+ readonly asCumulusXcm: CumulusPalletXcmOrigin;
+ readonly isOrigins: boolean;
+ readonly asOrigins: PalletGovOriginsOrigin;
+ readonly isEthereum: boolean;
+ readonly asEthereum: PalletEthereumRawOrigin;
+ readonly type: 'System' | 'Void' | 'Council' | 'TechnicalCommittee' | 'PolkadotXcm' | 'CumulusXcm' | 'Origins' | 'Ethereum';
+ }
+
+ /** @name FrameSupportDispatchRawOrigin (210) */
+ interface FrameSupportDispatchRawOrigin extends Enum {
+ readonly isRoot: boolean;
+ readonly isSigned: boolean;
+ readonly asSigned: AccountId32;
+ readonly isNone: boolean;
+ readonly type: 'Root' | 'Signed' | 'None';
+ }
+
+ /** @name PalletCollectiveRawOrigin (211) */
+ interface PalletCollectiveRawOrigin extends Enum {
+ readonly isMembers: boolean;
+ readonly asMembers: ITuple<[u32, u32]>;
+ readonly isMember: boolean;
+ readonly asMember: AccountId32;
+ readonly isPhantom: boolean;
+ readonly type: 'Members' | 'Member' | 'Phantom';
+ }
+
+ /** @name PalletGovOriginsOrigin (213) */
+ interface PalletGovOriginsOrigin extends Enum {
+ readonly isFellowshipProposition: boolean;
+ readonly type: 'FellowshipProposition';
+ }
+
+ /** @name PalletXcmOrigin (214) */
+ interface PalletXcmOrigin extends Enum {
+ readonly isXcm: boolean;
+ readonly asXcm: StagingXcmV3MultiLocation;
+ readonly isResponse: boolean;
+ readonly asResponse: StagingXcmV3MultiLocation;
+ readonly type: 'Xcm' | 'Response';
+ }
+
+ /** @name CumulusPalletXcmOrigin (215) */
+ interface CumulusPalletXcmOrigin extends Enum {
+ readonly isRelay: boolean;
+ readonly isSiblingParachain: boolean;
+ readonly asSiblingParachain: u32;
+ readonly type: 'Relay' | 'SiblingParachain';
+ }
+
+ /** @name PalletEthereumRawOrigin (216) */
+ interface PalletEthereumRawOrigin extends Enum {
+ readonly isEthereumTransaction: boolean;
+ readonly asEthereumTransaction: H160;
+ readonly type: 'EthereumTransaction';
+ }
+
+ /** @name SpCoreVoid (218) */
+ type SpCoreVoid = Null;
+
+ /** @name FrameSupportScheduleDispatchTime (219) */
+ interface FrameSupportScheduleDispatchTime extends Enum {
+ readonly isAt: boolean;
+ readonly asAt: u32;
+ readonly isAfter: boolean;
+ readonly asAfter: u32;
+ readonly type: 'At' | 'After';
+ }
+
+ /** @name PalletSchedulerCall (220) */
+ interface PalletSchedulerCall extends Enum {
+ readonly isSchedule: boolean;
+ readonly asSchedule: {
+ readonly when: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly isCancel: boolean;
+ readonly asCancel: {
+ readonly when: u32;
+ readonly index: u32;
+ } & Struct;
+ readonly isScheduleNamed: boolean;
+ readonly asScheduleNamed: {
+ readonly id: U8aFixed;
+ readonly when: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly isCancelNamed: boolean;
+ readonly asCancelNamed: {
+ readonly id: U8aFixed;
+ } & Struct;
+ readonly isScheduleAfter: boolean;
+ readonly asScheduleAfter: {
+ readonly after: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly isScheduleNamedAfter: boolean;
+ readonly asScheduleNamedAfter: {
+ readonly id: U8aFixed;
+ readonly after: u32;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly priority: u8;
+ readonly call: Call;
+ } & Struct;
+ readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter';
+ }
+
+ /** @name CumulusPalletXcmpQueueCall (223) */
+ interface CumulusPalletXcmpQueueCall extends Enum {
+ readonly isServiceOverweight: boolean;
+ readonly asServiceOverweight: {
+ readonly index: u64;
+ readonly weightLimit: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isSuspendXcmExecution: boolean;
+ readonly isResumeXcmExecution: boolean;
+ readonly isUpdateSuspendThreshold: boolean;
+ readonly asUpdateSuspendThreshold: {
+ readonly new_: u32;
+ } & Struct;
+ readonly isUpdateDropThreshold: boolean;
+ readonly asUpdateDropThreshold: {
+ readonly new_: u32;
+ } & Struct;
+ readonly isUpdateResumeThreshold: boolean;
+ readonly asUpdateResumeThreshold: {
+ readonly new_: u32;
+ } & Struct;
+ readonly isUpdateThresholdWeight: boolean;
+ readonly asUpdateThresholdWeight: {
+ readonly new_: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isUpdateWeightRestrictDecay: boolean;
+ readonly asUpdateWeightRestrictDecay: {
+ readonly new_: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isUpdateXcmpMaxIndividualWeight: boolean;
+ readonly asUpdateXcmpMaxIndividualWeight: {
+ readonly new_: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
+ }
+
+ /** @name PalletXcmCall (224) */
+ interface PalletXcmCall extends Enum {
+ readonly isSend: boolean;
+ readonly asSend: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly message: StagingXcmVersionedXcm;
+ } & Struct;
+ readonly isTeleportAssets: boolean;
+ readonly asTeleportAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ } & Struct;
+ readonly isReserveTransferAssets: boolean;
+ readonly asReserveTransferAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ } & Struct;
+ readonly isExecute: boolean;
+ readonly asExecute: {
+ readonly message: StagingXcmVersionedXcm;
+ readonly maxWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isForceXcmVersion: boolean;
+ readonly asForceXcmVersion: {
+ readonly location: StagingXcmV3MultiLocation;
+ readonly version: u32;
+ } & Struct;
+ readonly isForceDefaultXcmVersion: boolean;
+ readonly asForceDefaultXcmVersion: {
+ readonly maybeXcmVersion: Option<u32>;
+ } & Struct;
+ readonly isForceSubscribeVersionNotify: boolean;
+ readonly asForceSubscribeVersionNotify: {
+ readonly location: StagingXcmVersionedMultiLocation;
+ } & Struct;
+ readonly isForceUnsubscribeVersionNotify: boolean;
+ readonly asForceUnsubscribeVersionNotify: {
+ readonly location: StagingXcmVersionedMultiLocation;
+ } & Struct;
+ readonly isLimitedReserveTransferAssets: boolean;
+ readonly asLimitedReserveTransferAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isLimitedTeleportAssets: boolean;
+ readonly asLimitedTeleportAssets: {
+ readonly dest: StagingXcmVersionedMultiLocation;
+ readonly beneficiary: StagingXcmVersionedMultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ readonly feeAssetItem: u32;
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isForceSuspension: boolean;
+ readonly asForceSuspension: {
+ readonly suspended: bool;
+ } & Struct;
+ readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets' | 'ForceSuspension';
+ }
+
+ /** @name StagingXcmVersionedXcm (225) */
+ interface StagingXcmVersionedXcm extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2Xcm;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3Xcm;
+ readonly type: 'V2' | 'V3';
+ }
+
+ /** @name StagingXcmV2Xcm (226) */
+ interface StagingXcmV2Xcm extends Vec<StagingXcmV2Instruction> {}
+
+ /** @name StagingXcmV2Instruction (228) */
+ interface StagingXcmV2Instruction extends Enum {
+ readonly isWithdrawAsset: boolean;
+ readonly asWithdrawAsset: StagingXcmV2MultiassetMultiAssets;
+ readonly isReserveAssetDeposited: boolean;
+ readonly asReserveAssetDeposited: StagingXcmV2MultiassetMultiAssets;
+ readonly isReceiveTeleportedAsset: boolean;
+ readonly asReceiveTeleportedAsset: StagingXcmV2MultiassetMultiAssets;
+ readonly isQueryResponse: boolean;
+ readonly asQueryResponse: {
+ readonly queryId: Compact<u64>;
+ readonly response: StagingXcmV2Response;
+ readonly maxWeight: Compact<u64>;
+ } & Struct;
+ readonly isTransferAsset: boolean;
+ readonly asTransferAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssets;
+ readonly beneficiary: StagingXcmV2MultiLocation;
+ } & Struct;
+ readonly isTransferReserveAsset: boolean;
+ readonly asTransferReserveAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssets;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isTransact: boolean;
+ readonly asTransact: {
+ readonly originType: StagingXcmV2OriginKind;
+ readonly requireWeightAtMost: Compact<u64>;
+ readonly call: StagingXcmDoubleEncoded;
+ } & Struct;
+ readonly isHrmpNewChannelOpenRequest: boolean;
+ readonly asHrmpNewChannelOpenRequest: {
+ readonly sender: Compact<u32>;
+ readonly maxMessageSize: Compact<u32>;
+ readonly maxCapacity: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelAccepted: boolean;
+ readonly asHrmpChannelAccepted: {
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelClosing: boolean;
+ readonly asHrmpChannelClosing: {
+ readonly initiator: Compact<u32>;
+ readonly sender: Compact<u32>;
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isClearOrigin: boolean;
+ readonly isDescendOrigin: boolean;
+ readonly asDescendOrigin: StagingXcmV2MultilocationJunctions;
+ readonly isReportError: boolean;
+ readonly asReportError: {
+ readonly queryId: Compact<u64>;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly maxResponseWeight: Compact<u64>;
+ } & Struct;
+ readonly isDepositAsset: boolean;
+ readonly asDepositAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly maxAssets: Compact<u32>;
+ readonly beneficiary: StagingXcmV2MultiLocation;
+ } & Struct;
+ readonly isDepositReserveAsset: boolean;
+ readonly asDepositReserveAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly maxAssets: Compact<u32>;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isExchangeAsset: boolean;
+ readonly asExchangeAsset: {
+ readonly give: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly receive: StagingXcmV2MultiassetMultiAssets;
+ } & Struct;
+ readonly isInitiateReserveWithdraw: boolean;
+ readonly asInitiateReserveWithdraw: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly reserve: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isInitiateTeleport: boolean;
+ readonly asInitiateTeleport: {
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly xcm: StagingXcmV2Xcm;
+ } & Struct;
+ readonly isQueryHolding: boolean;
+ readonly asQueryHolding: {
+ readonly queryId: Compact<u64>;
+ readonly dest: StagingXcmV2MultiLocation;
+ readonly assets: StagingXcmV2MultiassetMultiAssetFilter;
+ readonly maxResponseWeight: Compact<u64>;
+ } & Struct;
+ readonly isBuyExecution: boolean;
+ readonly asBuyExecution: {
+ readonly fees: StagingXcmV2MultiAsset;
+ readonly weightLimit: StagingXcmV2WeightLimit;
+ } & Struct;
+ readonly isRefundSurplus: boolean;
+ readonly isSetErrorHandler: boolean;
+ readonly asSetErrorHandler: StagingXcmV2Xcm;
+ readonly isSetAppendix: boolean;
+ readonly asSetAppendix: StagingXcmV2Xcm;
+ readonly isClearError: boolean;
+ readonly isClaimAsset: boolean;
+ readonly asClaimAsset: {
+ readonly assets: StagingXcmV2MultiassetMultiAssets;
+ readonly ticket: StagingXcmV2MultiLocation;
+ } & Struct;
+ readonly isTrap: boolean;
+ readonly asTrap: Compact<u64>;
+ readonly isSubscribeVersion: boolean;
+ readonly asSubscribeVersion: {
+ readonly queryId: Compact<u64>;
+ readonly maxResponseWeight: Compact<u64>;
+ } & Struct;
+ readonly isUnsubscribeVersion: boolean;
+ readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion';
+ }
+
+ /** @name StagingXcmV2Response (229) */
+ interface StagingXcmV2Response extends Enum {
+ readonly isNull: boolean;
+ readonly isAssets: boolean;
+ readonly asAssets: StagingXcmV2MultiassetMultiAssets;
+ readonly isExecutionResult: boolean;
+ readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV2TraitsError]>>;
+ readonly isVersion: boolean;
+ readonly asVersion: u32;
+ readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version';
+ }
+
+ /** @name StagingXcmV2TraitsError (232) */
+ interface StagingXcmV2TraitsError extends Enum {
+ readonly isOverflow: boolean;
+ readonly isUnimplemented: boolean;
+ readonly isUntrustedReserveLocation: boolean;
+ readonly isUntrustedTeleportLocation: boolean;
+ readonly isMultiLocationFull: boolean;
+ readonly isMultiLocationNotInvertible: boolean;
+ readonly isBadOrigin: boolean;
+ readonly isInvalidLocation: boolean;
+ readonly isAssetNotFound: boolean;
+ readonly isFailedToTransactAsset: boolean;
+ readonly isNotWithdrawable: boolean;
+ readonly isLocationCannotHold: boolean;
+ readonly isExceedsMaxMessageSize: boolean;
+ readonly isDestinationUnsupported: boolean;
+ readonly isTransport: boolean;
+ readonly isUnroutable: boolean;
+ readonly isUnknownClaim: boolean;
+ readonly isFailedToDecode: boolean;
+ readonly isMaxWeightInvalid: boolean;
+ readonly isNotHoldingFees: boolean;
+ readonly isTooExpensive: boolean;
+ readonly isTrap: boolean;
+ readonly asTrap: u64;
+ readonly isUnhandledXcmVersion: boolean;
+ readonly isWeightLimitReached: boolean;
+ readonly asWeightLimitReached: u64;
+ readonly isBarrier: boolean;
+ readonly isWeightNotComputable: boolean;
+ readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'MultiLocationFull' | 'MultiLocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable';
+ }
+
+ /** @name StagingXcmV2OriginKind (233) */
+ interface StagingXcmV2OriginKind extends Enum {
+ readonly isNative: boolean;
+ readonly isSovereignAccount: boolean;
+ readonly isSuperuser: boolean;
+ readonly isXcm: boolean;
+ readonly type: 'Native' | 'SovereignAccount' | 'Superuser' | 'Xcm';
+ }
+
+ /** @name StagingXcmDoubleEncoded (234) */
+ interface StagingXcmDoubleEncoded extends Struct {
+ readonly encoded: Bytes;
+ }
+
+ /** @name StagingXcmV2MultiassetMultiAssetFilter (235) */
+ interface StagingXcmV2MultiassetMultiAssetFilter extends Enum {
+ readonly isDefinite: boolean;
+ readonly asDefinite: StagingXcmV2MultiassetMultiAssets;
+ readonly isWild: boolean;
+ readonly asWild: StagingXcmV2MultiassetWildMultiAsset;
+ readonly type: 'Definite' | 'Wild';
+ }
+
+ /** @name StagingXcmV2MultiassetWildMultiAsset (236) */
+ interface StagingXcmV2MultiassetWildMultiAsset extends Enum {
+ readonly isAll: boolean;
+ readonly isAllOf: boolean;
+ readonly asAllOf: {
+ readonly id: StagingXcmV2MultiassetAssetId;
+ readonly fun: StagingXcmV2MultiassetWildFungibility;
+ } & Struct;
+ readonly type: 'All' | 'AllOf';
+ }
+
+ /** @name StagingXcmV2MultiassetWildFungibility (237) */
+ interface StagingXcmV2MultiassetWildFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly isNonFungible: boolean;
+ readonly type: 'Fungible' | 'NonFungible';
+ }
+
+ /** @name StagingXcmV2WeightLimit (238) */
+ interface StagingXcmV2WeightLimit extends Enum {
+ readonly isUnlimited: boolean;
+ readonly isLimited: boolean;
+ readonly asLimited: Compact<u64>;
+ readonly type: 'Unlimited' | 'Limited';
+ }
+
+ /** @name StagingXcmV3Xcm (239) */
+ interface StagingXcmV3Xcm extends Vec<StagingXcmV3Instruction> {}
+
+ /** @name StagingXcmV3Instruction (241) */
+ interface StagingXcmV3Instruction extends Enum {
+ readonly isWithdrawAsset: boolean;
+ readonly asWithdrawAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isReserveAssetDeposited: boolean;
+ readonly asReserveAssetDeposited: StagingXcmV3MultiassetMultiAssets;
+ readonly isReceiveTeleportedAsset: boolean;
+ readonly asReceiveTeleportedAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isQueryResponse: boolean;
+ readonly asQueryResponse: {
+ readonly queryId: Compact<u64>;
+ readonly response: StagingXcmV3Response;
+ readonly maxWeight: SpWeightsWeightV2Weight;
+ readonly querier: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly isTransferAsset: boolean;
+ readonly asTransferAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly beneficiary: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isTransferReserveAsset: boolean;
+ readonly asTransferReserveAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly dest: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isTransact: boolean;
+ readonly asTransact: {
+ readonly originKind: StagingXcmV2OriginKind;
+ readonly requireWeightAtMost: SpWeightsWeightV2Weight;
+ readonly call: StagingXcmDoubleEncoded;
+ } & Struct;
+ readonly isHrmpNewChannelOpenRequest: boolean;
+ readonly asHrmpNewChannelOpenRequest: {
+ readonly sender: Compact<u32>;
+ readonly maxMessageSize: Compact<u32>;
+ readonly maxCapacity: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelAccepted: boolean;
+ readonly asHrmpChannelAccepted: {
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isHrmpChannelClosing: boolean;
+ readonly asHrmpChannelClosing: {
+ readonly initiator: Compact<u32>;
+ readonly sender: Compact<u32>;
+ readonly recipient: Compact<u32>;
+ } & Struct;
+ readonly isClearOrigin: boolean;
+ readonly isDescendOrigin: boolean;
+ readonly asDescendOrigin: StagingXcmV3Junctions;
+ readonly isReportError: boolean;
+ readonly asReportError: StagingXcmV3QueryResponseInfo;
+ readonly isDepositAsset: boolean;
+ readonly asDepositAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly beneficiary: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isDepositReserveAsset: boolean;
+ readonly asDepositReserveAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly dest: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isExchangeAsset: boolean;
+ readonly asExchangeAsset: {
+ readonly give: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly want: StagingXcmV3MultiassetMultiAssets;
+ readonly maximal: bool;
+ } & Struct;
+ readonly isInitiateReserveWithdraw: boolean;
+ readonly asInitiateReserveWithdraw: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly reserve: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isInitiateTeleport: boolean;
+ readonly asInitiateTeleport: {
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ readonly dest: StagingXcmV3MultiLocation;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isReportHolding: boolean;
+ readonly asReportHolding: {
+ readonly responseInfo: StagingXcmV3QueryResponseInfo;
+ readonly assets: StagingXcmV3MultiassetMultiAssetFilter;
+ } & Struct;
+ readonly isBuyExecution: boolean;
+ readonly asBuyExecution: {
+ readonly fees: StagingXcmV3MultiAsset;
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ } & Struct;
+ readonly isRefundSurplus: boolean;
+ readonly isSetErrorHandler: boolean;
+ readonly asSetErrorHandler: StagingXcmV3Xcm;
+ readonly isSetAppendix: boolean;
+ readonly asSetAppendix: StagingXcmV3Xcm;
+ readonly isClearError: boolean;
+ readonly isClaimAsset: boolean;
+ readonly asClaimAsset: {
+ readonly assets: StagingXcmV3MultiassetMultiAssets;
+ readonly ticket: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isTrap: boolean;
+ readonly asTrap: Compact<u64>;
+ readonly isSubscribeVersion: boolean;
+ readonly asSubscribeVersion: {
+ readonly queryId: Compact<u64>;
+ readonly maxResponseWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isUnsubscribeVersion: boolean;
+ readonly isBurnAsset: boolean;
+ readonly asBurnAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isExpectAsset: boolean;
+ readonly asExpectAsset: StagingXcmV3MultiassetMultiAssets;
+ readonly isExpectOrigin: boolean;
+ readonly asExpectOrigin: Option<StagingXcmV3MultiLocation>;
+ readonly isExpectError: boolean;
+ readonly asExpectError: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
+ readonly isExpectTransactStatus: boolean;
+ readonly asExpectTransactStatus: StagingXcmV3MaybeErrorCode;
+ readonly isQueryPallet: boolean;
+ readonly asQueryPallet: {
+ readonly moduleName: Bytes;
+ readonly responseInfo: StagingXcmV3QueryResponseInfo;
+ } & Struct;
+ readonly isExpectPallet: boolean;
+ readonly asExpectPallet: {
+ readonly index: Compact<u32>;
+ readonly name: Bytes;
+ readonly moduleName: Bytes;
+ readonly crateMajor: Compact<u32>;
+ readonly minCrateMinor: Compact<u32>;
+ } & Struct;
+ readonly isReportTransactStatus: boolean;
+ readonly asReportTransactStatus: StagingXcmV3QueryResponseInfo;
+ readonly isClearTransactStatus: boolean;
+ readonly isUniversalOrigin: boolean;
+ readonly asUniversalOrigin: StagingXcmV3Junction;
+ readonly isExportMessage: boolean;
+ readonly asExportMessage: {
+ readonly network: StagingXcmV3JunctionNetworkId;
+ readonly destination: StagingXcmV3Junctions;
+ readonly xcm: StagingXcmV3Xcm;
+ } & Struct;
+ readonly isLockAsset: boolean;
+ readonly asLockAsset: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly unlocker: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isUnlockAsset: boolean;
+ readonly asUnlockAsset: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly target: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isNoteUnlockable: boolean;
+ readonly asNoteUnlockable: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly owner: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isRequestUnlock: boolean;
+ readonly asRequestUnlock: {
+ readonly asset: StagingXcmV3MultiAsset;
+ readonly locker: StagingXcmV3MultiLocation;
+ } & Struct;
+ readonly isSetFeesMode: boolean;
+ readonly asSetFeesMode: {
+ readonly jitWithdraw: bool;
+ } & Struct;
+ readonly isSetTopic: boolean;
+ readonly asSetTopic: U8aFixed;
+ readonly isClearTopic: boolean;
+ readonly isAliasOrigin: boolean;
+ readonly asAliasOrigin: StagingXcmV3MultiLocation;
+ readonly isUnpaidExecution: boolean;
+ readonly asUnpaidExecution: {
+ readonly weightLimit: StagingXcmV3WeightLimit;
+ readonly checkOrigin: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'ClearOrigin' | 'DescendOrigin' | 'ReportError' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'ReportHolding' | 'BuyExecution' | 'RefundSurplus' | 'SetErrorHandler' | 'SetAppendix' | 'ClearError' | 'ClaimAsset' | 'Trap' | 'SubscribeVersion' | 'UnsubscribeVersion' | 'BurnAsset' | 'ExpectAsset' | 'ExpectOrigin' | 'ExpectError' | 'ExpectTransactStatus' | 'QueryPallet' | 'ExpectPallet' | 'ReportTransactStatus' | 'ClearTransactStatus' | 'UniversalOrigin' | 'ExportMessage' | 'LockAsset' | 'UnlockAsset' | 'NoteUnlockable' | 'RequestUnlock' | 'SetFeesMode' | 'SetTopic' | 'ClearTopic' | 'AliasOrigin' | 'UnpaidExecution';
+ }
+
+ /** @name StagingXcmV3Response (242) */
+ interface StagingXcmV3Response extends Enum {
+ readonly isNull: boolean;
+ readonly isAssets: boolean;
+ readonly asAssets: StagingXcmV3MultiassetMultiAssets;
+ readonly isExecutionResult: boolean;
+ readonly asExecutionResult: Option<ITuple<[u32, StagingXcmV3TraitsError]>>;
+ readonly isVersion: boolean;
+ readonly asVersion: u32;
+ readonly isPalletsInfo: boolean;
+ readonly asPalletsInfo: Vec<StagingXcmV3PalletInfo>;
+ readonly isDispatchResult: boolean;
+ readonly asDispatchResult: StagingXcmV3MaybeErrorCode;
+ readonly type: 'Null' | 'Assets' | 'ExecutionResult' | 'Version' | 'PalletsInfo' | 'DispatchResult';
+ }
+
+ /** @name StagingXcmV3TraitsError (245) */
+ interface StagingXcmV3TraitsError extends Enum {
+ readonly isOverflow: boolean;
+ readonly isUnimplemented: boolean;
+ readonly isUntrustedReserveLocation: boolean;
+ readonly isUntrustedTeleportLocation: boolean;
+ readonly isLocationFull: boolean;
+ readonly isLocationNotInvertible: boolean;
+ readonly isBadOrigin: boolean;
+ readonly isInvalidLocation: boolean;
+ readonly isAssetNotFound: boolean;
+ readonly isFailedToTransactAsset: boolean;
+ readonly isNotWithdrawable: boolean;
+ readonly isLocationCannotHold: boolean;
+ readonly isExceedsMaxMessageSize: boolean;
+ readonly isDestinationUnsupported: boolean;
+ readonly isTransport: boolean;
+ readonly isUnroutable: boolean;
+ readonly isUnknownClaim: boolean;
+ readonly isFailedToDecode: boolean;
+ readonly isMaxWeightInvalid: boolean;
+ readonly isNotHoldingFees: boolean;
+ readonly isTooExpensive: boolean;
+ readonly isTrap: boolean;
+ readonly asTrap: u64;
+ readonly isExpectationFalse: boolean;
+ readonly isPalletNotFound: boolean;
+ readonly isNameMismatch: boolean;
+ readonly isVersionIncompatible: boolean;
+ readonly isHoldingWouldOverflow: boolean;
+ readonly isExportError: boolean;
+ readonly isReanchorFailed: boolean;
+ readonly isNoDeal: boolean;
+ readonly isFeesNotMet: boolean;
+ readonly isLockError: boolean;
+ readonly isNoPermission: boolean;
+ readonly isUnanchored: boolean;
+ readonly isNotDepositable: boolean;
+ readonly isUnhandledXcmVersion: boolean;
+ readonly isWeightLimitReached: boolean;
+ readonly asWeightLimitReached: SpWeightsWeightV2Weight;
+ readonly isBarrier: boolean;
+ readonly isWeightNotComputable: boolean;
+ readonly isExceedsStackLimit: boolean;
+ readonly type: 'Overflow' | 'Unimplemented' | 'UntrustedReserveLocation' | 'UntrustedTeleportLocation' | 'LocationFull' | 'LocationNotInvertible' | 'BadOrigin' | 'InvalidLocation' | 'AssetNotFound' | 'FailedToTransactAsset' | 'NotWithdrawable' | 'LocationCannotHold' | 'ExceedsMaxMessageSize' | 'DestinationUnsupported' | 'Transport' | 'Unroutable' | 'UnknownClaim' | 'FailedToDecode' | 'MaxWeightInvalid' | 'NotHoldingFees' | 'TooExpensive' | 'Trap' | 'ExpectationFalse' | 'PalletNotFound' | 'NameMismatch' | 'VersionIncompatible' | 'HoldingWouldOverflow' | 'ExportError' | 'ReanchorFailed' | 'NoDeal' | 'FeesNotMet' | 'LockError' | 'NoPermission' | 'Unanchored' | 'NotDepositable' | 'UnhandledXcmVersion' | 'WeightLimitReached' | 'Barrier' | 'WeightNotComputable' | 'ExceedsStackLimit';
+ }
+
+ /** @name StagingXcmV3PalletInfo (247) */
+ interface StagingXcmV3PalletInfo extends Struct {
+ readonly index: Compact<u32>;
+ readonly name: Bytes;
+ readonly moduleName: Bytes;
+ readonly major: Compact<u32>;
+ readonly minor: Compact<u32>;
+ readonly patch: Compact<u32>;
+ }
+
+ /** @name StagingXcmV3MaybeErrorCode (250) */
+ interface StagingXcmV3MaybeErrorCode extends Enum {
+ readonly isSuccess: boolean;
+ readonly isError: boolean;
+ readonly asError: Bytes;
+ readonly isTruncatedError: boolean;
+ readonly asTruncatedError: Bytes;
+ readonly type: 'Success' | 'Error' | 'TruncatedError';
+ }
+
+ /** @name StagingXcmV3QueryResponseInfo (253) */
+ interface StagingXcmV3QueryResponseInfo extends Struct {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly queryId: Compact<u64>;
+ readonly maxWeight: SpWeightsWeightV2Weight;
+ }
+
+ /** @name StagingXcmV3MultiassetMultiAssetFilter (254) */
+ interface StagingXcmV3MultiassetMultiAssetFilter extends Enum {
+ readonly isDefinite: boolean;
+ readonly asDefinite: StagingXcmV3MultiassetMultiAssets;
+ readonly isWild: boolean;
+ readonly asWild: StagingXcmV3MultiassetWildMultiAsset;
+ readonly type: 'Definite' | 'Wild';
+ }
+
+ /** @name StagingXcmV3MultiassetWildMultiAsset (255) */
+ interface StagingXcmV3MultiassetWildMultiAsset extends Enum {
+ readonly isAll: boolean;
+ readonly isAllOf: boolean;
+ readonly asAllOf: {
+ readonly id: StagingXcmV3MultiassetAssetId;
+ readonly fun: StagingXcmV3MultiassetWildFungibility;
+ } & Struct;
+ readonly isAllCounted: boolean;
+ readonly asAllCounted: Compact<u32>;
+ readonly isAllOfCounted: boolean;
+ readonly asAllOfCounted: {
+ readonly id: StagingXcmV3MultiassetAssetId;
+ readonly fun: StagingXcmV3MultiassetWildFungibility;
+ readonly count: Compact<u32>;
+ } & Struct;
+ readonly type: 'All' | 'AllOf' | 'AllCounted' | 'AllOfCounted';
+ }
+
+ /** @name StagingXcmV3MultiassetWildFungibility (256) */
+ interface StagingXcmV3MultiassetWildFungibility extends Enum {
+ readonly isFungible: boolean;
+ readonly isNonFungible: boolean;
+ readonly type: 'Fungible' | 'NonFungible';
+ }
+
+ /** @name CumulusPalletXcmCall (265) */
+ type CumulusPalletXcmCall = Null;
+
+ /** @name CumulusPalletDmpQueueCall (266) */
+ interface CumulusPalletDmpQueueCall extends Enum {
+ readonly isServiceOverweight: boolean;
+ readonly asServiceOverweight: {
+ readonly index: u64;
+ readonly weightLimit: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'ServiceOverweight';
+ }
+
+ /** @name PalletInflationCall (267) */
+ interface PalletInflationCall extends Enum {
+ readonly isStartInflation: boolean;
+ readonly asStartInflation: {
+ readonly inflationStartRelayBlock: u32;
+ } & Struct;
+ readonly type: 'StartInflation';
+ }
+
+ /** @name PalletUniqueCall (268) */
+ interface PalletUniqueCall extends Enum {
+ readonly isCreateCollection: boolean;
+ readonly asCreateCollection: {
+ readonly collectionName: Vec<u16>;
+ readonly collectionDescription: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly mode: UpDataStructsCollectionMode;
+ } & Struct;
+ readonly isCreateCollectionEx: boolean;
+ readonly asCreateCollectionEx: {
+ readonly data: UpDataStructsCreateCollectionData;
+ } & Struct;
+ readonly isDestroyCollection: boolean;
+ readonly asDestroyCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isAddToAllowList: boolean;
+ readonly asAddToAllowList: {
+ readonly collectionId: u32;
+ readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isRemoveFromAllowList: boolean;
+ readonly asRemoveFromAllowList: {
+ readonly collectionId: u32;
+ readonly address: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isChangeCollectionOwner: boolean;
+ readonly asChangeCollectionOwner: {
+ readonly collectionId: u32;
+ readonly newOwner: AccountId32;
+ } & Struct;
+ readonly isAddCollectionAdmin: boolean;
+ readonly asAddCollectionAdmin: {
+ readonly collectionId: u32;
+ readonly newAdminId: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isRemoveCollectionAdmin: boolean;
+ readonly asRemoveCollectionAdmin: {
+ readonly collectionId: u32;
+ readonly accountId: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isSetCollectionSponsor: boolean;
+ readonly asSetCollectionSponsor: {
+ readonly collectionId: u32;
+ readonly newSponsor: AccountId32;
+ } & Struct;
+ readonly isConfirmSponsorship: boolean;
+ readonly asConfirmSponsorship: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isRemoveCollectionSponsor: boolean;
+ readonly asRemoveCollectionSponsor: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isCreateItem: boolean;
+ readonly asCreateItem: {
+ readonly collectionId: u32;
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly data: UpDataStructsCreateItemData;
+ } & Struct;
+ readonly isCreateMultipleItems: boolean;
+ readonly asCreateMultipleItems: {
+ readonly collectionId: u32;
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly itemsData: Vec<UpDataStructsCreateItemData>;
+ } & Struct;
+ readonly isSetCollectionProperties: boolean;
+ readonly asSetCollectionProperties: {
+ readonly collectionId: u32;
+ readonly properties: Vec<UpDataStructsProperty>;
+ } & Struct;
+ readonly isDeleteCollectionProperties: boolean;
+ readonly asDeleteCollectionProperties: {
+ readonly collectionId: u32;
+ readonly propertyKeys: Vec<Bytes>;
+ } & Struct;
+ readonly isSetTokenProperties: boolean;
+ readonly asSetTokenProperties: {
+ readonly collectionId: u32;
+ readonly tokenId: u32;
+ readonly properties: Vec<UpDataStructsProperty>;
+ } & Struct;
+ readonly isDeleteTokenProperties: boolean;
+ readonly asDeleteTokenProperties: {
+ readonly collectionId: u32;
+ readonly tokenId: u32;
+ readonly propertyKeys: Vec<Bytes>;
+ } & Struct;
+ readonly isSetTokenPropertyPermissions: boolean;
+ readonly asSetTokenPropertyPermissions: {
+ readonly collectionId: u32;
+ readonly propertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
+ } & Struct;
+ readonly isCreateMultipleItemsEx: boolean;
+ readonly asCreateMultipleItemsEx: {
+ readonly collectionId: u32;
+ readonly data: UpDataStructsCreateItemExData;
+ } & Struct;
+ readonly isSetTransfersEnabledFlag: boolean;
+ readonly asSetTransfersEnabledFlag: {
+ readonly collectionId: u32;
+ readonly value: bool;
+ } & Struct;
+ readonly isBurnItem: boolean;
+ readonly asBurnItem: {
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isBurnFrom: boolean;
+ readonly asBurnFrom: {
+ readonly collectionId: u32;
+ readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isTransfer: boolean;
+ readonly asTransfer: {
+ readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isApprove: boolean;
+ readonly asApprove: {
+ readonly spender: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isApproveFrom: boolean;
+ readonly asApproveFrom: {
+ readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly to: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isTransferFrom: boolean;
+ readonly asTransferFrom: {
+ readonly from: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly recipient: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ readonly value: u128;
+ } & Struct;
+ readonly isSetCollectionLimits: boolean;
+ readonly asSetCollectionLimits: {
+ readonly collectionId: u32;
+ readonly newLimit: UpDataStructsCollectionLimits;
+ } & Struct;
+ readonly isSetCollectionPermissions: boolean;
+ readonly asSetCollectionPermissions: {
+ readonly collectionId: u32;
+ readonly newPermission: UpDataStructsCollectionPermissions;
+ } & Struct;
+ readonly isRepartition: boolean;
+ readonly asRepartition: {
+ readonly collectionId: u32;
+ readonly tokenId: u32;
+ readonly amount: u128;
+ } & Struct;
+ readonly isSetAllowanceForAll: boolean;
+ readonly asSetAllowanceForAll: {
+ readonly collectionId: u32;
+ readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly approve: bool;
+ } & Struct;
+ readonly isForceRepairCollection: boolean;
+ readonly asForceRepairCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isForceRepairItem: boolean;
+ readonly asForceRepairItem: {
+ readonly collectionId: u32;
+ readonly itemId: u32;
+ } & Struct;
+ readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'ApproveFrom' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem';
+ }
+
+ /** @name UpDataStructsCollectionMode (273) */
+ interface UpDataStructsCollectionMode extends Enum {
+ readonly isNft: boolean;
+ readonly isFungible: boolean;
+ readonly asFungible: u8;
+ readonly isReFungible: boolean;
+ readonly type: 'Nft' | 'Fungible' | 'ReFungible';
+ }
+
+ /** @name UpDataStructsCreateCollectionData (274) */
+ interface UpDataStructsCreateCollectionData extends Struct {
+ readonly mode: UpDataStructsCollectionMode;
+ readonly access: Option<UpDataStructsAccessMode>;
+ readonly name: Vec<u16>;
+ readonly description: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly limits: Option<UpDataStructsCollectionLimits>;
+ readonly permissions: Option<UpDataStructsCollectionPermissions>;
+ readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly adminList: Vec<PalletEvmAccountBasicCrossAccountIdRepr>;
+ readonly pendingSponsor: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
+ readonly flags: U8aFixed;
+ }
+
+ /** @name PalletEvmAccountBasicCrossAccountIdRepr (275) */
+ interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
+ readonly isSubstrate: boolean;
+ readonly asSubstrate: AccountId32;
+ readonly isEthereum: boolean;
+ readonly asEthereum: H160;
+ readonly type: 'Substrate' | 'Ethereum';
+ }
+
+ /** @name UpDataStructsAccessMode (277) */
+ interface UpDataStructsAccessMode extends Enum {
+ readonly isNormal: boolean;
+ readonly isAllowList: boolean;
+ readonly type: 'Normal' | 'AllowList';
+ }
+
+ /** @name UpDataStructsCollectionLimits (279) */
+ interface UpDataStructsCollectionLimits extends Struct {
+ readonly accountTokenOwnershipLimit: Option<u32>;
+ readonly sponsoredDataSize: Option<u32>;
+ readonly sponsoredDataRateLimit: Option<UpDataStructsSponsoringRateLimit>;
+ readonly tokenLimit: Option<u32>;
+ readonly sponsorTransferTimeout: Option<u32>;
+ readonly sponsorApproveTimeout: Option<u32>;
+ readonly ownerCanTransfer: Option<bool>;
+ readonly ownerCanDestroy: Option<bool>;
+ readonly transfersEnabled: Option<bool>;
+ }
+
+ /** @name UpDataStructsSponsoringRateLimit (281) */
+ interface UpDataStructsSponsoringRateLimit extends Enum {
+ readonly isSponsoringDisabled: boolean;
+ readonly isBlocks: boolean;
+ readonly asBlocks: u32;
+ readonly type: 'SponsoringDisabled' | 'Blocks';
+ }
+
+ /** @name UpDataStructsCollectionPermissions (284) */
+ interface UpDataStructsCollectionPermissions extends Struct {
+ readonly access: Option<UpDataStructsAccessMode>;
+ readonly mintMode: Option<bool>;
+ readonly nesting: Option<UpDataStructsNestingPermissions>;
+ }
+
+ /** @name UpDataStructsNestingPermissions (286) */
+ interface UpDataStructsNestingPermissions extends Struct {
+ readonly tokenOwner: bool;
+ readonly collectionAdmin: bool;
+ readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
+ }
+
+ /** @name UpDataStructsOwnerRestrictedSet (288) */
+ interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
+
+ /** @name UpDataStructsPropertyKeyPermission (294) */
+ interface UpDataStructsPropertyKeyPermission extends Struct {
+ readonly key: Bytes;
+ readonly permission: UpDataStructsPropertyPermission;
+ }
+
+ /** @name UpDataStructsPropertyPermission (296) */
+ interface UpDataStructsPropertyPermission extends Struct {
+ readonly mutable: bool;
+ readonly collectionAdmin: bool;
+ readonly tokenOwner: bool;
+ }
+
+ /** @name UpDataStructsProperty (299) */
+ interface UpDataStructsProperty extends Struct {
+ readonly key: Bytes;
+ readonly value: Bytes;
+ }
+
+ /** @name UpDataStructsCreateItemData (304) */
+ interface UpDataStructsCreateItemData extends Enum {
+ readonly isNft: boolean;
+ readonly asNft: UpDataStructsCreateNftData;
+ readonly isFungible: boolean;
+ readonly asFungible: UpDataStructsCreateFungibleData;
+ readonly isReFungible: boolean;
+ readonly asReFungible: UpDataStructsCreateReFungibleData;
+ readonly type: 'Nft' | 'Fungible' | 'ReFungible';
+ }
+
+ /** @name UpDataStructsCreateNftData (305) */
+ interface UpDataStructsCreateNftData extends Struct {
+ readonly properties: Vec<UpDataStructsProperty>;
+ }
+
+ /** @name UpDataStructsCreateFungibleData (306) */
+ interface UpDataStructsCreateFungibleData extends Struct {
+ readonly value: u128;
+ }
+
+ /** @name UpDataStructsCreateReFungibleData (307) */
+ interface UpDataStructsCreateReFungibleData extends Struct {
+ readonly pieces: u128;
+ readonly properties: Vec<UpDataStructsProperty>;
+ }
+
+ /** @name UpDataStructsCreateItemExData (311) */
+ interface UpDataStructsCreateItemExData extends Enum {
+ readonly isNft: boolean;
+ readonly asNft: Vec<UpDataStructsCreateNftExData>;
+ readonly isFungible: boolean;
+ readonly asFungible: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
+ readonly isRefungibleMultipleItems: boolean;
+ readonly asRefungibleMultipleItems: Vec<UpDataStructsCreateRefungibleExSingleOwner>;
+ readonly isRefungibleMultipleOwners: boolean;
+ readonly asRefungibleMultipleOwners: UpDataStructsCreateRefungibleExMultipleOwners;
+ readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
+ }
+
+ /** @name UpDataStructsCreateNftExData (313) */
+ interface UpDataStructsCreateNftExData extends Struct {
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+ }
+
+ /** @name UpDataStructsCreateRefungibleExSingleOwner (320) */
+ interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
+ readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly pieces: u128;
+ readonly properties: Vec<UpDataStructsProperty>;
+ }
+
+ /** @name UpDataStructsCreateRefungibleExMultipleOwners (322) */
+ interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
+ readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
+ readonly properties: Vec<UpDataStructsProperty>;
+ }
+
+ /** @name PalletConfigurationCall (323) */
+ interface PalletConfigurationCall extends Enum {
+ readonly isSetWeightToFeeCoefficientOverride: boolean;
+ readonly asSetWeightToFeeCoefficientOverride: {
+ readonly coeff: Option<u64>;
+ } & Struct;
+ readonly isSetMinGasPriceOverride: boolean;
+ readonly asSetMinGasPriceOverride: {
+ readonly coeff: Option<u64>;
+ } & Struct;
+ readonly isSetAppPromotionConfigurationOverride: boolean;
+ readonly asSetAppPromotionConfigurationOverride: {
+ readonly configuration: PalletConfigurationAppPromotionConfiguration;
+ } & Struct;
+ readonly isSetCollatorSelectionDesiredCollators: boolean;
+ readonly asSetCollatorSelectionDesiredCollators: {
+ readonly max: Option<u32>;
+ } & Struct;
+ readonly isSetCollatorSelectionLicenseBond: boolean;
+ readonly asSetCollatorSelectionLicenseBond: {
+ readonly amount: Option<u128>;
+ } & Struct;
+ readonly isSetCollatorSelectionKickThreshold: boolean;
+ readonly asSetCollatorSelectionKickThreshold: {
+ readonly threshold: Option<u32>;
+ } & Struct;
+ readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride' | 'SetAppPromotionConfigurationOverride' | 'SetCollatorSelectionDesiredCollators' | 'SetCollatorSelectionLicenseBond' | 'SetCollatorSelectionKickThreshold';
+ }
+
+ /** @name PalletConfigurationAppPromotionConfiguration (325) */
+ interface PalletConfigurationAppPromotionConfiguration extends Struct {
+ readonly recalculationInterval: Option<u32>;
+ readonly pendingInterval: Option<u32>;
+ readonly intervalIncome: Option<Perbill>;
+ readonly maxStakersPerCalculation: Option<u8>;
+ }
+
+ /** @name PalletStructureCall (330) */
+ type PalletStructureCall = Null;
+
+ /** @name PalletAppPromotionCall (331) */
+ interface PalletAppPromotionCall extends Enum {
+ readonly isSetAdminAddress: boolean;
+ readonly asSetAdminAddress: {
+ readonly admin: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isStake: boolean;
+ readonly asStake: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnstakeAll: boolean;
+ readonly isSponsorCollection: boolean;
+ readonly asSponsorCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isStopSponsoringCollection: boolean;
+ readonly asStopSponsoringCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isSponsorContract: boolean;
+ readonly asSponsorContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isStopSponsoringContract: boolean;
+ readonly asStopSponsoringContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isPayoutStakers: boolean;
+ readonly asPayoutStakers: {
+ readonly stakersNumber: Option<u8>;
+ } & Struct;
+ readonly isUnstakePartial: boolean;
+ readonly asUnstakePartial: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isForceUnstake: boolean;
+ readonly asForceUnstake: {
+ readonly pendingBlocks: Vec<u32>;
+ } & Struct;
+ readonly type: 'SetAdminAddress' | 'Stake' | 'UnstakeAll' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers' | 'UnstakePartial' | 'ForceUnstake';
+ }
+
+ /** @name PalletForeignAssetsModuleCall (333) */
+ interface PalletForeignAssetsModuleCall extends Enum {
+ readonly isRegisterForeignAsset: boolean;
+ readonly asRegisterForeignAsset: {
+ readonly owner: AccountId32;
+ readonly location: StagingXcmVersionedMultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isUpdateForeignAsset: boolean;
+ readonly asUpdateForeignAsset: {
+ readonly foreignAssetId: u32;
+ readonly location: StagingXcmVersionedMultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset';
+ }
+
+ /** @name PalletForeignAssetsModuleAssetMetadata (334) */
+ interface PalletForeignAssetsModuleAssetMetadata extends Struct {
+ readonly name: Bytes;
+ readonly symbol: Bytes;
+ readonly decimals: u8;
+ readonly minimalBalance: u128;
+ }
+
+ /** @name PalletEvmCall (337) */
+ interface PalletEvmCall extends Enum {
+ readonly isWithdraw: boolean;
+ readonly asWithdraw: {
+ readonly address: H160;
+ readonly value: u128;
+ } & Struct;
+ readonly isCall: boolean;
+ readonly asCall: {
+ readonly source: H160;
+ readonly target: H160;
+ readonly input: Bytes;
+ readonly value: U256;
+ readonly gasLimit: u64;
+ readonly maxFeePerGas: U256;
+ readonly maxPriorityFeePerGas: Option<U256>;
+ readonly nonce: Option<U256>;
+ readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
+ } & Struct;
+ readonly isCreate: boolean;
+ readonly asCreate: {
+ readonly source: H160;
+ readonly init: Bytes;
+ readonly value: U256;
+ readonly gasLimit: u64;
+ readonly maxFeePerGas: U256;
+ readonly maxPriorityFeePerGas: Option<U256>;
+ readonly nonce: Option<U256>;
+ readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
+ } & Struct;
+ readonly isCreate2: boolean;
+ readonly asCreate2: {
+ readonly source: H160;
+ readonly init: Bytes;
+ readonly salt: H256;
+ readonly value: U256;
+ readonly gasLimit: u64;
+ readonly maxFeePerGas: U256;
+ readonly maxPriorityFeePerGas: Option<U256>;
+ readonly nonce: Option<U256>;
+ readonly accessList: Vec<ITuple<[H160, Vec<H256>]>>;
+ } & Struct;
+ readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
+ }
+
+ /** @name PalletEthereumCall (344) */
+ interface PalletEthereumCall extends Enum {
+ readonly isTransact: boolean;
+ readonly asTransact: {
+ readonly transaction: EthereumTransactionTransactionV2;
+ } & Struct;
+ readonly type: 'Transact';
+ }
+
+ /** @name EthereumTransactionTransactionV2 (345) */
+ interface EthereumTransactionTransactionV2 extends Enum {
+ readonly isLegacy: boolean;
+ readonly asLegacy: EthereumTransactionLegacyTransaction;
+ readonly isEip2930: boolean;
+ readonly asEip2930: EthereumTransactionEip2930Transaction;
+ readonly isEip1559: boolean;
+ readonly asEip1559: EthereumTransactionEip1559Transaction;
+ readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
+ }
+
+ /** @name EthereumTransactionLegacyTransaction (346) */
+ interface EthereumTransactionLegacyTransaction extends Struct {
+ readonly nonce: U256;
+ readonly gasPrice: U256;
+ readonly gasLimit: U256;
+ readonly action: EthereumTransactionTransactionAction;
+ readonly value: U256;
+ readonly input: Bytes;
+ readonly signature: EthereumTransactionTransactionSignature;
+ }
+
+ /** @name EthereumTransactionTransactionAction (347) */
+ interface EthereumTransactionTransactionAction extends Enum {
+ readonly isCall: boolean;
+ readonly asCall: H160;
+ readonly isCreate: boolean;
+ readonly type: 'Call' | 'Create';
+ }
+
+ /** @name EthereumTransactionTransactionSignature (348) */
+ interface EthereumTransactionTransactionSignature extends Struct {
+ readonly v: u64;
+ readonly r: H256;
+ readonly s: H256;
+ }
+
+ /** @name EthereumTransactionEip2930Transaction (350) */
+ interface EthereumTransactionEip2930Transaction extends Struct {
+ readonly chainId: u64;
+ readonly nonce: U256;
+ readonly gasPrice: U256;
+ readonly gasLimit: U256;
+ readonly action: EthereumTransactionTransactionAction;
+ readonly value: U256;
+ readonly input: Bytes;
+ readonly accessList: Vec<EthereumTransactionAccessListItem>;
+ readonly oddYParity: bool;
+ readonly r: H256;
+ readonly s: H256;
+ }
+
+ /** @name EthereumTransactionAccessListItem (352) */
+ interface EthereumTransactionAccessListItem extends Struct {
+ readonly address: H160;
+ readonly storageKeys: Vec<H256>;
+ }
+
+ /** @name EthereumTransactionEip1559Transaction (353) */
+ interface EthereumTransactionEip1559Transaction extends Struct {
+ readonly chainId: u64;
+ readonly nonce: U256;
+ readonly maxPriorityFeePerGas: U256;
+ readonly maxFeePerGas: U256;
+ readonly gasLimit: U256;
+ readonly action: EthereumTransactionTransactionAction;
+ readonly value: U256;
+ readonly input: Bytes;
+ readonly accessList: Vec<EthereumTransactionAccessListItem>;
+ readonly oddYParity: bool;
+ readonly r: H256;
+ readonly s: H256;
+ }
+
+ /** @name PalletEvmContractHelpersCall (354) */
+ interface PalletEvmContractHelpersCall extends Enum {
+ readonly isMigrateFromSelfSponsoring: boolean;
+ readonly asMigrateFromSelfSponsoring: {
+ readonly addresses: Vec<H160>;
+ } & Struct;
+ readonly type: 'MigrateFromSelfSponsoring';
+ }
+
+ /** @name PalletEvmMigrationCall (356) */
+ interface PalletEvmMigrationCall extends Enum {
+ readonly isBegin: boolean;
+ readonly asBegin: {
+ readonly address: H160;
+ } & Struct;
+ readonly isSetData: boolean;
+ readonly asSetData: {
+ readonly address: H160;
+ readonly data: Vec<ITuple<[H256, H256]>>;
+ } & Struct;
+ readonly isFinish: boolean;
+ readonly asFinish: {
+ readonly address: H160;
+ readonly code: Bytes;
+ } & Struct;
+ readonly isInsertEthLogs: boolean;
+ readonly asInsertEthLogs: {
+ readonly logs: Vec<EthereumLog>;
+ } & Struct;
+ readonly isInsertEvents: boolean;
+ readonly asInsertEvents: {
+ readonly events: Vec<Bytes>;
+ } & Struct;
+ readonly isRemoveRmrkData: boolean;
+ readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents' | 'RemoveRmrkData';
+ }
+
+ /** @name EthereumLog (360) */
+ interface EthereumLog extends Struct {
+ readonly address: H160;
+ readonly topics: Vec<H256>;
+ readonly data: Bytes;
+ }
+
+ /** @name PalletMaintenanceCall (361) */
+ interface PalletMaintenanceCall extends Enum {
+ readonly isEnable: boolean;
+ readonly isDisable: boolean;
+ readonly type: 'Enable' | 'Disable';
+ }
+
+ /** @name PalletUtilityCall (362) */
+ interface PalletUtilityCall extends Enum {
+ readonly isBatch: boolean;
+ readonly asBatch: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly isAsDerivative: boolean;
+ readonly asAsDerivative: {
+ readonly index: u16;
+ readonly call: Call;
+ } & Struct;
+ readonly isBatchAll: boolean;
+ readonly asBatchAll: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly isDispatchAs: boolean;
+ readonly asDispatchAs: {
+ readonly asOrigin: OpalRuntimeOriginCaller;
+ readonly call: Call;
+ } & Struct;
+ readonly isForceBatch: boolean;
+ readonly asForceBatch: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly isWithWeight: boolean;
+ readonly asWithWeight: {
+ readonly call: Call;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'Batch' | 'AsDerivative' | 'BatchAll' | 'DispatchAs' | 'ForceBatch' | 'WithWeight';
+ }
+
+ /** @name PalletTestUtilsCall (364) */
+ interface PalletTestUtilsCall extends Enum {
+ readonly isEnable: boolean;
+ readonly isSetTestValue: boolean;
+ readonly asSetTestValue: {
+ readonly value: u32;
+ } & Struct;
+ readonly isSetTestValueAndRollback: boolean;
+ readonly asSetTestValueAndRollback: {
+ readonly value: u32;
+ } & Struct;
+ readonly isIncTestValue: boolean;
+ readonly isJustTakeFee: boolean;
+ readonly isBatchAll: boolean;
+ readonly asBatchAll: {
+ readonly calls: Vec<Call>;
+ } & Struct;
+ readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'JustTakeFee' | 'BatchAll';
+ }
+
+ /** @name PalletSchedulerEvent (366) */
+ interface PalletSchedulerEvent extends Enum {
+ readonly isScheduled: boolean;
+ readonly asScheduled: {
+ readonly when: u32;
+ readonly index: u32;
+ } & Struct;
+ readonly isCanceled: boolean;
+ readonly asCanceled: {
+ readonly when: u32;
+ readonly index: u32;
+ } & Struct;
+ readonly isDispatched: boolean;
+ readonly asDispatched: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly isCallUnavailable: boolean;
+ readonly asCallUnavailable: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ } & Struct;
+ readonly isPeriodicFailed: boolean;
+ readonly asPeriodicFailed: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ } & Struct;
+ readonly isPermanentlyOverweight: boolean;
+ readonly asPermanentlyOverweight: {
+ readonly task: ITuple<[u32, u32]>;
+ readonly id: Option<U8aFixed>;
+ } & Struct;
+ readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'CallUnavailable' | 'PeriodicFailed' | 'PermanentlyOverweight';
+ }
+
+ /** @name CumulusPalletXcmpQueueEvent (367) */
+ interface CumulusPalletXcmpQueueEvent extends Enum {
+ readonly isSuccess: boolean;
+ readonly asSuccess: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isFail: boolean;
+ readonly asFail: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly error: StagingXcmV3TraitsError;
+ readonly weight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isBadVersion: boolean;
+ readonly asBadVersion: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isBadFormat: boolean;
+ readonly asBadFormat: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isXcmpMessageSent: boolean;
+ readonly asXcmpMessageSent: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isOverweightEnqueued: boolean;
+ readonly asOverweightEnqueued: {
+ readonly sender: u32;
+ readonly sentAt: u32;
+ readonly index: u64;
+ readonly required: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isOverweightServiced: boolean;
+ readonly asOverweightServiced: {
+ readonly index: u64;
+ readonly used: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced';
+ }
+
+ /** @name PalletXcmEvent (368) */
+ interface PalletXcmEvent extends Enum {
+ readonly isAttempted: boolean;
+ readonly asAttempted: {
+ readonly outcome: StagingXcmV3TraitsOutcome;
+ } & Struct;
+ readonly isSent: boolean;
+ readonly asSent: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly message: StagingXcmV3Xcm;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isUnexpectedResponse: boolean;
+ readonly asUnexpectedResponse: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isResponseReady: boolean;
+ readonly asResponseReady: {
+ readonly queryId: u64;
+ readonly response: StagingXcmV3Response;
+ } & Struct;
+ readonly isNotified: boolean;
+ readonly asNotified: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ } & Struct;
+ readonly isNotifyOverweight: boolean;
+ readonly asNotifyOverweight: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ readonly actualWeight: SpWeightsWeightV2Weight;
+ readonly maxBudgetedWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isNotifyDispatchError: boolean;
+ readonly asNotifyDispatchError: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ } & Struct;
+ readonly isNotifyDecodeFailed: boolean;
+ readonly asNotifyDecodeFailed: {
+ readonly queryId: u64;
+ readonly palletIndex: u8;
+ readonly callIndex: u8;
+ } & Struct;
+ readonly isInvalidResponder: boolean;
+ readonly asInvalidResponder: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ readonly expectedLocation: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly isInvalidResponderVersion: boolean;
+ readonly asInvalidResponderVersion: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isResponseTaken: boolean;
+ readonly asResponseTaken: {
+ readonly queryId: u64;
+ } & Struct;
+ readonly isAssetsTrapped: boolean;
+ readonly asAssetsTrapped: {
+ readonly hash_: H256;
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ } & Struct;
+ readonly isVersionChangeNotified: boolean;
+ readonly asVersionChangeNotified: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly result: u32;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isSupportedVersionChanged: boolean;
+ readonly asSupportedVersionChanged: {
+ readonly location: StagingXcmV3MultiLocation;
+ readonly version: u32;
+ } & Struct;
+ readonly isNotifyTargetSendFail: boolean;
+ readonly asNotifyTargetSendFail: {
+ readonly location: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ readonly error: StagingXcmV3TraitsError;
+ } & Struct;
+ readonly isNotifyTargetMigrationFail: boolean;
+ readonly asNotifyTargetMigrationFail: {
+ readonly location: StagingXcmVersionedMultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isInvalidQuerierVersion: boolean;
+ readonly asInvalidQuerierVersion: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ } & Struct;
+ readonly isInvalidQuerier: boolean;
+ readonly asInvalidQuerier: {
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly queryId: u64;
+ readonly expectedQuerier: StagingXcmV3MultiLocation;
+ readonly maybeActualQuerier: Option<StagingXcmV3MultiLocation>;
+ } & Struct;
+ readonly isVersionNotifyStarted: boolean;
+ readonly asVersionNotifyStarted: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isVersionNotifyRequested: boolean;
+ readonly asVersionNotifyRequested: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isVersionNotifyUnrequested: boolean;
+ readonly asVersionNotifyUnrequested: {
+ readonly destination: StagingXcmV3MultiLocation;
+ readonly cost: StagingXcmV3MultiassetMultiAssets;
+ readonly messageId: U8aFixed;
+ } & Struct;
+ readonly isFeesPaid: boolean;
+ readonly asFeesPaid: {
+ readonly paying: StagingXcmV3MultiLocation;
+ readonly fees: StagingXcmV3MultiassetMultiAssets;
+ } & Struct;
+ readonly isAssetsClaimed: boolean;
+ readonly asAssetsClaimed: {
+ readonly hash_: H256;
+ readonly origin: StagingXcmV3MultiLocation;
+ readonly assets: StagingXcmVersionedMultiAssets;
+ } & Struct;
+ readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail' | 'InvalidQuerierVersion' | 'InvalidQuerier' | 'VersionNotifyStarted' | 'VersionNotifyRequested' | 'VersionNotifyUnrequested' | 'FeesPaid' | 'AssetsClaimed';
+ }
+
+ /** @name StagingXcmV3TraitsOutcome (369) */
+ interface StagingXcmV3TraitsOutcome extends Enum {
+ readonly isComplete: boolean;
+ readonly asComplete: SpWeightsWeightV2Weight;
+ readonly isIncomplete: boolean;
+ readonly asIncomplete: ITuple<[SpWeightsWeightV2Weight, StagingXcmV3TraitsError]>;
+ readonly isError: boolean;
+ readonly asError: StagingXcmV3TraitsError;
+ readonly type: 'Complete' | 'Incomplete' | 'Error';
+ }
+
+ /** @name CumulusPalletXcmEvent (370) */
+ interface CumulusPalletXcmEvent extends Enum {
+ readonly isInvalidFormat: boolean;
+ readonly asInvalidFormat: U8aFixed;
+ readonly isUnsupportedVersion: boolean;
+ readonly asUnsupportedVersion: U8aFixed;
+ readonly isExecutedDownward: boolean;
+ readonly asExecutedDownward: ITuple<[U8aFixed, StagingXcmV3TraitsOutcome]>;
+ readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward';
+ }
+
+ /** @name CumulusPalletDmpQueueEvent (371) */
+ interface CumulusPalletDmpQueueEvent extends Enum {
+ readonly isInvalidFormat: boolean;
+ readonly asInvalidFormat: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isUnsupportedVersion: boolean;
+ readonly asUnsupportedVersion: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly isExecutedDownward: boolean;
+ readonly asExecutedDownward: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly outcome: StagingXcmV3TraitsOutcome;
+ } & Struct;
+ readonly isWeightExhausted: boolean;
+ readonly asWeightExhausted: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly remainingWeight: SpWeightsWeightV2Weight;
+ readonly requiredWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isOverweightEnqueued: boolean;
+ readonly asOverweightEnqueued: {
+ readonly messageHash: U8aFixed;
+ readonly messageId: U8aFixed;
+ readonly overweightIndex: u64;
+ readonly requiredWeight: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isOverweightServiced: boolean;
+ readonly asOverweightServiced: {
+ readonly overweightIndex: u64;
+ readonly weightUsed: SpWeightsWeightV2Weight;
+ } & Struct;
+ readonly isMaxMessagesExhausted: boolean;
+ readonly asMaxMessagesExhausted: {
+ readonly messageHash: U8aFixed;
+ } & Struct;
+ readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced' | 'MaxMessagesExhausted';
+ }
+
+ /** @name PalletConfigurationEvent (372) */
+ interface PalletConfigurationEvent extends Enum {
+ readonly isNewDesiredCollators: boolean;
+ readonly asNewDesiredCollators: {
+ readonly desiredCollators: Option<u32>;
+ } & Struct;
+ readonly isNewCollatorLicenseBond: boolean;
+ readonly asNewCollatorLicenseBond: {
+ readonly bondCost: Option<u128>;
+ } & Struct;
+ readonly isNewCollatorKickThreshold: boolean;
+ readonly asNewCollatorKickThreshold: {
+ readonly lengthInBlocks: Option<u32>;
+ } & Struct;
+ readonly type: 'NewDesiredCollators' | 'NewCollatorLicenseBond' | 'NewCollatorKickThreshold';
+ }
+
+ /** @name PalletCommonEvent (373) */
+ interface PalletCommonEvent extends Enum {
+ readonly isCollectionCreated: boolean;
+ readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
+ readonly isCollectionDestroyed: boolean;
+ readonly asCollectionDestroyed: u32;
+ readonly isItemCreated: boolean;
+ readonly asItemCreated: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isItemDestroyed: boolean;
+ readonly asItemDestroyed: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isTransfer: boolean;
+ readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isApproved: boolean;
+ readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+ readonly isApprovedForAll: boolean;
+ readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
+ readonly isCollectionPropertySet: boolean;
+ readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
+ readonly isCollectionPropertyDeleted: boolean;
+ readonly asCollectionPropertyDeleted: ITuple<[u32, Bytes]>;
+ readonly isTokenPropertySet: boolean;
+ readonly asTokenPropertySet: ITuple<[u32, u32, Bytes]>;
+ readonly isTokenPropertyDeleted: boolean;
+ readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
+ readonly isPropertyPermissionSet: boolean;
+ readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
+ readonly isAllowListAddressAdded: boolean;
+ readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isAllowListAddressRemoved: boolean;
+ readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isCollectionAdminAdded: boolean;
+ readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isCollectionAdminRemoved: boolean;
+ readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+ readonly isCollectionLimitSet: boolean;
+ readonly asCollectionLimitSet: u32;
+ readonly isCollectionOwnerChanged: boolean;
+ readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>;
+ readonly isCollectionPermissionSet: boolean;
+ readonly asCollectionPermissionSet: u32;
+ readonly isCollectionSponsorSet: boolean;
+ readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
+ readonly isSponsorshipConfirmed: boolean;
+ readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
+ readonly isCollectionSponsorRemoved: boolean;
+ readonly asCollectionSponsorRemoved: u32;
+ readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved';
+ }
+
+ /** @name PalletStructureEvent (374) */
+ interface PalletStructureEvent extends Enum {
+ readonly isExecuted: boolean;
+ readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
+ readonly type: 'Executed';
+ }
+
+ /** @name PalletAppPromotionEvent (375) */
+ interface PalletAppPromotionEvent extends Enum {
+ readonly isStakingRecalculation: boolean;
+ readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
+ readonly isStake: boolean;
+ readonly asStake: ITuple<[AccountId32, u128]>;
+ readonly isUnstake: boolean;
+ readonly asUnstake: ITuple<[AccountId32, u128]>;
+ readonly isSetAdmin: boolean;
+ readonly asSetAdmin: AccountId32;
+ readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
+ }
+
+ /** @name PalletForeignAssetsModuleEvent (376) */
+ interface PalletForeignAssetsModuleEvent extends Enum {
+ readonly isForeignAssetRegistered: boolean;
+ readonly asForeignAssetRegistered: {
+ readonly assetId: u32;
+ readonly assetAddress: StagingXcmV3MultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isForeignAssetUpdated: boolean;
+ readonly asForeignAssetUpdated: {
+ readonly assetId: u32;
+ readonly assetAddress: StagingXcmV3MultiLocation;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isAssetRegistered: boolean;
+ readonly asAssetRegistered: {
+ readonly assetId: PalletForeignAssetsAssetId;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly isAssetUpdated: boolean;
+ readonly asAssetUpdated: {
+ readonly assetId: PalletForeignAssetsAssetId;
+ readonly metadata: PalletForeignAssetsModuleAssetMetadata;
+ } & Struct;
+ readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated';
+ }
+
+ /** @name PalletEvmEvent (377) */
+ interface PalletEvmEvent extends Enum {
+ readonly isLog: boolean;
+ readonly asLog: {
+ readonly log: EthereumLog;
+ } & Struct;
+ readonly isCreated: boolean;
+ readonly asCreated: {
+ readonly address: H160;
+ } & Struct;
+ readonly isCreatedFailed: boolean;
+ readonly asCreatedFailed: {
+ readonly address: H160;
+ } & Struct;
+ readonly isExecuted: boolean;
+ readonly asExecuted: {
+ readonly address: H160;
+ } & Struct;
+ readonly isExecutedFailed: boolean;
+ readonly asExecutedFailed: {
+ readonly address: H160;
+ } & Struct;
+ readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
+ }
+
+ /** @name PalletEthereumEvent (378) */
+ interface PalletEthereumEvent extends Enum {
+ readonly isExecuted: boolean;
+ readonly asExecuted: {
+ readonly from: H160;
+ readonly to: H160;
+ readonly transactionHash: H256;
+ readonly exitReason: EvmCoreErrorExitReason;
+ readonly extraData: Bytes;
+ } & Struct;
+ readonly type: 'Executed';
+ }
+
+ /** @name EvmCoreErrorExitReason (379) */
+ interface EvmCoreErrorExitReason extends Enum {
+ readonly isSucceed: boolean;
+ readonly asSucceed: EvmCoreErrorExitSucceed;
+ readonly isError: boolean;
+ readonly asError: EvmCoreErrorExitError;
+ readonly isRevert: boolean;
+ readonly asRevert: EvmCoreErrorExitRevert;
+ readonly isFatal: boolean;
+ readonly asFatal: EvmCoreErrorExitFatal;
+ readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
+ }
+
+ /** @name EvmCoreErrorExitSucceed (380) */
+ interface EvmCoreErrorExitSucceed extends Enum {
+ readonly isStopped: boolean;
+ readonly isReturned: boolean;
+ readonly isSuicided: boolean;
+ readonly type: 'Stopped' | 'Returned' | 'Suicided';
+ }
+
+ /** @name EvmCoreErrorExitError (381) */
+ interface EvmCoreErrorExitError extends Enum {
+ readonly isStackUnderflow: boolean;
+ readonly isStackOverflow: boolean;
+ readonly isInvalidJump: boolean;
+ readonly isInvalidRange: boolean;
+ readonly isDesignatedInvalid: boolean;
+ readonly isCallTooDeep: boolean;
+ readonly isCreateCollision: boolean;
+ readonly isCreateContractLimit: boolean;
+ readonly isOutOfOffset: boolean;
+ readonly isOutOfGas: boolean;
+ readonly isOutOfFund: boolean;
+ readonly isPcUnderflow: boolean;
+ readonly isCreateEmpty: boolean;
+ readonly isOther: boolean;
+ readonly asOther: Text;
+ readonly isMaxNonce: boolean;
+ readonly isInvalidCode: boolean;
+ readonly asInvalidCode: u8;
+ readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'MaxNonce' | 'InvalidCode';
+ }
+
+ /** @name EvmCoreErrorExitRevert (385) */
+ interface EvmCoreErrorExitRevert extends Enum {
+ readonly isReverted: boolean;
+ readonly type: 'Reverted';
+ }
+
+ /** @name EvmCoreErrorExitFatal (386) */
+ interface EvmCoreErrorExitFatal extends Enum {
+ readonly isNotSupported: boolean;
+ readonly isUnhandledInterrupt: boolean;
+ readonly isCallErrorAsFatal: boolean;
+ readonly asCallErrorAsFatal: EvmCoreErrorExitError;
+ readonly isOther: boolean;
+ readonly asOther: Text;
+ readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
+ }
+
+ /** @name PalletEvmContractHelpersEvent (387) */
+ interface PalletEvmContractHelpersEvent extends Enum {
+ readonly isContractSponsorSet: boolean;
+ readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorshipConfirmed: boolean;
+ readonly asContractSponsorshipConfirmed: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorRemoved: boolean;
+ readonly asContractSponsorRemoved: H160;
+ readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
+ }
+
+ /** @name PalletEvmMigrationEvent (388) */
+ interface PalletEvmMigrationEvent extends Enum {
+ readonly isTestEvent: boolean;
+ readonly type: 'TestEvent';
+ }
+
+ /** @name PalletMaintenanceEvent (389) */
+ interface PalletMaintenanceEvent extends Enum {
+ readonly isMaintenanceEnabled: boolean;
+ readonly isMaintenanceDisabled: boolean;
+ readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled';
+ }
+
+ /** @name PalletUtilityEvent (390) */
+ interface PalletUtilityEvent extends Enum {
+ readonly isBatchInterrupted: boolean;
+ readonly asBatchInterrupted: {
+ readonly index: u32;
+ readonly error: SpRuntimeDispatchError;
+ } & Struct;
+ readonly isBatchCompleted: boolean;
+ readonly isBatchCompletedWithErrors: boolean;
+ readonly isItemCompleted: boolean;
+ readonly isItemFailed: boolean;
+ readonly asItemFailed: {
+ readonly error: SpRuntimeDispatchError;
+ } & Struct;
+ readonly isDispatchedAs: boolean;
+ readonly asDispatchedAs: {
+ readonly result: Result<Null, SpRuntimeDispatchError>;
+ } & Struct;
+ readonly type: 'BatchInterrupted' | 'BatchCompleted' | 'BatchCompletedWithErrors' | 'ItemCompleted' | 'ItemFailed' | 'DispatchedAs';
+ }
+
+ /** @name PalletTestUtilsEvent (391) */
+ interface PalletTestUtilsEvent extends Enum {
+ readonly isValueIsSet: boolean;
+ readonly isShouldRollback: boolean;
+ readonly isBatchCompleted: boolean;
+ readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
+ }
+
+ /** @name FrameSystemPhase (392) */
+ interface FrameSystemPhase extends Enum {
+ readonly isApplyExtrinsic: boolean;
+ readonly asApplyExtrinsic: u32;
+ readonly isFinalization: boolean;
+ readonly isInitialization: boolean;
+ readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
+ }
+
+ /** @name FrameSystemLastRuntimeUpgradeInfo (394) */
+ interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
+ readonly specVersion: Compact<u32>;
+ readonly specName: Text;
+ }
+
+ /** @name FrameSystemLimitsBlockWeights (395) */
+ interface FrameSystemLimitsBlockWeights extends Struct {
+ readonly baseBlock: SpWeightsWeightV2Weight;
+ readonly maxBlock: SpWeightsWeightV2Weight;
+ readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
+ }
+
+ /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (396) */
+ interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct {
+ readonly normal: FrameSystemLimitsWeightsPerClass;
+ readonly operational: FrameSystemLimitsWeightsPerClass;
+ readonly mandatory: FrameSystemLimitsWeightsPerClass;
+ }
+
+ /** @name FrameSystemLimitsWeightsPerClass (397) */
+ interface FrameSystemLimitsWeightsPerClass extends Struct {
+ readonly baseExtrinsic: SpWeightsWeightV2Weight;
+ readonly maxExtrinsic: Option<SpWeightsWeightV2Weight>;
+ readonly maxTotal: Option<SpWeightsWeightV2Weight>;
+ readonly reserved: Option<SpWeightsWeightV2Weight>;
+ }
+
+ /** @name FrameSystemLimitsBlockLength (399) */
+ interface FrameSystemLimitsBlockLength extends Struct {
+ readonly max: FrameSupportDispatchPerDispatchClassU32;
+ }
+
+ /** @name FrameSupportDispatchPerDispatchClassU32 (400) */
+ interface FrameSupportDispatchPerDispatchClassU32 extends Struct {
+ readonly normal: u32;
+ readonly operational: u32;
+ readonly mandatory: u32;
+ }
+
+ /** @name SpWeightsRuntimeDbWeight (401) */
+ interface SpWeightsRuntimeDbWeight extends Struct {
+ readonly read: u64;
+ readonly write: u64;
+ }
+
+ /** @name SpVersionRuntimeVersion (402) */
+ interface SpVersionRuntimeVersion extends Struct {
+ readonly specName: Text;
+ readonly implName: Text;
+ readonly authoringVersion: u32;
+ readonly specVersion: u32;
+ readonly implVersion: u32;
+ readonly apis: Vec<ITuple<[U8aFixed, u32]>>;
+ readonly transactionVersion: u32;
+ readonly stateVersion: u8;
+ }
+
+ /** @name FrameSystemError (406) */
+ interface FrameSystemError extends Enum {
+ readonly isInvalidSpecName: boolean;
+ readonly isSpecVersionNeedsToIncrease: boolean;
+ readonly isFailedToExtractRuntimeVersion: boolean;
+ readonly isNonDefaultComposite: boolean;
+ readonly isNonZeroRefCount: boolean;
+ readonly isCallFiltered: boolean;
+ readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
+ }
+
+ /** @name CumulusPalletParachainSystemUnincludedSegmentAncestor (408) */
+ interface CumulusPalletParachainSystemUnincludedSegmentAncestor extends Struct {
+ readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
+ readonly paraHeadHash: Option<H256>;
+ readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
+ }
+
+ /** @name CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth (409) */
+ interface CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth extends Struct {
+ readonly umpMsgCount: u32;
+ readonly umpTotalBytes: u32;
+ readonly hrmpOutgoing: BTreeMap<u32, CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate>;
+ }
+
+ /** @name CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate (411) */
+ interface CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate extends Struct {
+ readonly msgCount: u32;
+ readonly totalBytes: u32;
+ }
+
+ /** @name PolkadotPrimitivesV5UpgradeGoAhead (415) */
+ interface PolkadotPrimitivesV5UpgradeGoAhead extends Enum {
+ readonly isAbort: boolean;
+ readonly isGoAhead: boolean;
+ readonly type: 'Abort' | 'GoAhead';
+ }
+
+ /** @name CumulusPalletParachainSystemUnincludedSegmentSegmentTracker (416) */
+ interface CumulusPalletParachainSystemUnincludedSegmentSegmentTracker extends Struct {
+ readonly usedBandwidth: CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth;
+ readonly hrmpWatermark: Option<u32>;
+ readonly consumedGoAheadSignal: Option<PolkadotPrimitivesV5UpgradeGoAhead>;
+ }
+
+ /** @name PolkadotPrimitivesV5UpgradeRestriction (418) */
+ interface PolkadotPrimitivesV5UpgradeRestriction extends Enum {
+ readonly isPresent: boolean;
+ readonly type: 'Present';
+ }
+
+ /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (419) */
+ interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
+ readonly dmqMqcHead: H256;
+ readonly relayDispatchQueueRemainingCapacity: CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity;
+ readonly ingressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
+ readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV5AbridgedHrmpChannel]>>;
+ }
+
+ /** @name CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity (420) */
+ interface CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity extends Struct {
+ readonly remainingCount: u32;
+ readonly remainingSize: u32;
+ }
+
+ /** @name PolkadotPrimitivesV5AbridgedHrmpChannel (423) */
+ interface PolkadotPrimitivesV5AbridgedHrmpChannel extends Struct {
+ readonly maxCapacity: u32;
+ readonly maxTotalSize: u32;
+ readonly maxMessageSize: u32;
+ readonly msgCount: u32;
+ readonly totalSize: u32;
+ readonly mqcHead: Option<H256>;
+ }
+
+ /** @name PolkadotPrimitivesV5AbridgedHostConfiguration (424) */
+ interface PolkadotPrimitivesV5AbridgedHostConfiguration extends Struct {
+ readonly maxCodeSize: u32;
+ readonly maxHeadDataSize: u32;
+ readonly maxUpwardQueueCount: u32;
+ readonly maxUpwardQueueSize: u32;
+ readonly maxUpwardMessageSize: u32;
+ readonly maxUpwardMessageNumPerCandidate: u32;
+ readonly hrmpMaxMessageNumPerCandidate: u32;
+ readonly validationUpgradeCooldown: u32;
+ readonly validationUpgradeDelay: u32;
+ readonly asyncBackingParams: PolkadotPrimitivesVstagingAsyncBackingParams;
+ }
+
+ /** @name PolkadotPrimitivesVstagingAsyncBackingParams (425) */
+ interface PolkadotPrimitivesVstagingAsyncBackingParams extends Struct {
+ readonly maxCandidateDepth: u32;
+ readonly allowedAncestryLen: u32;
+ }
+
+ /** @name PolkadotCorePrimitivesOutboundHrmpMessage (431) */
+ interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
+ readonly recipient: u32;
+ readonly data: Bytes;
+ }
+
+ /** @name CumulusPalletParachainSystemCodeUpgradeAuthorization (432) */
+ interface CumulusPalletParachainSystemCodeUpgradeAuthorization extends Struct {
+ readonly codeHash: H256;
+ readonly checkVersion: bool;
+ }
+
+ /** @name CumulusPalletParachainSystemError (433) */
+ interface CumulusPalletParachainSystemError extends Enum {
+ readonly isOverlappingUpgrades: boolean;
+ readonly isProhibitedByPolkadot: boolean;
+ readonly isTooBig: boolean;
+ readonly isValidationDataNotAvailable: boolean;
+ readonly isHostConfigurationNotAvailable: boolean;
+ readonly isNotScheduled: boolean;
+ readonly isNothingAuthorized: boolean;
+ readonly isUnauthorized: boolean;
+ readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
+ }
+
+ /** @name PalletCollatorSelectionError (435) */
+ interface PalletCollatorSelectionError extends Enum {
+ readonly isTooManyCandidates: boolean;
+ readonly isUnknown: boolean;
+ readonly isPermission: boolean;
+ readonly isAlreadyHoldingLicense: boolean;
+ readonly isNoLicense: boolean;
+ readonly isAlreadyCandidate: boolean;
+ readonly isNotCandidate: boolean;
+ readonly isTooManyInvulnerables: boolean;
+ readonly isTooFewInvulnerables: boolean;
+ readonly isAlreadyInvulnerable: boolean;
+ readonly isNotInvulnerable: boolean;
+ readonly isNoAssociatedValidatorId: boolean;
+ readonly isValidatorNotRegistered: boolean;
+ readonly type: 'TooManyCandidates' | 'Unknown' | 'Permission' | 'AlreadyHoldingLicense' | 'NoLicense' | 'AlreadyCandidate' | 'NotCandidate' | 'TooManyInvulnerables' | 'TooFewInvulnerables' | 'AlreadyInvulnerable' | 'NotInvulnerable' | 'NoAssociatedValidatorId' | 'ValidatorNotRegistered';
+ }
+
+ /** @name SpCoreCryptoKeyTypeId (439) */
+ interface SpCoreCryptoKeyTypeId extends U8aFixed {}
+
+ /** @name PalletSessionError (440) */
+ interface PalletSessionError extends Enum {
+ readonly isInvalidProof: boolean;
+ readonly isNoAssociatedValidatorId: boolean;
+ readonly isDuplicatedKey: boolean;
+ readonly isNoKeys: boolean;
+ readonly isNoAccount: boolean;
+ readonly type: 'InvalidProof' | 'NoAssociatedValidatorId' | 'DuplicatedKey' | 'NoKeys' | 'NoAccount';
+ }
+
+ /** @name PalletBalancesBalanceLock (446) */
+ interface PalletBalancesBalanceLock extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+ readonly reasons: PalletBalancesReasons;
+ }
+
+ /** @name PalletBalancesReasons (447) */
+ interface PalletBalancesReasons extends Enum {
+ readonly isFee: boolean;
+ readonly isMisc: boolean;
+ readonly isAll: boolean;
+ readonly type: 'Fee' | 'Misc' | 'All';
+ }
+
+ /** @name PalletBalancesReserveData (450) */
+ interface PalletBalancesReserveData extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+ }
+
+ /** @name OpalRuntimeRuntimeHoldReason (454) */
+ interface OpalRuntimeRuntimeHoldReason extends Enum {
+ readonly isCollatorSelection: boolean;
+ readonly asCollatorSelection: PalletCollatorSelectionHoldReason;
+ readonly type: 'CollatorSelection';
+ }
+
+ /** @name PalletCollatorSelectionHoldReason (455) */
+ interface PalletCollatorSelectionHoldReason extends Enum {
+ readonly isLicenseBond: boolean;
+ readonly type: 'LicenseBond';
+ }
+
+ /** @name PalletBalancesIdAmount (458) */
+ interface PalletBalancesIdAmount extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+ }
+
+ /** @name PalletBalancesError (460) */
+ interface PalletBalancesError extends Enum {
+ readonly isVestingBalance: boolean;
+ readonly isLiquidityRestrictions: boolean;
+ readonly isInsufficientBalance: boolean;
+ readonly isExistentialDeposit: boolean;
+ readonly isExpendability: boolean;
+ readonly isExistingVestingSchedule: boolean;
+ readonly isDeadAccount: boolean;
+ readonly isTooManyReserves: boolean;
+ readonly isTooManyHolds: boolean;
+ readonly isTooManyFreezes: boolean;
+ readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'Expendability' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves' | 'TooManyHolds' | 'TooManyFreezes';
+ }
+
+ /** @name PalletTransactionPaymentReleases (462) */
+ interface PalletTransactionPaymentReleases extends Enum {
+ readonly isV1Ancient: boolean;
+ readonly isV2: boolean;
+ readonly type: 'V1Ancient' | 'V2';
+ }
+
+ /** @name PalletTreasuryProposal (463) */
+ interface PalletTreasuryProposal extends Struct {
+ readonly proposer: AccountId32;
+ readonly value: u128;
+ readonly beneficiary: AccountId32;
+ readonly bond: u128;
+ }
+
+ /** @name FrameSupportPalletId (466) */
+ interface FrameSupportPalletId extends U8aFixed {}
+
+ /** @name PalletTreasuryError (467) */
+ interface PalletTreasuryError extends Enum {
+ readonly isInsufficientProposersBalance: boolean;
+ readonly isInvalidIndex: boolean;
+ readonly isTooManyApprovals: boolean;
+ readonly isInsufficientPermission: boolean;
+ readonly isProposalNotApproved: boolean;
+ readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
+ }
+
+ /** @name PalletSudoError (468) */
+ interface PalletSudoError extends Enum {
+ readonly isRequireSudo: boolean;
+ readonly type: 'RequireSudo';
+ }
+
+ /** @name OrmlVestingModuleError (470) */
+ interface OrmlVestingModuleError extends Enum {
+ readonly isZeroVestingPeriod: boolean;
+ readonly isZeroVestingPeriodCount: boolean;
+ readonly isInsufficientBalanceToLock: boolean;
+ readonly isTooManyVestingSchedules: boolean;
+ readonly isAmountLow: boolean;
+ readonly isMaxVestingSchedulesExceeded: boolean;
+ readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
+ }
+
+ /** @name OrmlXtokensModuleError (471) */
+ interface OrmlXtokensModuleError extends Enum {
+ readonly isAssetHasNoReserve: boolean;
+ readonly isNotCrossChainTransfer: boolean;
+ readonly isInvalidDest: boolean;
+ readonly isNotCrossChainTransferableCurrency: boolean;
+ readonly isUnweighableMessage: boolean;
+ readonly isXcmExecutionFailed: boolean;
+ readonly isCannotReanchor: boolean;
+ readonly isInvalidAncestry: boolean;
+ readonly isInvalidAsset: boolean;
+ readonly isDestinationNotInvertible: boolean;
+ readonly isBadVersion: boolean;
+ readonly isDistinctReserveForAssetAndFee: boolean;
+ readonly isZeroFee: boolean;
+ readonly isZeroAmount: boolean;
+ readonly isTooManyAssetsBeingSent: boolean;
+ readonly isAssetIndexNonExistent: boolean;
+ readonly isFeeNotEnough: boolean;
+ readonly isNotSupportedMultiLocation: boolean;
+ readonly isMinXcmFeeNotDefined: boolean;
+ readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined';
+ }
+
+ /** @name OrmlTokensBalanceLock (474) */
+ interface OrmlTokensBalanceLock extends Struct {
+ readonly id: U8aFixed;
+ readonly amount: u128;
+ }
+
+ /** @name OrmlTokensAccountData (476) */
+ interface OrmlTokensAccountData extends Struct {
+ readonly free: u128;
+ readonly reserved: u128;
+ readonly frozen: u128;
+ }
+
+ /** @name OrmlTokensReserveData (478) */
+ interface OrmlTokensReserveData extends Struct {
+ readonly id: Null;
+ readonly amount: u128;
+ }
+
+ /** @name OrmlTokensModuleError (480) */
+ interface OrmlTokensModuleError extends Enum {
+ readonly isBalanceTooLow: boolean;
+ readonly isAmountIntoBalanceFailed: boolean;
+ readonly isLiquidityRestrictions: boolean;
+ readonly isMaxLocksExceeded: boolean;
+ readonly isKeepAlive: boolean;
+ readonly isExistentialDeposit: boolean;
+ readonly isDeadAccount: boolean;
+ readonly isTooManyReserves: boolean;
+ readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves';
+ }
+
+ /** @name PalletIdentityRegistrarInfo (485) */
+ interface PalletIdentityRegistrarInfo extends Struct {
+ readonly account: AccountId32;
+ readonly fee: u128;
+ readonly fields: PalletIdentityBitFlags;
+ }
+
+ /** @name PalletIdentityError (487) */
+ interface PalletIdentityError extends Enum {
+ readonly isTooManySubAccounts: boolean;
+ readonly isNotFound: boolean;
+ readonly isNotNamed: boolean;
+ readonly isEmptyIndex: boolean;
+ readonly isFeeChanged: boolean;
+ readonly isNoIdentity: boolean;
+ readonly isStickyJudgement: boolean;
+ readonly isJudgementGiven: boolean;
+ readonly isInvalidJudgement: boolean;
+ readonly isInvalidIndex: boolean;
+ readonly isInvalidTarget: boolean;
+ readonly isTooManyFields: boolean;
+ readonly isTooManyRegistrars: boolean;
+ readonly isAlreadyClaimed: boolean;
+ readonly isNotSub: boolean;
+ readonly isNotOwned: boolean;
+ readonly isJudgementForDifferentIdentity: boolean;
+ readonly isJudgementPaymentFailed: boolean;
+ readonly type: 'TooManySubAccounts' | 'NotFound' | 'NotNamed' | 'EmptyIndex' | 'FeeChanged' | 'NoIdentity' | 'StickyJudgement' | 'JudgementGiven' | 'InvalidJudgement' | 'InvalidIndex' | 'InvalidTarget' | 'TooManyFields' | 'TooManyRegistrars' | 'AlreadyClaimed' | 'NotSub' | 'NotOwned' | 'JudgementForDifferentIdentity' | 'JudgementPaymentFailed';
+ }
+
+ /** @name PalletPreimageRequestStatus (488) */
+ interface PalletPreimageRequestStatus extends Enum {
+ readonly isUnrequested: boolean;
+ readonly asUnrequested: {
+ readonly deposit: ITuple<[AccountId32, u128]>;
+ readonly len: u32;
+ } & Struct;
+ readonly isRequested: boolean;
+ readonly asRequested: {
+ readonly deposit: Option<ITuple<[AccountId32, u128]>>;
+ readonly count: u32;
+ readonly len: Option<u32>;
+ } & Struct;
+ readonly type: 'Unrequested' | 'Requested';
+ }
+
+ /** @name PalletPreimageError (493) */
+ interface PalletPreimageError extends Enum {
+ readonly isTooBig: boolean;
+ readonly isAlreadyNoted: boolean;
+ readonly isNotAuthorized: boolean;
+ readonly isNotNoted: boolean;
+ readonly isRequested: boolean;
+ readonly isNotRequested: boolean;
+ readonly type: 'TooBig' | 'AlreadyNoted' | 'NotAuthorized' | 'NotNoted' | 'Requested' | 'NotRequested';
+ }
+
+ /** @name PalletDemocracyReferendumInfo (499) */
+ interface PalletDemocracyReferendumInfo extends Enum {
+ readonly isOngoing: boolean;
+ readonly asOngoing: PalletDemocracyReferendumStatus;
+ readonly isFinished: boolean;
+ readonly asFinished: {
+ readonly approved: bool;
+ readonly end: u32;
+ } & Struct;
+ readonly type: 'Ongoing' | 'Finished';
+ }
+
+ /** @name PalletDemocracyReferendumStatus (500) */
+ interface PalletDemocracyReferendumStatus extends Struct {
+ readonly end: u32;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly threshold: PalletDemocracyVoteThreshold;
+ readonly delay: u32;
+ readonly tally: PalletDemocracyTally;
+ }
+
+ /** @name PalletDemocracyTally (501) */
+ interface PalletDemocracyTally extends Struct {
+ readonly ayes: u128;
+ readonly nays: u128;
+ readonly turnout: u128;
+ }
+
+ /** @name PalletDemocracyVoteVoting (502) */
+ interface PalletDemocracyVoteVoting extends Enum {
+ readonly isDirect: boolean;
+ readonly asDirect: {
+ readonly votes: Vec<ITuple<[u32, PalletDemocracyVoteAccountVote]>>;
+ readonly delegations: PalletDemocracyDelegations;
+ readonly prior: PalletDemocracyVotePriorLock;
+ } & Struct;
+ readonly isDelegating: boolean;
+ readonly asDelegating: {
+ readonly balance: u128;
+ readonly target: AccountId32;
+ readonly conviction: PalletDemocracyConviction;
+ readonly delegations: PalletDemocracyDelegations;
+ readonly prior: PalletDemocracyVotePriorLock;
+ } & Struct;
+ readonly type: 'Direct' | 'Delegating';
+ }
+
+ /** @name PalletDemocracyDelegations (506) */
+ interface PalletDemocracyDelegations extends Struct {
+ readonly votes: u128;
+ readonly capital: u128;
+ }
+
+ /** @name PalletDemocracyVotePriorLock (507) */
+ interface PalletDemocracyVotePriorLock extends ITuple<[u32, u128]> {}
+
+ /** @name PalletDemocracyError (510) */
+ interface PalletDemocracyError extends Enum {
+ readonly isValueLow: boolean;
+ readonly isProposalMissing: boolean;
+ readonly isAlreadyCanceled: boolean;
+ readonly isDuplicateProposal: boolean;
+ readonly isProposalBlacklisted: boolean;
+ readonly isNotSimpleMajority: boolean;
+ readonly isInvalidHash: boolean;
+ readonly isNoProposal: boolean;
+ readonly isAlreadyVetoed: boolean;
+ readonly isReferendumInvalid: boolean;
+ readonly isNoneWaiting: boolean;
+ readonly isNotVoter: boolean;
+ readonly isNoPermission: boolean;
+ readonly isAlreadyDelegating: boolean;
+ readonly isInsufficientFunds: boolean;
+ readonly isNotDelegating: boolean;
+ readonly isVotesExist: boolean;
+ readonly isInstantNotAllowed: boolean;
+ readonly isNonsense: boolean;
+ readonly isWrongUpperBound: boolean;
+ readonly isMaxVotesReached: boolean;
+ readonly isTooMany: boolean;
+ readonly isVotingPeriodLow: boolean;
+ readonly isPreimageNotExist: boolean;
+ readonly type: 'ValueLow' | 'ProposalMissing' | 'AlreadyCanceled' | 'DuplicateProposal' | 'ProposalBlacklisted' | 'NotSimpleMajority' | 'InvalidHash' | 'NoProposal' | 'AlreadyVetoed' | 'ReferendumInvalid' | 'NoneWaiting' | 'NotVoter' | 'NoPermission' | 'AlreadyDelegating' | 'InsufficientFunds' | 'NotDelegating' | 'VotesExist' | 'InstantNotAllowed' | 'Nonsense' | 'WrongUpperBound' | 'MaxVotesReached' | 'TooMany' | 'VotingPeriodLow' | 'PreimageNotExist';
+ }
+
+ /** @name PalletCollectiveVotes (512) */
+ interface PalletCollectiveVotes extends Struct {
+ readonly index: u32;
+ readonly threshold: u32;
+ readonly ayes: Vec<AccountId32>;
+ readonly nays: Vec<AccountId32>;
+ readonly end: u32;
+ }
+
+ /** @name PalletCollectiveError (513) */
+ interface PalletCollectiveError extends Enum {
+ readonly isNotMember: boolean;
+ readonly isDuplicateProposal: boolean;
+ readonly isProposalMissing: boolean;
+ readonly isWrongIndex: boolean;
+ readonly isDuplicateVote: boolean;
+ readonly isAlreadyInitialized: boolean;
+ readonly isTooEarly: boolean;
+ readonly isTooManyProposals: boolean;
+ readonly isWrongProposalWeight: boolean;
+ readonly isWrongProposalLength: boolean;
+ readonly isPrimeAccountNotMember: boolean;
+ readonly type: 'NotMember' | 'DuplicateProposal' | 'ProposalMissing' | 'WrongIndex' | 'DuplicateVote' | 'AlreadyInitialized' | 'TooEarly' | 'TooManyProposals' | 'WrongProposalWeight' | 'WrongProposalLength' | 'PrimeAccountNotMember';
+ }
+
+ /** @name PalletMembershipError (517) */
+ interface PalletMembershipError extends Enum {
+ readonly isAlreadyMember: boolean;
+ readonly isNotMember: boolean;
+ readonly isTooManyMembers: boolean;
+ readonly type: 'AlreadyMember' | 'NotMember' | 'TooManyMembers';
+ }
+
+ /** @name PalletRankedCollectiveMemberRecord (520) */
+ interface PalletRankedCollectiveMemberRecord extends Struct {
+ readonly rank: u16;
+ }
+
+ /** @name PalletRankedCollectiveError (525) */
+ interface PalletRankedCollectiveError extends Enum {
+ readonly isAlreadyMember: boolean;
+ readonly isNotMember: boolean;
+ readonly isNotPolling: boolean;
+ readonly isOngoing: boolean;
+ readonly isNoneRemaining: boolean;
+ readonly isCorruption: boolean;
+ readonly isRankTooLow: boolean;
+ readonly isInvalidWitness: boolean;
+ readonly isNoPermission: boolean;
+ readonly type: 'AlreadyMember' | 'NotMember' | 'NotPolling' | 'Ongoing' | 'NoneRemaining' | 'Corruption' | 'RankTooLow' | 'InvalidWitness' | 'NoPermission';
+ }
+
+ /** @name PalletReferendaReferendumInfo (526) */
+ interface PalletReferendaReferendumInfo extends Enum {
+ readonly isOngoing: boolean;
+ readonly asOngoing: PalletReferendaReferendumStatus;
+ readonly isApproved: boolean;
+ readonly asApproved: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isRejected: boolean;
+ readonly asRejected: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isCancelled: boolean;
+ readonly asCancelled: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isTimedOut: boolean;
+ readonly asTimedOut: ITuple<[u32, Option<PalletReferendaDeposit>, Option<PalletReferendaDeposit>]>;
+ readonly isKilled: boolean;
+ readonly asKilled: u32;
+ readonly type: 'Ongoing' | 'Approved' | 'Rejected' | 'Cancelled' | 'TimedOut' | 'Killed';
+ }
+
+ /** @name PalletReferendaReferendumStatus (527) */
+ interface PalletReferendaReferendumStatus extends Struct {
+ readonly track: u16;
+ readonly origin: OpalRuntimeOriginCaller;
+ readonly proposal: FrameSupportPreimagesBounded;
+ readonly enactment: FrameSupportScheduleDispatchTime;
+ readonly submitted: u32;
+ readonly submissionDeposit: PalletReferendaDeposit;
+ readonly decisionDeposit: Option<PalletReferendaDeposit>;
+ readonly deciding: Option<PalletReferendaDecidingStatus>;
+ readonly tally: PalletRankedCollectiveTally;
+ readonly inQueue: bool;
+ readonly alarm: Option<ITuple<[u32, ITuple<[u32, u32]>]>>;
+ }
+
+ /** @name PalletReferendaDeposit (528) */
+ interface PalletReferendaDeposit extends Struct {
+ readonly who: AccountId32;
+ readonly amount: u128;
+ }
+
+ /** @name PalletReferendaDecidingStatus (531) */
+ interface PalletReferendaDecidingStatus extends Struct {
+ readonly since: u32;
+ readonly confirming: Option<u32>;
+ }
+
+ /** @name PalletReferendaTrackInfo (537) */
+ interface PalletReferendaTrackInfo extends Struct {
+ readonly name: Text;
+ readonly maxDeciding: u32;
+ readonly decisionDeposit: u128;
+ readonly preparePeriod: u32;
+ readonly decisionPeriod: u32;
+ readonly confirmPeriod: u32;
+ readonly minEnactmentPeriod: u32;
+ readonly minApproval: PalletReferendaCurve;
+ readonly minSupport: PalletReferendaCurve;
+ }
+
+ /** @name PalletReferendaCurve (538) */
+ interface PalletReferendaCurve extends Enum {
+ readonly isLinearDecreasing: boolean;
+ readonly asLinearDecreasing: {
+ readonly length: Perbill;
+ readonly floor: Perbill;
+ readonly ceil: Perbill;
+ } & Struct;
+ readonly isSteppedDecreasing: boolean;
+ readonly asSteppedDecreasing: {
+ readonly begin: Perbill;
+ readonly end: Perbill;
+ readonly step: Perbill;
+ readonly period: Perbill;
+ } & Struct;
+ readonly isReciprocal: boolean;
+ readonly asReciprocal: {
+ readonly factor: i64;
+ readonly xOffset: i64;
+ readonly yOffset: i64;
+ } & Struct;
+ readonly type: 'LinearDecreasing' | 'SteppedDecreasing' | 'Reciprocal';
+ }
+
+ /** @name PalletReferendaError (541) */
+ interface PalletReferendaError extends Enum {
+ readonly isNotOngoing: boolean;
+ readonly isHasDeposit: boolean;
+ readonly isBadTrack: boolean;
+ readonly isFull: boolean;
+ readonly isQueueEmpty: boolean;
+ readonly isBadReferendum: boolean;
+ readonly isNothingToDo: boolean;
+ readonly isNoTrack: boolean;
+ readonly isUnfinished: boolean;
+ readonly isNoPermission: boolean;
+ readonly isNoDeposit: boolean;
+ readonly isBadStatus: boolean;
+ readonly isPreimageNotExist: boolean;
+ readonly type: 'NotOngoing' | 'HasDeposit' | 'BadTrack' | 'Full' | 'QueueEmpty' | 'BadReferendum' | 'NothingToDo' | 'NoTrack' | 'Unfinished' | 'NoPermission' | 'NoDeposit' | 'BadStatus' | 'PreimageNotExist';
+ }
+
+ /** @name PalletSchedulerScheduled (544) */
+ interface PalletSchedulerScheduled extends Struct {
+ readonly maybeId: Option<U8aFixed>;
+ readonly priority: u8;
+ readonly call: FrameSupportPreimagesBounded;
+ readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+ readonly origin: OpalRuntimeOriginCaller;
+ }
+
+ /** @name PalletSchedulerError (546) */
+ interface PalletSchedulerError extends Enum {
+ readonly isFailedToSchedule: boolean;
+ readonly isNotFound: boolean;
+ readonly isTargetBlockNumberInPast: boolean;
+ readonly isRescheduleNoChange: boolean;
+ readonly isNamed: boolean;
+ readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange' | 'Named';
+ }
+
+ /** @name CumulusPalletXcmpQueueInboundChannelDetails (548) */
+ interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
+ readonly sender: u32;
+ readonly state: CumulusPalletXcmpQueueInboundState;
+ readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat]>>;
+ }
+
+ /** @name CumulusPalletXcmpQueueInboundState (549) */
+ interface CumulusPalletXcmpQueueInboundState extends Enum {
+ readonly isOk: boolean;
+ readonly isSuspended: boolean;
+ readonly type: 'Ok' | 'Suspended';
+ }
+
+ /** @name PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat (552) */
+ interface PolkadotParachainPrimitivesPrimitivesXcmpMessageFormat extends Enum {
+ readonly isConcatenatedVersionedXcm: boolean;
+ readonly isConcatenatedEncodedBlob: boolean;
+ readonly isSignals: boolean;
+ readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
+ }
+
+ /** @name CumulusPalletXcmpQueueOutboundChannelDetails (555) */
+ interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
+ readonly recipient: u32;
+ readonly state: CumulusPalletXcmpQueueOutboundState;
+ readonly signalsExist: bool;
+ readonly firstIndex: u16;
+ readonly lastIndex: u16;
+ }
+
+ /** @name CumulusPalletXcmpQueueOutboundState (556) */
+ interface CumulusPalletXcmpQueueOutboundState extends Enum {
+ readonly isOk: boolean;
+ readonly isSuspended: boolean;
+ readonly type: 'Ok' | 'Suspended';
+ }
+
+ /** @name CumulusPalletXcmpQueueQueueConfigData (558) */
+ interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
+ readonly suspendThreshold: u32;
+ readonly dropThreshold: u32;
+ readonly resumeThreshold: u32;
+ readonly thresholdWeight: SpWeightsWeightV2Weight;
+ readonly weightRestrictDecay: SpWeightsWeightV2Weight;
+ readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight;
+ }
+
+ /** @name CumulusPalletXcmpQueueError (560) */
+ interface CumulusPalletXcmpQueueError extends Enum {
+ readonly isFailedToSend: boolean;
+ readonly isBadXcmOrigin: boolean;
+ readonly isBadXcm: boolean;
+ readonly isBadOverweightIndex: boolean;
+ readonly isWeightOverLimit: boolean;
+ readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
+ }
+
+ /** @name PalletXcmQueryStatus (561) */
+ interface PalletXcmQueryStatus extends Enum {
+ readonly isPending: boolean;
+ readonly asPending: {
+ readonly responder: StagingXcmVersionedMultiLocation;
+ readonly maybeMatchQuerier: Option<StagingXcmVersionedMultiLocation>;
+ readonly maybeNotify: Option<ITuple<[u8, u8]>>;
+ readonly timeout: u32;
+ } & Struct;
+ readonly isVersionNotifier: boolean;
+ readonly asVersionNotifier: {
+ readonly origin: StagingXcmVersionedMultiLocation;
+ readonly isActive: bool;
+ } & Struct;
+ readonly isReady: boolean;
+ readonly asReady: {
+ readonly response: StagingXcmVersionedResponse;
+ readonly at: u32;
+ } & Struct;
+ readonly type: 'Pending' | 'VersionNotifier' | 'Ready';
+ }
+
+ /** @name StagingXcmVersionedResponse (565) */
+ interface StagingXcmVersionedResponse extends Enum {
+ readonly isV2: boolean;
+ readonly asV2: StagingXcmV2Response;
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3Response;
+ readonly type: 'V2' | 'V3';
+ }
+
+ /** @name PalletXcmVersionMigrationStage (571) */
+ interface PalletXcmVersionMigrationStage extends Enum {
+ readonly isMigrateSupportedVersion: boolean;
+ readonly isMigrateVersionNotifiers: boolean;
+ readonly isNotifyCurrentTargets: boolean;
+ readonly asNotifyCurrentTargets: Option<Bytes>;
+ readonly isMigrateAndNotifyOldTargets: boolean;
+ readonly type: 'MigrateSupportedVersion' | 'MigrateVersionNotifiers' | 'NotifyCurrentTargets' | 'MigrateAndNotifyOldTargets';
+ }
+
+ /** @name StagingXcmVersionedAssetId (574) */
+ interface StagingXcmVersionedAssetId extends Enum {
+ readonly isV3: boolean;
+ readonly asV3: StagingXcmV3MultiassetAssetId;
+ readonly type: 'V3';
+ }
+
+ /** @name PalletXcmRemoteLockedFungibleRecord (575) */
+ interface PalletXcmRemoteLockedFungibleRecord extends Struct {
+ readonly amount: u128;
+ readonly owner: StagingXcmVersionedMultiLocation;
+ readonly locker: StagingXcmVersionedMultiLocation;
+ readonly consumers: Vec<ITuple<[Null, u128]>>;
+ }
+
+ /** @name PalletXcmError (582) */
+ interface PalletXcmError extends Enum {
+ readonly isUnreachable: boolean;
+ readonly isSendFailure: boolean;
+ readonly isFiltered: boolean;
+ readonly isUnweighableMessage: boolean;
+ readonly isDestinationNotInvertible: boolean;
+ readonly isEmpty: boolean;
+ readonly isCannotReanchor: boolean;
+ readonly isTooManyAssets: boolean;
+ readonly isInvalidOrigin: boolean;
+ readonly isBadVersion: boolean;
+ readonly isBadLocation: boolean;
+ readonly isNoSubscription: boolean;
+ readonly isAlreadySubscribed: boolean;
+ readonly isInvalidAsset: boolean;
+ readonly isLowBalance: boolean;
+ readonly isTooManyLocks: boolean;
+ readonly isAccountNotSovereign: boolean;
+ readonly isFeesNotMet: boolean;
+ readonly isLockNotFound: boolean;
+ readonly isInUse: boolean;
+ readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed' | 'InvalidAsset' | 'LowBalance' | 'TooManyLocks' | 'AccountNotSovereign' | 'FeesNotMet' | 'LockNotFound' | 'InUse';
+ }
+
+ /** @name CumulusPalletXcmError (583) */
+ type CumulusPalletXcmError = Null;
+
+ /** @name CumulusPalletDmpQueueConfigData (584) */
+ interface CumulusPalletDmpQueueConfigData extends Struct {
+ readonly maxIndividual: SpWeightsWeightV2Weight;
+ }
+
+ /** @name CumulusPalletDmpQueuePageIndexData (585) */
+ interface CumulusPalletDmpQueuePageIndexData extends Struct {
+ readonly beginUsed: u32;
+ readonly endUsed: u32;
+ readonly overweightCount: u64;
+ }
+
+ /** @name CumulusPalletDmpQueueError (588) */
+ interface CumulusPalletDmpQueueError extends Enum {
+ readonly isUnknown: boolean;
+ readonly isOverLimit: boolean;
+ readonly type: 'Unknown' | 'OverLimit';
+ }
+
+ /** @name PalletUniqueError (592) */
+ interface PalletUniqueError extends Enum {
+ readonly isCollectionDecimalPointLimitExceeded: boolean;
+ readonly isEmptyArgument: boolean;
+ readonly isRepartitionCalledOnNonRefungibleCollection: boolean;
+ readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
+ }
+
+ /** @name PalletConfigurationError (593) */
+ interface PalletConfigurationError extends Enum {
+ readonly isInconsistentConfiguration: boolean;
+ readonly type: 'InconsistentConfiguration';
+ }
+
+ /** @name UpDataStructsCollection (594) */
+ interface UpDataStructsCollection extends Struct {
+ readonly owner: AccountId32;
+ readonly mode: UpDataStructsCollectionMode;
+ readonly name: Vec<u16>;
+ readonly description: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
+ readonly limits: UpDataStructsCollectionLimits;
+ readonly permissions: UpDataStructsCollectionPermissions;
+ readonly flags: U8aFixed;
+ }
+
+ /** @name UpDataStructsSponsorshipStateAccountId32 (595) */
+ interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
+ readonly isDisabled: boolean;
+ readonly isUnconfirmed: boolean;
+ readonly asUnconfirmed: AccountId32;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: AccountId32;
+ readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
+ }
+
+ /** @name UpDataStructsProperties (596) */
+ interface UpDataStructsProperties extends Struct {
+ readonly map: UpDataStructsPropertiesMapBoundedVec;
+ readonly consumedSpace: u32;
+ readonly reserved: u32;
+ }
+
+ /** @name UpDataStructsPropertiesMapBoundedVec (597) */
+ interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
+
+ /** @name UpDataStructsPropertiesMapPropertyPermission (602) */
+ interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
+
+ /** @name UpDataStructsCollectionStats (609) */
+ interface UpDataStructsCollectionStats extends Struct {
+ readonly created: u32;
+ readonly destroyed: u32;
+ readonly alive: u32;
+ }
+
+ /** @name UpDataStructsTokenChild (610) */
+ interface UpDataStructsTokenChild extends Struct {
+ readonly token: u32;
+ readonly collection: u32;
+ }
+
+ /** @name PhantomTypeUpDataStructs (611) */
+ interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, UpPovEstimateRpcPovInfo]>> {}
+
+ /** @name UpDataStructsTokenData (613) */
+ interface UpDataStructsTokenData extends Struct {
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
+ readonly pieces: u128;
+ }
+
+ /** @name UpDataStructsRpcCollection (614) */
+ interface UpDataStructsRpcCollection extends Struct {
+ readonly owner: AccountId32;
+ readonly mode: UpDataStructsCollectionMode;
+ readonly name: Vec<u16>;
+ readonly description: Vec<u16>;
+ readonly tokenPrefix: Bytes;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
+ readonly limits: UpDataStructsCollectionLimits;
+ readonly permissions: UpDataStructsCollectionPermissions;
+ readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
+ readonly properties: Vec<UpDataStructsProperty>;
+ readonly readOnly: bool;
+ readonly flags: UpDataStructsRpcCollectionFlags;
+ }
+
+ /** @name UpDataStructsRpcCollectionFlags (615) */
+ interface UpDataStructsRpcCollectionFlags extends Struct {
+ readonly foreign: bool;
+ readonly erc721metadata: bool;
+ }
+
+ /** @name UpPovEstimateRpcPovInfo (616) */
+ interface UpPovEstimateRpcPovInfo extends Struct {
+ readonly proofSize: u64;
+ readonly compactProofSize: u64;
+ readonly compressedProofSize: u64;
+ readonly results: Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>;
+ readonly keyValues: Vec<UpPovEstimateRpcTrieKeyValue>;
+ }
+
+ /** @name SpRuntimeTransactionValidityTransactionValidityError (619) */
+ interface SpRuntimeTransactionValidityTransactionValidityError extends Enum {
+ readonly isInvalid: boolean;
+ readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction;
+ readonly isUnknown: boolean;
+ readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction;
+ readonly type: 'Invalid' | 'Unknown';
+ }
+
+ /** @name SpRuntimeTransactionValidityInvalidTransaction (620) */
+ interface SpRuntimeTransactionValidityInvalidTransaction extends Enum {
+ readonly isCall: boolean;
+ readonly isPayment: boolean;
+ readonly isFuture: boolean;
+ readonly isStale: boolean;
+ readonly isBadProof: boolean;
+ readonly isAncientBirthBlock: boolean;
+ readonly isExhaustsResources: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly isBadMandatory: boolean;
+ readonly isMandatoryValidation: boolean;
+ readonly isBadSigner: boolean;
+ readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner';
+ }
+
+ /** @name SpRuntimeTransactionValidityUnknownTransaction (621) */
+ interface SpRuntimeTransactionValidityUnknownTransaction extends Enum {
+ readonly isCannotLookup: boolean;
+ readonly isNoUnsignedValidator: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom';
+ }
+
+ /** @name UpPovEstimateRpcTrieKeyValue (623) */
+ interface UpPovEstimateRpcTrieKeyValue extends Struct {
+ readonly key: Bytes;
+ readonly value: Bytes;
+ }
+
+ /** @name PalletCommonError (625) */
+ interface PalletCommonError extends Enum {
+ readonly isCollectionNotFound: boolean;
+ readonly isMustBeTokenOwner: boolean;
+ readonly isNoPermission: boolean;
+ readonly isCantDestroyNotEmptyCollection: boolean;
+ readonly isPublicMintingNotAllowed: boolean;
+ readonly isAddressNotInAllowlist: boolean;
+ readonly isCollectionNameLimitExceeded: boolean;
+ readonly isCollectionDescriptionLimitExceeded: boolean;
+ readonly isCollectionTokenPrefixLimitExceeded: boolean;
+ readonly isTotalCollectionsLimitExceeded: boolean;
+ readonly isCollectionAdminCountExceeded: boolean;
+ readonly isCollectionLimitBoundsExceeded: boolean;
+ readonly isOwnerPermissionsCantBeReverted: boolean;
+ readonly isTransferNotAllowed: boolean;
+ readonly isAccountTokenLimitExceeded: boolean;
+ readonly isCollectionTokenLimitExceeded: boolean;
+ readonly isMetadataFlagFrozen: boolean;
+ readonly isTokenNotFound: boolean;
+ readonly isTokenValueTooLow: boolean;
+ readonly isApprovedValueTooLow: boolean;
+ readonly isCantApproveMoreThanOwned: boolean;
+ readonly isAddressIsNotEthMirror: boolean;
+ readonly isAddressIsZero: boolean;
+ readonly isUnsupportedOperation: boolean;
+ readonly isNotSufficientFounds: boolean;
+ readonly isUserIsNotAllowedToNest: boolean;
+ readonly isSourceCollectionIsNotAllowedToNest: boolean;
+ readonly isCollectionFieldSizeExceeded: boolean;
+ readonly isNoSpaceForProperty: boolean;
+ readonly isPropertyLimitReached: boolean;
+ readonly isPropertyKeyIsTooLong: boolean;
+ readonly isInvalidCharacterInPropertyKey: boolean;
+ readonly isEmptyPropertyKey: boolean;
+ readonly isCollectionIsExternal: boolean;
+ readonly isCollectionIsInternal: boolean;
+ readonly isConfirmSponsorshipFail: boolean;
+ readonly isUserIsNotCollectionAdmin: boolean;
+ readonly isFungibleItemsHaveNoId: boolean;
+ readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsNotEthMirror' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin' | 'FungibleItemsHaveNoId';
+ }
+
+ /** @name PalletFungibleError (627) */
+ interface PalletFungibleError extends Enum {
+ readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
+ readonly isFungibleItemsDontHaveData: boolean;
+ readonly isFungibleDisallowsNesting: boolean;
+ readonly isSettingPropertiesNotAllowed: boolean;
+ readonly isSettingAllowanceForAllNotAllowed: boolean;
+ readonly isFungibleTokensAreAlwaysValid: boolean;
+ readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid';
+ }
+
+ /** @name PalletRefungibleError (632) */
+ interface PalletRefungibleError extends Enum {
+ readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
+ readonly isWrongRefungiblePieces: boolean;
+ readonly isRepartitionWhileNotOwningAllPieces: boolean;
+ readonly isRefungibleDisallowsNesting: boolean;
+ readonly isSettingPropertiesNotAllowed: boolean;
+ readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
+ }
+
+ /** @name PalletNonfungibleItemData (633) */
+ interface PalletNonfungibleItemData extends Struct {
+ readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
+ }
+
+ /** @name UpDataStructsPropertyScope (635) */
+ interface UpDataStructsPropertyScope extends Enum {
+ readonly isNone: boolean;
+ readonly isRmrk: boolean;
+ readonly type: 'None' | 'Rmrk';
+ }
+
+ /** @name PalletNonfungibleError (638) */
+ interface PalletNonfungibleError extends Enum {
+ readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
+ readonly isNonfungibleItemsHaveNoAmount: boolean;
+ readonly isCantBurnNftWithChildren: boolean;
+ readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
+ }
+
+ /** @name PalletStructureError (639) */
+ interface PalletStructureError extends Enum {
+ readonly isOuroborosDetected: boolean;
+ readonly isDepthLimit: boolean;
+ readonly isBreadthLimit: boolean;
+ readonly isTokenNotFound: boolean;
+ readonly isCantNestTokenUnderCollection: boolean;
+ readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound' | 'CantNestTokenUnderCollection';
+ }
+
+ /** @name PalletAppPromotionError (644) */
+ interface PalletAppPromotionError extends Enum {
+ readonly isAdminNotSet: boolean;
+ readonly isNoPermission: boolean;
+ readonly isNotSufficientFunds: boolean;
+ readonly isPendingForBlockOverflow: boolean;
+ readonly isSponsorNotSet: boolean;
+ readonly isInsufficientStakedBalance: boolean;
+ readonly isInconsistencyState: boolean;
+ readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'InsufficientStakedBalance' | 'InconsistencyState';
+ }
+
+ /** @name PalletForeignAssetsModuleError (645) */
+ interface PalletForeignAssetsModuleError extends Enum {
+ readonly isBadLocation: boolean;
+ readonly isMultiLocationExisted: boolean;
+ readonly isAssetIdNotExists: boolean;
+ readonly isAssetIdExisted: boolean;
+ readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
+ }
+
+ /** @name PalletEvmCodeMetadata (646) */
+ interface PalletEvmCodeMetadata extends Struct {
+ readonly size_: u64;
+ readonly hash_: H256;
+ }
+
+ /** @name PalletEvmError (648) */
+ interface PalletEvmError extends Enum {
+ readonly isBalanceLow: boolean;
+ readonly isFeeOverflow: boolean;
+ readonly isPaymentOverflow: boolean;
+ readonly isWithdrawFailed: boolean;
+ readonly isGasPriceTooLow: boolean;
+ readonly isInvalidNonce: boolean;
+ readonly isGasLimitTooLow: boolean;
+ readonly isGasLimitTooHigh: boolean;
+ readonly isUndefined: boolean;
+ readonly isReentrancy: boolean;
+ readonly isTransactionMustComeFromEOA: boolean;
+ readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA';
+ }
+
+ /** @name FpRpcTransactionStatus (651) */
+ interface FpRpcTransactionStatus extends Struct {
+ readonly transactionHash: H256;
+ readonly transactionIndex: u32;
+ readonly from: H160;
+ readonly to: Option<H160>;
+ readonly contractAddress: Option<H160>;
+ readonly logs: Vec<EthereumLog>;
+ readonly logsBloom: EthbloomBloom;
+ }
+
+ /** @name EthbloomBloom (653) */
+ interface EthbloomBloom extends U8aFixed {}
+
+ /** @name EthereumReceiptReceiptV3 (655) */
+ interface EthereumReceiptReceiptV3 extends Enum {
+ readonly isLegacy: boolean;
+ readonly asLegacy: EthereumReceiptEip658ReceiptData;
+ readonly isEip2930: boolean;
+ readonly asEip2930: EthereumReceiptEip658ReceiptData;
+ readonly isEip1559: boolean;
+ readonly asEip1559: EthereumReceiptEip658ReceiptData;
+ readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
+ }
+
+ /** @name EthereumReceiptEip658ReceiptData (656) */
+ interface EthereumReceiptEip658ReceiptData extends Struct {
+ readonly statusCode: u8;
+ readonly usedGas: U256;
+ readonly logsBloom: EthbloomBloom;
+ readonly logs: Vec<EthereumLog>;
+ }
+
+ /** @name EthereumBlock (657) */
+ interface EthereumBlock extends Struct {
+ readonly header: EthereumHeader;
+ readonly transactions: Vec<EthereumTransactionTransactionV2>;
+ readonly ommers: Vec<EthereumHeader>;
+ }
+
+ /** @name EthereumHeader (658) */
+ interface EthereumHeader extends Struct {
+ readonly parentHash: H256;
+ readonly ommersHash: H256;
+ readonly beneficiary: H160;
+ readonly stateRoot: H256;
+ readonly transactionsRoot: H256;
+ readonly receiptsRoot: H256;
+ readonly logsBloom: EthbloomBloom;
+ readonly difficulty: U256;
+ readonly number: U256;
+ readonly gasLimit: U256;
+ readonly gasUsed: U256;
+ readonly timestamp: u64;
+ readonly extraData: Bytes;
+ readonly mixHash: H256;
+ readonly nonce: EthereumTypesHashH64;
+ }
+
+ /** @name EthereumTypesHashH64 (659) */
+ interface EthereumTypesHashH64 extends U8aFixed {}
+
+ /** @name PalletEthereumError (664) */
+ interface PalletEthereumError extends Enum {
+ readonly isInvalidSignature: boolean;
+ readonly isPreLogExists: boolean;
+ readonly type: 'InvalidSignature' | 'PreLogExists';
+ }
+
+ /** @name PalletEvmCoderSubstrateError (665) */
+ interface PalletEvmCoderSubstrateError extends Enum {
+ readonly isOutOfGas: boolean;
+ readonly isOutOfFund: boolean;
+ readonly type: 'OutOfGas' | 'OutOfFund';
+ }
+
+ /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (666) */
+ interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
+ readonly isDisabled: boolean;
+ readonly isUnconfirmed: boolean;
+ readonly asUnconfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
+ }
+
+ /** @name PalletEvmContractHelpersSponsoringModeT (667) */
+ interface PalletEvmContractHelpersSponsoringModeT extends Enum {
+ readonly isDisabled: boolean;
+ readonly isAllowlisted: boolean;
+ readonly isGenerous: boolean;
+ readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
+ }
+
+ /** @name PalletEvmContractHelpersError (673) */
+ interface PalletEvmContractHelpersError extends Enum {
+ readonly isNoPermission: boolean;
+ readonly isNoPendingSponsor: boolean;
+ readonly isTooManyMethodsHaveSponsoredLimit: boolean;
+ readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
+ }
+
+ /** @name PalletEvmMigrationError (674) */
+ interface PalletEvmMigrationError extends Enum {
+ readonly isAccountNotEmpty: boolean;
+ readonly isAccountIsNotMigrating: boolean;
+ readonly isBadEvent: boolean;
+ readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
+ }
+
+ /** @name PalletMaintenanceError (675) */
+ type PalletMaintenanceError = Null;
+
+ /** @name PalletUtilityError (676) */
+ interface PalletUtilityError extends Enum {
+ readonly isTooManyCalls: boolean;
+ readonly type: 'TooManyCalls';
+ }
+
+ /** @name PalletTestUtilsError (677) */
+ interface PalletTestUtilsError extends Enum {
+ readonly isTestPalletDisabled: boolean;
+ readonly isTriggerRollback: boolean;
+ readonly type: 'TestPalletDisabled' | 'TriggerRollback';
+ }
+
+ /** @name SpRuntimeMultiSignature (679) */
+ interface SpRuntimeMultiSignature extends Enum {
+ readonly isEd25519: boolean;
+ readonly asEd25519: SpCoreEd25519Signature;
+ readonly isSr25519: boolean;
+ readonly asSr25519: SpCoreSr25519Signature;
+ readonly isEcdsa: boolean;
+ readonly asEcdsa: SpCoreEcdsaSignature;
+ readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
+ }
+
+ /** @name SpCoreEd25519Signature (680) */
+ interface SpCoreEd25519Signature extends U8aFixed {}
+
+ /** @name SpCoreSr25519Signature (682) */
+ interface SpCoreSr25519Signature extends U8aFixed {}
+
+ /** @name SpCoreEcdsaSignature (683) */
+ interface SpCoreEcdsaSignature extends U8aFixed {}
+
+ /** @name FrameSystemExtensionsCheckSpecVersion (686) */
+ type FrameSystemExtensionsCheckSpecVersion = Null;
+
+ /** @name FrameSystemExtensionsCheckTxVersion (687) */
+ type FrameSystemExtensionsCheckTxVersion = Null;
+
+ /** @name FrameSystemExtensionsCheckGenesis (688) */
+ type FrameSystemExtensionsCheckGenesis = Null;
+
+ /** @name FrameSystemExtensionsCheckNonce (691) */
+ interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
+
+ /** @name FrameSystemExtensionsCheckWeight (692) */
+ type FrameSystemExtensionsCheckWeight = Null;
+
+ /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (693) */
+ type OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance = Null;
+
+ /** @name OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls (694) */
+ type OpalRuntimeRuntimeCommonIdentityDisableIdentityCalls = Null;
+
+ /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (695) */
+ interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
+
+ /** @name OpalRuntimeRuntime (696) */
+ type OpalRuntimeRuntime = Null;
+
+ /** @name PalletEthereumFakeTransactionFinalizer (697) */
+ type PalletEthereumFakeTransactionFinalizer = Null;
+
+} // declare module
js-packages/types/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/types.ts
@@ -0,0 +1,7 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './appPromotion/types.js';
+export * from './default/types.js';
+export * from './povinfo/types.js';
+export * from './unique/types.js';
js-packages/types/unique/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/unique/definitions.ts
@@ -0,0 +1,184 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+type RpcParam = {
+ name: string;
+ type: string;
+ isOptional?: true;
+};
+
+const CROSS_ACCOUNT_ID_TYPE = 'PalletEvmAccountBasicCrossAccountIdRepr';
+
+const collectionParam = {name: 'collection', type: 'u32'};
+const tokenParam = {name: 'tokenId', type: 'u32'};
+const propertyKeysParam = {name: 'propertyKeys', type: 'Option<Vec<String>>', isOptional: true};
+const crossAccountParam = (name = 'account') => ({name, type: CROSS_ACCOUNT_ID_TYPE});
+const atParam = {name: 'at', type: 'Hash', isOptional: true};
+
+const fun = (description: string, params: RpcParam[], type: string) => ({
+ description,
+ params: [...params, atParam],
+ type,
+});
+
+export default {
+ types: {},
+ rpc: {
+ accountTokens: fun(
+ 'Get tokens owned by an account in a collection',
+ [collectionParam, crossAccountParam()],
+ 'Vec<u32>',
+ ),
+ collectionTokens: fun(
+ 'Get tokens contained within a collection',
+ [collectionParam],
+ 'Vec<u32>',
+ ),
+ tokenExists: fun(
+ 'Check if the token exists',
+ [collectionParam, tokenParam],
+ 'bool',
+ ),
+
+ tokenOwner: fun(
+ 'Get the token owner',
+ [collectionParam, tokenParam],
+ `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
+ ),
+ topmostTokenOwner: fun(
+ 'Get the topmost token owner in the hierarchy of a possibly nested token',
+ [collectionParam, tokenParam],
+ `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
+ ),
+ tokenOwners: fun(
+ 'Returns 10 tokens owners in no particular order',
+ [collectionParam, tokenParam],
+ `Vec<${CROSS_ACCOUNT_ID_TYPE}>`,
+ ),
+ tokenChildren: fun(
+ 'Get tokens nested directly into the token',
+ [collectionParam, tokenParam],
+ 'Vec<UpDataStructsTokenChild>',
+ ),
+
+ collectionProperties: fun(
+ 'Get collection properties, optionally limited to the provided keys',
+ [collectionParam, propertyKeysParam],
+ 'Vec<UpDataStructsProperty>',
+ ),
+ tokenProperties: fun(
+ 'Get token properties, optionally limited to the provided keys',
+ [collectionParam, tokenParam, propertyKeysParam],
+ 'Vec<UpDataStructsProperty>',
+ ),
+ propertyPermissions: fun(
+ 'Get property permissions, optionally limited to the provided keys',
+ [collectionParam, propertyKeysParam],
+ 'Vec<UpDataStructsPropertyKeyPermission>',
+ ),
+
+ constMetadata: fun(
+ 'Get token constant metadata',
+ [collectionParam, tokenParam],
+ 'Vec<u8>',
+ ),
+ variableMetadata: fun(
+ 'Get token variable metadata',
+ [collectionParam, tokenParam],
+ 'Vec<u8>',
+ ),
+
+ tokenData: fun(
+ 'Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT',
+ [collectionParam, tokenParam, propertyKeysParam],
+ 'UpDataStructsTokenData',
+ ),
+ totalSupply: fun(
+ 'Get the amount of distinctive tokens present in a collection',
+ [collectionParam],
+ 'u32',
+ ),
+
+ accountBalance: fun(
+ 'Get the amount of any user tokens owned by an account',
+ [collectionParam, crossAccountParam()],
+ 'u32',
+ ),
+ balance: fun(
+ 'Get the amount of a specific token owned by an account',
+ [collectionParam, crossAccountParam(), tokenParam],
+ 'u128',
+ ),
+ allowance: fun(
+ 'Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor',
+ [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam],
+ 'u128',
+ ),
+
+ adminlist: fun(
+ 'Get the list of admin accounts of a collection',
+ [collectionParam],
+ 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
+ ),
+ allowlist: fun(
+ 'Get the list of accounts allowed to operate within a collection',
+ [collectionParam],
+ 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
+ ),
+ allowed: fun(
+ 'Check if a user is allowed to operate within a collection',
+ [collectionParam, crossAccountParam()],
+ 'bool',
+ ),
+
+ lastTokenId: fun(
+ 'Get the last token ID created in a collection',
+ [collectionParam],
+ 'u32',
+ ),
+ collectionById: fun(
+ 'Get a collection by the specified ID',
+ [collectionParam],
+ 'Option<UpDataStructsRpcCollection>',
+ ),
+ collectionStats: fun(
+ 'Get chain stats about collections',
+ [],
+ 'UpDataStructsCollectionStats',
+ ),
+
+ nextSponsored: fun(
+ 'Get the number of blocks until sponsoring a transaction is available',
+ [collectionParam, crossAccountParam(), tokenParam],
+ 'Option<u64>',
+ ),
+ effectiveCollectionLimits: fun(
+ 'Get effective collection limits',
+ [collectionParam],
+ 'Option<UpDataStructsCollectionLimits>',
+ ),
+ totalPieces: fun(
+ 'Get the total amount of pieces of an RFT',
+ [collectionParam, tokenParam],
+ 'Option<u128>',
+ ),
+ allowanceForAll: fun(
+ 'Tells whether the given `owner` approves the `operator`.',
+ [collectionParam, crossAccountParam('owner'), crossAccountParam('operator')],
+ 'Option<bool>',
+ ),
+ },
+};
js-packages/types/unique/index.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/unique/index.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './types.js';
js-packages/types/unique/types.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/types/unique/types.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export type PHANTOM_UNIQUE = 'unique';
js-packages/yarn.lockdiffbeforeafterboth--- a/js-packages/yarn.lock
+++ b/js-packages/yarn.lock
@@ -595,6 +595,35 @@
languageName: node
linkType: hard
+"@polkadot/typegen@npm:^10.10.1":
+ version: 10.10.1
+ resolution: "@polkadot/typegen@npm:10.10.1"
+ dependencies:
+ "@polkadot/api": 10.10.1
+ "@polkadot/api-augment": 10.10.1
+ "@polkadot/rpc-augment": 10.10.1
+ "@polkadot/rpc-provider": 10.10.1
+ "@polkadot/types": 10.10.1
+ "@polkadot/types-augment": 10.10.1
+ "@polkadot/types-codec": 10.10.1
+ "@polkadot/types-create": 10.10.1
+ "@polkadot/types-support": 10.10.1
+ "@polkadot/util": ^12.5.1
+ "@polkadot/util-crypto": ^12.5.1
+ "@polkadot/x-ws": ^12.5.1
+ handlebars: ^4.7.8
+ tslib: ^2.6.2
+ yargs: ^17.7.2
+ bin:
+ polkadot-types-chain-info: scripts/polkadot-types-chain-info.mjs
+ polkadot-types-from-chain: scripts/polkadot-types-from-chain.mjs
+ polkadot-types-from-defs: scripts/polkadot-types-from-defs.mjs
+ polkadot-types-internal-interfaces: scripts/polkadot-types-internal-interfaces.mjs
+ polkadot-types-internal-metadata: scripts/polkadot-types-internal-metadata.mjs
+ checksum: 9c167fffc476b59524ef864472b688884739c8f2deccc24b09713d7ce4247e43e352be05261ff21072dc1afbbbd2da750a11f42ae657de481d9b402ef858904b
+ languageName: node
+ linkType: hard
+
"@polkadot/types-augment@npm:10.10.1":
version: 10.10.1
resolution: "@polkadot/types-augment@npm:10.10.1"
@@ -1217,8 +1246,7 @@
version: 0.0.0-use.local
resolution: "@unique/opal-types@workspace:types"
dependencies:
- rxjs: ^7.8.1
- tslib: ^2.6.2
+ "@polkadot/typegen": ^10.10.1
languageName: unknown
linkType: soft
@@ -1965,6 +1993,17 @@
languageName: node
linkType: hard
+"cliui@npm:^8.0.1":
+ version: 8.0.1
+ resolution: "cliui@npm:8.0.1"
+ dependencies:
+ string-width: ^4.2.0
+ strip-ansi: ^6.0.1
+ wrap-ansi: ^7.0.0
+ checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56
+ languageName: node
+ linkType: hard
+
"clone-response@npm:^1.0.2":
version: 1.0.3
resolution: "clone-response@npm:1.0.3"
@@ -3376,6 +3415,24 @@
languageName: node
linkType: hard
+"handlebars@npm:^4.7.8":
+ version: 4.7.8
+ resolution: "handlebars@npm:4.7.8"
+ dependencies:
+ minimist: ^1.2.5
+ neo-async: ^2.6.2
+ source-map: ^0.6.1
+ uglify-js: ^3.1.4
+ wordwrap: ^1.0.0
+ dependenciesMeta:
+ uglify-js:
+ optional: true
+ bin:
+ handlebars: bin/handlebars
+ checksum: 00e68bb5c183fd7b8b63322e6234b5ac8fbb960d712cb3f25587d559c2951d9642df83c04a1172c918c41bcfc81bfbd7a7718bbce93b893e0135fc99edea93ff
+ languageName: node
+ linkType: hard
+
"har-schema@npm:^2.0.0":
version: 2.0.0
resolution: "har-schema@npm:2.0.0"
@@ -4199,7 +4256,7 @@
languageName: node
linkType: hard
-"minimist@npm:^1.2.6":
+"minimist@npm:^1.2.5, minimist@npm:^1.2.6":
version: 1.2.8
resolution: "minimist@npm:1.2.8"
checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0
@@ -4494,6 +4551,13 @@
languageName: node
linkType: hard
+"neo-async@npm:^2.6.2":
+ version: 2.6.2
+ resolution: "neo-async@npm:2.6.2"
+ checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9
+ languageName: node
+ linkType: hard
+
"next-tick@npm:^1.1.0":
version: 1.1.0
resolution: "next-tick@npm:1.1.0"
@@ -5422,6 +5486,13 @@
languageName: node
linkType: hard
+"source-map@npm:^0.6.1":
+ version: 0.6.1
+ resolution: "source-map@npm:0.6.1"
+ checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2
+ languageName: node
+ linkType: hard
+
"sshpk@npm:^1.7.0":
version: 1.18.0
resolution: "sshpk@npm:1.18.0"
@@ -5473,7 +5544,7 @@
languageName: node
linkType: hard
-"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0":
+"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3":
version: 4.2.3
resolution: "string-width@npm:4.2.3"
dependencies:
@@ -5886,6 +5957,15 @@
languageName: node
linkType: hard
+"uglify-js@npm:^3.1.4":
+ version: 3.17.4
+ resolution: "uglify-js@npm:3.17.4"
+ bin:
+ uglifyjs: bin/uglifyjs
+ checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924
+ languageName: node
+ linkType: hard
+
"ultron@npm:~1.1.0":
version: 1.1.1
resolution: "ultron@npm:1.1.1"
@@ -5942,6 +6022,7 @@
eslint-plugin-mocha: ^10.2.0
lossless-json: ^3.0.1
solc: ^0.8.22
+ ts-node: ^10.9.1
typechain: ^8.3.2
typescript: ^5.2.2
web3: 1.10.0
@@ -6416,6 +6497,13 @@
languageName: node
linkType: hard
+"wordwrap@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "wordwrap@npm:1.0.0"
+ checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04
+ languageName: node
+ linkType: hard
+
"wordwrapjs@npm:^4.0.0":
version: 4.0.1
resolution: "wordwrapjs@npm:4.0.1"
@@ -6573,6 +6661,13 @@
languageName: node
linkType: hard
+"yargs-parser@npm:^21.1.1":
+ version: 21.1.1
+ resolution: "yargs-parser@npm:21.1.1"
+ checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c
+ languageName: node
+ linkType: hard
+
"yargs-unparser@npm:2.0.0":
version: 2.0.0
resolution: "yargs-unparser@npm:2.0.0"
@@ -6600,6 +6695,21 @@
languageName: node
linkType: hard
+"yargs@npm:^17.7.2":
+ version: 17.7.2
+ resolution: "yargs@npm:17.7.2"
+ dependencies:
+ cliui: ^8.0.1
+ escalade: ^3.1.1
+ get-caller-file: ^2.0.5
+ require-directory: ^2.1.1
+ string-width: ^4.2.3
+ y18n: ^5.0.5
+ yargs-parser: ^21.1.1
+ checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a
+ languageName: node
+ linkType: hard
+
"yn@npm:3.1.1":
version: 3.1.1
resolution: "yn@npm:3.1.1"