1234567891011121314151617import {IKeyringPair} from '@polkadot/types/types';18import {evmToAddress} from '@polkadot/util-crypto';19import {Pallets, requirePalletsOrSkip} from '../util';20import {expect, itEth, usingEthPlaygrounds} from './util';21import {CollectionLimits} from './util/playgrounds/types';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({filename: __filename});32 });33 });34 35 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';42 43 const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY');4445 const collection = 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');66 67 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 expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)88 .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())89 .to.be.false;90 91 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');92 expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)93 .methods.isCollectionExist(collectionAddress).call())94 .to.be.true;95 96 97 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);98 const collectionOwner = await collectionEvm.methods.collectionOwner().call();99 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner));100 });101 102 itEth('destroyCollection', async ({helper}) => {103 const owner = await helper.eth.createAccountWithBalance(donor);104 const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');105 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);106107 const result = await collectionHelper.methods108 .destroyCollection(collectionAddress)109 .send({from: owner});110111 const events = helper.eth.normalizeEvents(result.events);112 113 expect(events).to.be.deep.equal([114 {115 address: collectionHelper.options.address,116 event: 'CollectionDestroyed',117 args: {118 collectionId: collectionAddress,119 },120 },121 ]);122123 expect(await collectionHelper.methods124 .isCollectionExist(collectionAddress)125 .call()).to.be.false;126 expect(await helper.collection.getData(collectionId)).to.be.null;127 });128});129130describe('(!negative tests!) Create FT collection from EVM', () => {131 let donor: IKeyringPair;132 let nominal: bigint;133134 before(async function() {135 await usingEthPlaygrounds(async (helper, privateKey) => {136 requirePalletsOrSkip(this, helper, [Pallets.Fungible]);137 donor = await privateKey({filename: __filename});138 nominal = helper.balance.getOneTokenNominal();139 });140 });141142 itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {143 const owner = await helper.eth.createAccountWithBalance(donor);144 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);145 {146 const MAX_NAME_LENGTH = 64;147 const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);148 const description = 'A';149 const tokenPrefix = 'A';150151 await expect(collectionHelper.methods152 .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)153 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);154 }155 {156 const MAX_DESCRIPTION_LENGTH = 256;157 const collectionName = 'A';158 const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);159 const tokenPrefix = 'A';160 await expect(collectionHelper.methods161 .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)162 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);163 }164 {165 const MAX_TOKEN_PREFIX_LENGTH = 16;166 const collectionName = 'A';167 const description = 'A';168 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);169 await expect(collectionHelper.methods170 .createFTCollection(collectionName, DECIMALS, description, tokenPrefix)171 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);172 }173 });174 175 itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {176 const owner = await helper.eth.createAccountWithBalance(donor);177 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);178 const expects = [0n, 1n, 30n].map(async value => {179 await expect(collectionHelper.methods180 .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')181 .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');182 });183 await Promise.all(expects);184 });185186 187 itEth('(!negative test!) [eth] Check owner', async ({helper}) => {188 const owner = await helper.eth.createAccountWithBalance(donor);189 const peasant = helper.eth.createAccount();190 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');191 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant, true);192 const EXPECTED_ERROR = 'NoPermission';193 {194 const sponsor = await helper.eth.createAccountWithBalance(donor);195 await expect(peasantCollection.methods196 .setCollectionSponsor(sponsor)197 .call()).to.be.rejectedWith(EXPECTED_ERROR);198 199 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor, true);200 await expect(sponsorCollection.methods201 .confirmCollectionSponsorship()202 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');203 }204 {205 await expect(peasantCollection.methods206 .setCollectionLimit(CollectionLimits.AccountTokenOwnership, true, 1000)207 .call()).to.be.rejectedWith(EXPECTED_ERROR);208 }209 });210211 itEth('(!negative test!) [cross] Check owner', async ({helper}) => {212 const owner = await helper.eth.createAccountWithBalance(donor);213 const peasant = helper.eth.createAccount();214 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE');215 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', peasant);216 const EXPECTED_ERROR = 'NoPermission';217 {218 const sponsor = await helper.eth.createAccountWithBalance(donor);219 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);220 await expect(peasantCollection.methods221 .setCollectionSponsorCross(sponsorCross)222 .call()).to.be.rejectedWith(EXPECTED_ERROR);223 224 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor);225 await expect(sponsorCollection.methods226 .confirmCollectionSponsorship()227 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');228 }229 {230 await expect(peasantCollection.methods231 .setCollectionLimit(CollectionLimits.AccountTokenOwnership, true, 1000)232 .call()).to.be.rejectedWith(EXPECTED_ERROR);233 }234 }); 235});