1234567891011121314151617import {evmToAddress} from '@polkadot/util-crypto';18import {IKeyringPair} from '@polkadot/types/types';19import {Pallets, requirePalletsOrSkip} from '../util';20import {expect, itEth, usingEthPlaygrounds} from './util';21import {CollectionLimits} from './util/playgrounds/types';222324describe('Create RFT collection from EVM', () => {25 let donor: IKeyringPair;2627 before(async function() {28 await usingEthPlaygrounds(async (helper, privateKey) => {29 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);30 donor = await privateKey({filename: __filename});31 });32 });3334 itEth('Create collection', async ({helper}) => {35 const owner = await helper.eth.createAccountWithBalance(donor);36 37 const name = 'CollectionEVM';38 const description = 'Some description';39 const prefix = 'token prefix';40 41 const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix);42 const data = (await helper.rft.getData(collectionId))!;43 const collection = helper.rft.getCollectionObject(collectionId);4445 expect(data.name).to.be.eq(name);46 expect(data.description).to.be.eq(description);47 expect(data.raw.tokenPrefix).to.be.eq(prefix);48 expect(data.raw.mode).to.be.eq('ReFungible');4950 const options = await collection.getOptions();5152 expect(options.tokenPropertyPermissions).to.be.empty;53 });5455 5657 itEth('Create collection with properties & get description', async ({helper}) => {58 const owner = await helper.eth.createAccountWithBalance(donor);5960 const name = 'CollectionEVM';61 const description = 'Some description';62 const prefix = 'token prefix';63 const baseUri = 'BaseURI';6465 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);66 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');6768 const collection = helper.rft.getCollectionObject(collectionId);69 const data = (await collection.getData())!;70 71 expect(data.name).to.be.eq(name);72 expect(data.description).to.be.eq(description);73 expect(data.raw.tokenPrefix).to.be.eq(prefix);74 expect(data.raw.mode).to.be.eq('ReFungible');7576 expect(await contract.methods.description().call()).to.deep.equal(description);7778 const options = await collection.getOptions();79 expect(options.tokenPropertyPermissions).to.be.deep.equal([80 {81 key: 'URI',82 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},83 },84 {85 key: 'URISuffix',86 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},87 },88 ]);89 });90 91 92 itEth('[eth] Set sponsorship', async ({helper}) => {93 const owner = await helper.eth.createAccountWithBalance(donor);94 const sponsor = await helper.eth.createAccountWithBalance(donor);95 const ss58Format = helper.chain.getChainProperties().ss58Format;96 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');9798 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);99 await collection.methods.setCollectionSponsor(sponsor).send();100101 let data = (await helper.rft.getData(collectionId))!;102 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));103104 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');105106 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);107 await sponsorCollection.methods.confirmCollectionSponsorship().send();108109 data = (await helper.rft.getData(collectionId))!;110 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));111 });112113 itEth('[cross] Set sponsorship', async ({helper}) => {114 const owner = await helper.eth.createAccountWithBalance(donor);115 const sponsor = await helper.eth.createAccountWithBalance(donor);116 const ss58Format = helper.chain.getChainProperties().ss58Format;117 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');118119 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);120 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);121 await collection.methods.setCollectionSponsorCross(sponsorCross).send();122123 let data = (await helper.rft.getData(collectionId))!;124 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));125126 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');127128 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);129 await sponsorCollection.methods.confirmCollectionSponsorship().send();130131 data = (await helper.rft.getData(collectionId))!;132 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));133 });134135 itEth('Collection address exist', async ({helper}) => {136 const owner = await helper.eth.createAccountWithBalance(donor);137 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';138 expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)139 .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())140 .to.be.false;141 142 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT');143 expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)144 .methods.isCollectionExist(collectionAddress).call())145 .to.be.true;146147 148 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);149 const collectionOwner = await collectionEvm.methods.collectionOwner().call();150 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner));151 });152});153154describe('(!negative tests!) Create RFT collection from EVM', () => {155 let donor: IKeyringPair;156 let nominal: bigint;157158 before(async function() {159 await usingEthPlaygrounds(async (helper, privateKey) => {160 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);161 donor = await privateKey({filename: __filename});162 nominal = helper.balance.getOneTokenNominal();163 });164 });165166 itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {167 const owner = await helper.eth.createAccountWithBalance(donor);168 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);169 {170 const MAX_NAME_LENGTH = 64;171 const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);172 const description = 'A';173 const tokenPrefix = 'A';174175 await expect(collectionHelper.methods176 .createRFTCollection(collectionName, description, tokenPrefix)177 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);178 }179 {180 const MAX_DESCRIPTION_LENGTH = 256;181 const collectionName = 'A';182 const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);183 const tokenPrefix = 'A';184 await expect(collectionHelper.methods185 .createRFTCollection(collectionName, description, tokenPrefix)186 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);187 }188 {189 const MAX_TOKEN_PREFIX_LENGTH = 16;190 const collectionName = 'A';191 const description = 'A';192 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);193 await expect(collectionHelper.methods194 .createRFTCollection(collectionName, description, tokenPrefix)195 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);196 }197 });198 199 itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {200 const owner = await helper.eth.createAccountWithBalance(donor);201 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);202 await expect(collectionHelper.methods203 .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')204 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');205 });206207 208 itEth('(!negative test!) [eth] Check owner', async ({helper}) => {209 const owner = await helper.eth.createAccountWithBalance(donor);210 const peasant = helper.eth.createAccount();211 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');212 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true);213 const EXPECTED_ERROR = 'NoPermission';214 {215 const sponsor = await helper.eth.createAccountWithBalance(donor);216 await expect(peasantCollection.methods217 .setCollectionSponsor(sponsor)218 .call()).to.be.rejectedWith(EXPECTED_ERROR);219 220 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);221 await expect(sponsorCollection.methods222 .confirmCollectionSponsorship()223 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');224 }225 {226 await expect(peasantCollection.methods227 .setCollectionLimit(CollectionLimits.AccountTokenOwnership, true, 1000)228 .call()).to.be.rejectedWith(EXPECTED_ERROR);229 }230 });231232 itEth('(!negative test!) [cross] Check owner', async ({helper}) => {233 const owner = await helper.eth.createAccountWithBalance(donor);234 const peasant = helper.eth.createAccount();235 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');236 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant);237 const EXPECTED_ERROR = 'NoPermission';238 {239 const sponsor = await helper.eth.createAccountWithBalance(donor);240 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);241 await expect(peasantCollection.methods242 .setCollectionSponsorCross(sponsorCross)243 .call()).to.be.rejectedWith(EXPECTED_ERROR);244 245 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);246 await expect(sponsorCollection.methods247 .confirmCollectionSponsorship()248 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');249 }250 {251 await expect(peasantCollection.methods252 .setCollectionLimit(CollectionLimits.AccountTokenOwnership, true, 1000)253 .call()).to.be.rejectedWith(EXPECTED_ERROR);254 }255 });256 257 itEth('destroyCollection', async ({helper}) => {258 const owner = await helper.eth.createAccountWithBalance(donor);259 const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');260 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);261 262 await expect(collectionHelper.methods263 .destroyCollection(collectionAddress)264 .send({from: owner})).to.be.fulfilled;265 266 expect(await collectionHelper.methods267 .isCollectionExist(collectionAddress)268 .call()).to.be.false;269 expect(await helper.collection.getData(collectionId)).to.be.null;270 });271});