1234567891011121314151617import {IKeyringPair} from '@polkadot/types/types';18import {usingPlaygrounds} from '../util/index';19import {itEth, expect} from './util';2021describe('evm collection sponsoring', () => {22 let donor: IKeyringPair;23 let alice: IKeyringPair;24 let nominal: bigint;2526 before(async () => {27 await usingPlaygrounds(async (helper, privateKey) => {28 donor = await privateKey({filename: __filename});29 [alice] = await helper.arrange.createAccounts([100n], donor);30 nominal = helper.balance.getOneTokenNominal();31 });32 });33 34 itEth('sponsors mint transactions', async ({helper}) => {35 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}});36 await collection.setSponsor(alice, alice.address);37 await collection.confirmSponsorship(alice);3839 const minter = helper.eth.createAccount();40 expect(await helper.balance.getEthereum(minter)).to.equal(0n);4142 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);43 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', minter);4445 await collection.addToAllowList(alice, {Ethereum: minter});4647 const result = await contract.methods.mint(minter).send();4849 const events = helper.eth.normalizeEvents(result.events);50 expect(events).to.be.deep.equal([51 {52 address: collectionAddress,53 event: 'Transfer',54 args: {55 from: '0x0000000000000000000000000000000000000000',56 to: minter,57 tokenId: '1',58 },59 },60 ]);61 });6263 64 65 66 67 68 69 70 7172 73 74 7576 77 78 7980 81 82 8384 85 itEth('[eth] Remove sponsor', async ({helper}) => {86 const owner = await helper.eth.createAccountWithBalance(donor);87 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);8889 let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});90 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);91 const sponsor = await helper.eth.createAccountWithBalance(donor);92 const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner, true);9394 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;95 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});96 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;9798 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});99 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;100101 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});102103 const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});104 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');105 });106107 itEth('[cross] Remove sponsor', async ({helper}) => {108 const owner = await helper.eth.createAccountWithBalance(donor);109 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);110111 let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});112 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);113 const sponsor = await helper.eth.createAccountWithBalance(donor);114 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);115 const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner);116117 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;118 result = await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});119 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;120121 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});122 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;123124 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});125126 const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});127 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');128 });129130 131 itEth('[eth] Sponsoring collection from evm address via access list', async ({helper}) => {132 const owner = await helper.eth.createAccountWithBalance(donor);133134 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');135136 const collection = helper.nft.getCollectionObject(collectionId);137 const sponsor = await helper.eth.createAccountWithBalance(donor);138 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);139140 await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});141 let collectionData = (await collection.getData())!;142 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));143 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');144145 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});146 collectionData = (await collection.getData())!;147 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));148149 const user = helper.eth.createAccount();150 const nextTokenId = await collectionEvm.methods.nextTokenId().call();151 expect(nextTokenId).to.be.equal('1');152153 const oldPermissions = (await collection.getData())!.raw.permissions; 154 expect(oldPermissions.mintMode).to.be.false;155 expect(oldPermissions.access).to.be.equal('Normal');156157 await collectionEvm.methods.setCollectionAccess(1 ).send({from: owner});158 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});159 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});160161 const newPermissions = (await collection.getData())!.raw.permissions; 162 expect(newPermissions.mintMode).to.be.true;163 expect(newPermissions.access).to.be.equal('AllowList');164165 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));166 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));167168 {169 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});170 const events = helper.eth.normalizeEvents(result.events);171172 expect(events).to.be.deep.equal([173 {174 address: collectionAddress,175 event: 'Transfer',176 args: {177 from: '0x0000000000000000000000000000000000000000',178 to: user,179 tokenId: '1',180 },181 },182 ]);183184 const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner));185 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));186187 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');188 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);189 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;190 }191 });192193 itEth('[cross] Sponsoring collection from evm address via access list', async ({helper}) => {194 const owner = await helper.eth.createAccountWithBalance(donor);195196 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');197198 const collection = helper.nft.getCollectionObject(collectionId);199 const sponsor = await helper.eth.createAccountWithBalance(donor);200 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);201 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);202203 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});204 let collectionData = (await collection.getData())!;205 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));206 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');207208 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});209 collectionData = (await collection.getData())!;210 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));211212 const user = helper.eth.createAccount();213 const userCross = helper.ethCrossAccount.fromAddress(user);214 const nextTokenId = await collectionEvm.methods.nextTokenId().call();215 expect(nextTokenId).to.be.equal('1');216217 const oldPermissions = (await collection.getData())!.raw.permissions; 218 expect(oldPermissions.mintMode).to.be.false;219 expect(oldPermissions.access).to.be.equal('Normal');220221 await collectionEvm.methods.setCollectionAccess(1 ).send({from: owner});222 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});223 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});224225 const newPermissions = (await collection.getData())!.raw.permissions; 226 expect(newPermissions.mintMode).to.be.true;227 expect(newPermissions.access).to.be.equal('AllowList');228229 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));230 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));231232 {233 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});234 const events = helper.eth.normalizeEvents(result.events);235236 expect(events).to.be.deep.equal([237 {238 address: collectionAddress,239 event: 'Transfer',240 args: {241 from: '0x0000000000000000000000000000000000000000',242 to: user,243 tokenId: '1',244 },245 },246 ]);247248 const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner));249 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));250251 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');252 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);253 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;254 }255 });256257 258 259 260 261 262 263 264 265266 267268 269 270271 272 273 274275 276 277 278279 280 281282 283 284 285 286 287 288 289 290 291292 293 294 295 296 297 298 299 300 301 302 303304 305 306307 308 309 310 311 312313 314 itEth('[eth] Check that transaction via EVM spend money from sponsor address', async ({helper}) => {315 const owner = await helper.eth.createAccountWithBalance(donor);316317 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');318 const collection = helper.nft.getCollectionObject(collectionId);319 const sponsor = await helper.eth.createAccountWithBalance(donor);320 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);321322 await collectionEvm.methods.setCollectionSponsor(sponsor).send();323 let collectionData = (await collection.getData())!;324 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));325 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');326327 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);328 await sponsorCollection.methods.confirmCollectionSponsorship().send();329 collectionData = (await collection.getData())!;330 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));331332 const user = helper.eth.createAccount();333 await collectionEvm.methods.addCollectionAdmin(user).send();334335 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));336 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));337338 const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', user, true);339340 const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').send();341 const tokenId = result.events.Transfer.returnValues.tokenId;342343 const events = helper.eth.normalizeEvents(result.events);344 const address = helper.ethAddress.fromCollectionId(collectionId);345346 expect(events).to.be.deep.equal([347 {348 address,349 event: 'Transfer',350 args: {351 from: '0x0000000000000000000000000000000000000000',352 to: user,353 tokenId: '1',354 },355 },356 ]);357 expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');358359 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));360 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);361 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));362 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;363 });364365 itEth('[cross] Check that transaction via EVM spend money from sponsor address', async ({helper}) => {366 const owner = await helper.eth.createAccountWithBalance(donor);367368 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');369 const collection = helper.nft.getCollectionObject(collectionId);370 const sponsor = await helper.eth.createAccountWithBalance(donor);371 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);372 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);373374 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();375 let collectionData = (await collection.getData())!;376 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));377 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');378379 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);380 await sponsorCollection.methods.confirmCollectionSponsorship().send();381 collectionData = (await collection.getData())!;382 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));383384 const user = helper.eth.createAccount();385 const userCross = helper.ethCrossAccount.fromAddress(user);386 await collectionEvm.methods.addCollectionAdminCross(userCross).send();387388 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));389 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));390391 const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', user);392393 const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').send();394 const tokenId = result.events.Transfer.returnValues.tokenId;395396 const events = helper.eth.normalizeEvents(result.events);397 const address = helper.ethAddress.fromCollectionId(collectionId);398399 expect(events).to.be.deep.equal([400 {401 address,402 event: 'Transfer',403 args: {404 from: '0x0000000000000000000000000000000000000000',405 to: user,406 tokenId: '1',407 },408 },409 ]);410 expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');411412 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));413 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);414 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));415 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;416 });417});