1234567891011121314151617import type {IKeyringPair} from '@polkadot/types/types';18import {evmToAddress} from '@polkadot/util-crypto';19import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';20import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';21import {CollectionLimitField} from '@unique/test-utils/eth/types.js';2223const DECIMALS = 18;2425describe('Create FT collection from EVM', () => {26 let donor: IKeyringPair;2728 before(async function() {29 await usingEthPlaygrounds(async (helper, privateKey) => {30 requirePalletsOrSkip(this, helper, [Pallets.Fungible]);31 donor = await privateKey({url: import.meta.url});32 });33 });3435 36 37 itEth('[eth] Set sponsorship', async ({helper}) => {38 const owner = await helper.eth.createAccountWithBalance(donor);39 const sponsor = await helper.eth.createAccountWithBalance(donor);40 const ss58Format = helper.chain.getChainProperties().ss58Format;41 const description = 'absolutely anything';4243 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');4445 const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);46 await collection.methods.setCollectionSponsor(sponsor).send();4748 let data = (await helper.rft.getData(collectionId))!;49 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));5051 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');5253 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);54 await sponsorCollection.methods.confirmCollectionSponsorship().send();5556 data = (await helper.rft.getData(collectionId))!;57 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));58 });5960 itEth('[cross] Set sponsorship', async ({helper}) => {61 const owner = await helper.eth.createAccountWithBalance(donor);62 const sponsor = await helper.eth.createAccountWithBalance(donor);63 const ss58Format = helper.chain.getChainProperties().ss58Format;64 const description = 'absolutely anything';65 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');6667 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);68 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);69 await collection.methods.setCollectionSponsorCross(sponsorCross).send();7071 let data = (await helper.rft.getData(collectionId))!;72 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));7374 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');7576 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);77 await sponsorCollection.methods.confirmCollectionSponsorship().send();7879 data = (await helper.rft.getData(collectionId))!;80 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));81 expect(await collection.methods.description().call()).to.deep.equal(description);82 });8384 itEth('Collection address exist', async ({helper}) => {85 const owner = await helper.eth.createAccountWithBalance(donor);86 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';87 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);8889 expect(await collectionHelpers90 .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())91 .to.be.false;9293 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');94 expect(await collectionHelpers95 .methods.isCollectionExist(collectionAddress).call())96 .to.be.true;9798 99 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);100 const collectionOwner = await collectionEvm.methods.collectionOwner().call();101 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));102 });103104 itEth('destroyCollection', async ({helper}) => {105 const owner = await helper.eth.createAccountWithBalance(donor);106 const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');107 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);108109 const result = await collectionHelper.methods110 .destroyCollection(collectionAddress)111 .send({from: owner});112113 const events = helper.eth.normalizeEvents(result.events);114115 expect(events).to.be.deep.equal([116 {117 address: collectionHelper.options.address,118 event: 'CollectionDestroyed',119 args: {120 collectionId: collectionAddress,121 },122 },123 ]);124125 expect(await collectionHelper.methods126 .isCollectionExist(collectionAddress)127 .call()).to.be.false;128 expect(await helper.collection.getData(collectionId)).to.be.null;129 });130});131132describe('(!negative tests!) Create FT collection from EVM', () => {133 let donor: IKeyringPair;134 let nominal: bigint;135136 before(async function() {137 await usingEthPlaygrounds(async (helper, privateKey) => {138 requirePalletsOrSkip(this, helper, [Pallets.Fungible]);139 donor = await privateKey({url: import.meta.url});140 nominal = helper.balance.getOneTokenNominal();141 });142 });143144 itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {145 const owner = await helper.eth.createAccountWithBalance(donor);146 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);147 {148 const MAX_NAME_LENGTH = 64;149 const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);150 const description = 'A';151 const tokenPrefix = 'A';152153 await expect(collectionHelper.methods154 .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)155 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);156 }157 {158 const MAX_DESCRIPTION_LENGTH = 256;159 const collectionName = 'A';160 const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);161 const tokenPrefix = 'A';162 await expect(collectionHelper.methods163 .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)164 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);165 }166 {167 const MAX_TOKEN_PREFIX_LENGTH = 16;168 const collectionName = 'A';169 const description = 'A';170 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);171 await expect(collectionHelper.methods172 .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)173 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);174 }175 });176177 itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {178 const owner = await helper.eth.createAccountWithBalance(donor);179 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);180 const expects = [0n, 1n, 30n].map(async value => {181 await expect(collectionHelper.methods182 .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')183 .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');184 });185 await Promise.all(expects);186 });187188 189 itEth('(!negative test!) [eth] Check owner', async ({helper}) => {190 const owner = await helper.eth.createAccountWithBalance(donor);191 const peasant = helper.eth.createAccount();192 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');193 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant, true);194 const EXPECTED_ERROR = 'NoPermission';195 {196 const sponsor = await helper.eth.createAccountWithBalance(donor);197 await expect(peasantCollection.methods198 .setCollectionSponsor(sponsor)199 .call()).to.be.rejectedWith(EXPECTED_ERROR);200201 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor, true);202 await expect(sponsorCollection.methods203 .confirmCollectionSponsorship()204 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');205 }206 {207 await expect(peasantCollection.methods208 .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})209 .call()).to.be.rejectedWith(EXPECTED_ERROR);210 }211 });212213 itEth('(!negative test!) [cross] Check owner', async ({helper}) => {214 const owner = await helper.eth.createAccountWithBalance(donor);215 const peasant = helper.eth.createAccount();216 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');217 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant);218 const EXPECTED_ERROR = 'NoPermission';219 {220 const sponsor = await helper.eth.createAccountWithBalance(donor);221 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);222 await expect(peasantCollection.methods223 .setCollectionSponsorCross(sponsorCross)224 .call()).to.be.rejectedWith(EXPECTED_ERROR);225226 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor);227 await expect(sponsorCollection.methods228 .confirmCollectionSponsorship()229 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');230 }231 {232 await expect(peasantCollection.methods233 .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}})234 .call()).to.be.rejectedWith(EXPECTED_ERROR);235 }236 });237});