1234567891011121314151617import {evmToAddress} from '@polkadot/util-crypto';18import {IKeyringPair} from '@polkadot/types/types';19import {Pallets, requirePalletsOrSkip} from '../util';20import {expect, itEth, usingEthPlaygrounds} from './util';212223describe('Create RFT collection from EVM', () => {24 let donor: IKeyringPair;2526 before(async function() {27 await usingEthPlaygrounds(async (helper, privateKey) => {28 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);29 donor = await privateKey({filename: __filename});30 });31 });3233 itEth('Create collection', async ({helper}) => {34 const owner = await helper.eth.createAccountWithBalance(donor);35 36 const name = 'CollectionEVM';37 const description = 'Some description';38 const prefix = 'token prefix';39 40 const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix);41 const data = (await helper.rft.getData(collectionId))!;42 const collection = helper.rft.getCollectionObject(collectionId);4344 expect(data.name).to.be.eq(name);45 expect(data.description).to.be.eq(description);46 expect(data.raw.tokenPrefix).to.be.eq(prefix);47 expect(data.raw.mode).to.be.eq('ReFungible');4849 const options = await collection.getOptions();5051 expect(options.tokenPropertyPermissions).to.be.empty;52 });5354 5556 itEth('Create collection with properties & get description', async ({helper}) => {57 const owner = await helper.eth.createAccountWithBalance(donor);5859 const name = 'CollectionEVM';60 const description = 'Some description';61 const prefix = 'token prefix';62 const baseUri = 'BaseURI';6364 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);65 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');6667 const collection = helper.rft.getCollectionObject(collectionId);68 const data = (await collection.getData())!;69 70 expect(data.name).to.be.eq(name);71 expect(data.description).to.be.eq(description);72 expect(data.raw.tokenPrefix).to.be.eq(prefix);73 expect(data.raw.mode).to.be.eq('ReFungible');7475 expect(await contract.methods.description().call()).to.deep.equal(description);7677 const options = await collection.getOptions();78 expect(options.tokenPropertyPermissions).to.be.deep.equal([79 {80 key: 'URI',81 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},82 },83 {84 key: 'URISuffix',85 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},86 },87 ]);88 });89 90 91 itEth.skip('Check collection address exist', async ({helper}) => {92 const owner = await helper.eth.createAccountWithBalance(donor);9394 const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;95 const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);96 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);9798 expect(await collectionHelpers.methods99 .isCollectionExist(expectedCollectionAddress)100 .call()).to.be.false;101102 await collectionHelpers.methods103 .createRFTCollection('A', 'A', 'A')104 .send({value: Number(2n * helper.balance.getOneTokenNominal())});105 106 expect(await collectionHelpers.methods107 .isCollectionExist(expectedCollectionAddress)108 .call()).to.be.true;109 });110 111 112 itEth('[eth] Set sponsorship', async ({helper}) => {113 const owner = await helper.eth.createAccountWithBalance(donor);114 const sponsor = await helper.eth.createAccountWithBalance(donor);115 const ss58Format = helper.chain.getChainProperties().ss58Format;116 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');117118 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);119 await collection.methods.setCollectionSponsor(sponsor).send();120121 let data = (await helper.rft.getData(collectionId))!;122 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));123124 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');125126 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);127 await sponsorCollection.methods.confirmCollectionSponsorship().send();128129 data = (await helper.rft.getData(collectionId))!;130 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));131 });132133 itEth('[cross] Set sponsorship', async ({helper}) => {134 const owner = await helper.eth.createAccountWithBalance(donor);135 const sponsor = await helper.eth.createAccountWithBalance(donor);136 const ss58Format = helper.chain.getChainProperties().ss58Format;137 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');138139 const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);140 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);141 await collection.methods.setCollectionSponsorCross(sponsorCross).send();142143 let data = (await helper.rft.getData(collectionId))!;144 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));145146 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');147148 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);149 await sponsorCollection.methods.confirmCollectionSponsorship().send();150151 data = (await helper.rft.getData(collectionId))!;152 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));153 });154155 itEth('Collection address exist', async ({helper}) => {156 const owner = await helper.eth.createAccountWithBalance(donor);157 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';158 expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)159 .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())160 .to.be.false;161 162 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT');163 expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)164 .methods.isCollectionExist(collectionAddress).call())165 .to.be.true;166 });167});168169describe('(!negative tests!) Create RFT collection from EVM', () => {170 let donor: IKeyringPair;171 let nominal: bigint;172173 before(async function() {174 await usingEthPlaygrounds(async (helper, privateKey) => {175 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);176 donor = await privateKey({filename: __filename});177 nominal = helper.balance.getOneTokenNominal();178 });179 });180181 itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {182 const owner = await helper.eth.createAccountWithBalance(donor);183 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);184 {185 const MAX_NAME_LENGTH = 64;186 const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);187 const description = 'A';188 const tokenPrefix = 'A';189190 await expect(collectionHelper.methods191 .createRFTCollection(collectionName, description, tokenPrefix)192 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);193 }194 {195 const MAX_DESCRIPTION_LENGTH = 256;196 const collectionName = 'A';197 const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);198 const tokenPrefix = 'A';199 await expect(collectionHelper.methods200 .createRFTCollection(collectionName, description, tokenPrefix)201 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);202 }203 {204 const MAX_TOKEN_PREFIX_LENGTH = 16;205 const collectionName = 'A';206 const description = 'A';207 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);208 await expect(collectionHelper.methods209 .createRFTCollection(collectionName, description, tokenPrefix)210 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);211 }212 });213 214 itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {215 const owner = await helper.eth.createAccountWithBalance(donor);216 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);217 await expect(collectionHelper.methods218 .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')219 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');220 });221222 223 itEth('(!negative test!) [eth] Check owner', async ({helper}) => {224 const owner = await helper.eth.createAccountWithBalance(donor);225 const peasant = helper.eth.createAccount();226 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');227 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true);228 const EXPECTED_ERROR = 'NoPermission';229 {230 const sponsor = await helper.eth.createAccountWithBalance(donor);231 await expect(peasantCollection.methods232 .setCollectionSponsor(sponsor)233 .call()).to.be.rejectedWith(EXPECTED_ERROR);234 235 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);236 await expect(sponsorCollection.methods237 .confirmCollectionSponsorship()238 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');239 }240 {241 await expect(peasantCollection.methods242 .setCollectionLimit('accountTokenOwnershipLimit', '1000')243 .call()).to.be.rejectedWith(EXPECTED_ERROR);244 }245 });246247 itEth('(!negative test!) [cross] Check owner', async ({helper}) => {248 const owner = await helper.eth.createAccountWithBalance(donor);249 const peasant = helper.eth.createAccount();250 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');251 const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant);252 const EXPECTED_ERROR = 'NoPermission';253 {254 const sponsor = await helper.eth.createAccountWithBalance(donor);255 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);256 await expect(peasantCollection.methods257 .setCollectionSponsorCross(sponsorCross)258 .call()).to.be.rejectedWith(EXPECTED_ERROR);259 260 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);261 await expect(sponsorCollection.methods262 .confirmCollectionSponsorship()263 .call()).to.be.rejectedWith('ConfirmSponsorshipFail');264 }265 {266 await expect(peasantCollection.methods267 .setCollectionLimit('accountTokenOwnershipLimit', '1000')268 .call()).to.be.rejectedWith(EXPECTED_ERROR);269 }270 });271 272 itEth('destroyCollection', async ({helper}) => {273 const owner = await helper.eth.createAccountWithBalance(donor);274 const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');275 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);276 277 await expect(collectionHelper.methods278 .destroyCollection(collectionAddress)279 .send({from: owner})).to.be.fulfilled;280 281 expect(await collectionHelper.methods282 .isCollectionExist(collectionAddress)283 .call()).to.be.false;284 expect(await helper.collection.getData(collectionId)).to.be.null;285 });286});