1234567891011121314151617import {IKeyringPair} from '@polkadot/types/types';18import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index';19import {itEth, expect} from './util';2021describe.only('evm nft 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({url: import.meta.url});29 [alice] = await helper.arrange.createAccounts([100n], donor);30 nominal = helper.balance.getOneTokenNominal();31 });32 });3334 35 itEth('sponsors mint transactions', async ({helper}) => {36 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}});37 await collection.setSponsor(alice, alice.address);38 await collection.confirmSponsorship(alice);3940 const minter = helper.eth.createAccount();41 expect(await helper.balance.getEthereum(minter)).to.equal(0n);4243 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);44 const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', minter);4546 await collection.addToAllowList(alice, {Ethereum: minter});4748 const result = await contract.methods.mint(minter).send();4950 const events = helper.eth.normalizeEvents(result.events);51 expect(events).to.be.deep.equal([52 {53 address: collectionAddress,54 event: 'Transfer',55 args: {56 from: '0x0000000000000000000000000000000000000000',57 to: minter,58 tokenId: '1',59 },60 },61 ]);62 });6364 65 66 67 68 69 70 71 7273 74 75 7677 78 79 8081 82 83 8485 [86 'setCollectionSponsorCross',87 'setCollectionSponsor', 88 ].map(testCase =>89 itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {90 const owner = await helper.eth.createAccountWithBalance(donor);91 const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);9293 let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});94 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);95 const sponsor = await helper.eth.createAccountWithBalance(donor);96 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);97 const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner, testCase === 'setCollectionSponsor');9899 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;100 result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});101 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;102103 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});104 let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});105 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true));106 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;107108 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});109110 sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});111 expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');112 }));113114 [115 'setCollectionSponsorCross',116 'setCollectionSponsor', 117 ].map(testCase =>118 itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {119 const owner = await helper.eth.createAccountWithBalance(donor);120 const sponsorEth = await helper.eth.createAccountWithBalance(donor);121 const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);122123 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', '');124125 const collectionSub = helper.nft.getCollectionObject(collectionId);126 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor');127128 129 await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});130 let sponsorship = (await collectionSub.getData())!.raw.sponsorship;131 expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));132 133 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');134135 136 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});137 sponsorship = (await collectionSub.getData())!.raw.sponsorship;138 expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));139140 141 const user = helper.eth.createAccount();142 const userCross = helper.ethCrossAccount.fromAddress(user);143 const nextTokenId = await collectionEvm.methods.nextTokenId().call();144 expect(nextTokenId).to.be.equal('1');145146 147 const oldPermissions = (await collectionSub.getData())!.raw.permissions;148 expect(oldPermissions.mintMode).to.be.false;149 expect(oldPermissions.access).to.be.equal('Normal');150151 await collectionEvm.methods.setCollectionAccess(1 ).send({from: owner});152 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});153 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});154155 const newPermissions = (await collectionSub.getData())!.raw.permissions;156 expect(newPermissions.mintMode).to.be.true;157 expect(newPermissions.access).to.be.equal('AllowList');158159 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));160 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));161 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));162163 164 {165 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});166 const event = helper.eth.normalizeEvents(result.events)167 .find(event => event.event === 'Transfer');168169 expect(event).to.be.deep.equal({170 address: collectionAddress,171 event: 'Transfer',172 args: {173 from: '0x0000000000000000000000000000000000000000',174 to: user,175 tokenId: '1',176 },177 });178179 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));180 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));181 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));182183 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');184 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);185 expect(userBalanceAfter).to.be.eq(userBalanceBefore);186 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;187 }188 }));189190 191 192 193 194 195 196 197 198199 200201 202 203204 205 206 207208 209 210 211212 213 214215 216 217 218 219 220 221 222 223 224225 226 227 228 229 230 231 232 233 234 235 236237 238 239240 241 242 243 244 245246 [247 'setCollectionSponsorCross',248 'setCollectionSponsor', 249 ].map(testCase =>250 itEth(`[${testCase}] Check that transaction via EVM spend money from sponsor address`, async ({helper}) => {251 const owner = await helper.eth.createAccountWithBalance(donor);252 const sponsor = await helper.eth.createAccountWithBalance(donor);253 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);254255 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');256257 const collectionSub = helper.nft.getCollectionObject(collectionId);258 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor');259 260 await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();261 let collectionData = (await collectionSub.getData())!;262 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));263 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');264265 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});266 collectionData = (await collectionSub.getData())!;267 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));268269 const user = helper.eth.createAccount();270 const userCross = helper.ethCrossAccount.fromAddress(user);271 await collectionEvm.methods.addCollectionAdminCross(userCross).send();272273 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));274 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));275276 const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});277 const tokenId = mintingResult.events.Transfer.returnValues.tokenId;278279 const event = helper.eth.normalizeEvents(mintingResult.events)280 .find(event => event.event === 'Transfer');281 const address = helper.ethAddress.fromCollectionId(collectionId);282283 expect(event).to.be.deep.equal({284 address,285 event: 'Transfer',286 args: {287 from: '0x0000000000000000000000000000000000000000',288 to: user,289 tokenId: '1',290 },291 });292 expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');293294 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));295 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);296 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));297 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;298 }));299300 itEth('Can reassign collection sponsor', async ({helper}) => {301 const owner = await helper.eth.createAccountWithBalance(donor);302 const sponsorEth = await helper.eth.createAccountWithBalance(donor);303 const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);304 const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);305 const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);306307 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', '');308 const collectionSub = helper.nft.getCollectionObject(collectionId);309 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner);310311 312 await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});313 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});314315 316 await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});317 const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;318 expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});319 });320});321322describe.only('evm RFT collection sponsoring', () => {323 let donor: IKeyringPair;324 let alice: IKeyringPair;325 let nominal: bigint;326327 before(async function() {328 await usingPlaygrounds(async (helper, privateKey) => {329 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);330 donor = await privateKey({url: import.meta.url});331 [alice] = await helper.arrange.createAccounts([100n], donor);332 nominal = helper.balance.getOneTokenNominal();333 });334 });335336 [337 'mintCross',338 'mintWithTokenURI',339 ].map(testCase =>340 itEth(`[${testCase}] sponsors mint transactions`, async ({helper}) => {341 const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}, tokenPropertyPermissions: [342 {key: 'URI', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},343 ]});344345 const owner = await helper.eth.createAccountWithBalance(donor);346 await collection.setSponsor(alice, alice.address);347 await collection.confirmSponsorship(alice);348349 const minter = helper.eth.createAccount();350 const minterCross = helper.ethCrossAccount.fromAddress(minter);351 expect(await helper.balance.getEthereum(minter)).to.equal(0n);352353 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);354 const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);355356 await collection.addToAllowList(alice, {Ethereum: minter});357 await collection.addAdmin(alice, {Ethereum: owner});358 const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);359 await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/')360 .send();361362 let mintingResult;363 let tokenId;364 switch (testCase) {365 case 'mintCross':366 mintingResult = await contract.methods.mintCross(minterCross, []).send();367 break;368 case 'mintWithTokenURI':369 mintingResult = await contract.methods.mintWithTokenURI(minter, 'Test URI').send();370 tokenId = mintingResult.events.Transfer.returnValues.tokenId;371 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');372 break;373 }374375 const events = helper.eth.normalizeEvents(mintingResult.events);376 expect(events).to.deep.include({377 address: collectionAddress,378 event: 'Transfer',379 args: {380 from: '0x0000000000000000000000000000000000000000',381 to: minter,382 tokenId: '1',383 },384 });385 }));386387 [388 'setCollectionSponsorCross',389 'setCollectionSponsor', 390 ].map(testCase =>391 itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {392 const owner = await helper.eth.createAccountWithBalance(donor);393 const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);394395 let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});396 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);397 const sponsor = await helper.eth.createAccountWithBalance(donor);398 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);399 const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, testCase === 'setCollectionSponsor');400401 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;402 result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});403 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;404405 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});406 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;407408 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});409410 const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});411 expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');412 }));413414 [415 'setCollectionSponsorCross',416 'setCollectionSponsor', 417 ].map(testCase =>418 itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {419 const owner = await helper.eth.createAccountWithBalance(donor);420 const sponsorEth = await helper.eth.createAccountWithBalance(donor);421 const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);422423 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');424425 const collectionSub = helper.rft.getCollectionObject(collectionId);426 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');427428 429 await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});430 let sponsorship = (await collectionSub.getData())!.raw.sponsorship;431 expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));432 433 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');434435 436 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});437 sponsorship = (await collectionSub.getData())!.raw.sponsorship;438 expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));439440 441 const user = helper.eth.createAccount();442 const userCross = helper.ethCrossAccount.fromAddress(user);443 const nextTokenId = await collectionEvm.methods.nextTokenId().call();444 expect(nextTokenId).to.be.equal('1');445446 447 const oldPermissions = (await collectionSub.getData())!.raw.permissions;448 expect(oldPermissions.mintMode).to.be.false;449 expect(oldPermissions.access).to.be.equal('Normal');450451 await collectionEvm.methods.setCollectionAccess(1 ).send({from: owner});452 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});453 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});454455 const newPermissions = (await collectionSub.getData())!.raw.permissions;456 expect(newPermissions.mintMode).to.be.true;457 expect(newPermissions.access).to.be.equal('AllowList');458459 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));460 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));461 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));462463 464 {465 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});466 const events = helper.eth.normalizeEvents(result.events);467468 expect(events).to.deep.include({469 address: collectionAddress,470 event: 'Transfer',471 args: {472 from: '0x0000000000000000000000000000000000000000',473 to: user,474 tokenId: '1',475 },476 });477478 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));479 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));480 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));481482 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');483 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);484 expect(userBalanceAfter).to.be.eq(userBalanceBefore);485 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;486 }487 }));488489 [490 'setCollectionSponsorCross',491 'setCollectionSponsor', 492 ].map(testCase =>493 itEth(`[${testCase}] Check that collection admin EVM transaction spend money from sponsor eth address`, async ({helper}) => {494 const owner = await helper.eth.createAccountWithBalance(donor);495 const sponsor = await helper.eth.createAccountWithBalance(donor);496 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);497498 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');499500 const collectionSub = helper.rft.getCollectionObject(collectionId);501 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');502 503 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;504 await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();505 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;506 let collectionData = (await collectionSub.getData())!;507 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));508 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');509 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;510511 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});512 collectionData = (await collectionSub.getData())!;513 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));514 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;515 const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});516 const sponsorSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.ethToSubstrate(sponsor));517 const actualSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub)));518 expect(actualSubAddress).to.be.equal(sponsorSubAddress);519520 const user = helper.eth.createAccount();521 const userCross = helper.ethCrossAccount.fromAddress(user);522 await collectionEvm.methods.addCollectionAdminCross(userCross).send();523524 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));525 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));526527 const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});528 const tokenId = mintingResult.events.Transfer.returnValues.tokenId;529530 const events = helper.eth.normalizeEvents(mintingResult.events);531 const address = helper.ethAddress.fromCollectionId(collectionId);532533 expect(events).to.deep.include({534 address,535 event: 'Transfer',536 args: {537 from: '0x0000000000000000000000000000000000000000',538 to: user,539 tokenId: '1',540 },541 });542 expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');543544 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));545 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);546 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));547 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;548 }));549550 itEth('Check that collection admin EVM transaction spend money from sponsor sub address', async ({helper}) => {551 const owner = await helper.eth.createAccountWithBalance(donor);552 const sponsor = alice;553 const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);554555 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');556557 const collectionSub = helper.rft.getCollectionObject(collectionId);558 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);559 560 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;561 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();562 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;563 let collectionData = (await collectionSub.getData())!;564 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(sponsor.address);565 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');566567 await collectionSub.confirmSponsorship(sponsor);568 collectionData = (await collectionSub.getData())!;569 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(sponsor.address);570 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;571 const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});572 expect(BigInt(sponsorStruct.sub)).to.be.equal(BigInt('0x' + Buffer.from(sponsor.addressRaw).toString('hex')));573574 const user = helper.eth.createAccount();575 const userCross = helper.ethCrossAccount.fromAddress(user);576 await collectionEvm.methods.addCollectionAdminCross(userCross).send();577578 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));579 const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);580581 const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});582 const tokenId = mintingResult.events.Transfer.returnValues.tokenId;583584 const events = helper.eth.normalizeEvents(mintingResult.events);585586 expect(events).to.deep.include({587 address: collectionAddress,588 event: 'Transfer',589 args: {590 from: '0x0000000000000000000000000000000000000000',591 to: user,592 tokenId: '1',593 },594 });595 596 expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');597598 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));599 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);600 const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);601 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;602 });603604 itEth('Sponsoring collection from substrate address via access list', async ({helper}) => {605 const owner = await helper.eth.createAccountWithBalance(donor);606 const user = helper.eth.createAccount();607 const userCross = helper.ethCrossAccount.fromAddress(user);608 const sponsor = alice;609 const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);610611 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');612 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);613614 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});615616 const collectionSub = helper.rft.getCollectionObject(collectionId);617 await collectionSub.confirmSponsorship(sponsor);618619 const nextTokenId = await collectionEvm.methods.nextTokenId().call();620 expect(nextTokenId).to.be.equal('1');621622 await collectionEvm.methods.setCollectionAccess(1 ).send({from: owner});623624 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});625 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});626627 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));628 const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);629 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));630631 {632 const nextTokenId = await collectionEvm.methods.nextTokenId().call();633 expect(nextTokenId).to.be.equal('1');634 const mintingResult = await collectionEvm.methods.mintWithTokenURI(635 user,636 'Test URI',637 ).send({from: user});638639 const events = helper.eth.normalizeEvents(mintingResult.events);640641642 expect(events).to.deep.include({643 address: collectionAddress,644 event: 'Transfer',645 args: {646 from: '0x0000000000000000000000000000000000000000',647 to: user,648 tokenId: nextTokenId,649 },650 });651652 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));653 const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);654 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));655656 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');657 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);658 expect(userBalanceAfter).to.be.eq(userBalanceBefore);659 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;660 }661 });662663 itEth('Can reassign collection sponsor', async ({helper}) => {664 const owner = await helper.eth.createAccountWithBalance(donor);665 const sponsorEth = await helper.eth.createAccountWithBalance(donor);666 const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);667 const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);668 const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);669670 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');671 const collectionSub = helper.rft.getCollectionObject(collectionId);672 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);673674 675 await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});676 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});677678 679 await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});680 const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;681 expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});682 });683684 [685 'transfer',686 'transferCross',687 'transferFrom',688 'transferFromCross',689 ].map(testCase =>690 itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {691 const owner = await helper.eth.createAccountWithBalance(donor);692693 const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');694 const sponsor = await helper.eth.createAccountWithBalance(donor);695 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);696 const receiver = await helper.eth.createAccountWithBalance(donor);697 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);698699 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();700 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});701702 const user = await helper.eth.createAccountWithBalance(donor);703 const userCross = helper.ethCrossAccount.fromAddress(user);704 await collectionEvm.methods.addCollectionAdminCross(userCross).send();705706 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});707 const tokenId = result.events.Transfer.returnValues.tokenId;708709 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));710 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));711 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));712713 switch (testCase) {714 case 'transfer':715 await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});716 break;717 case 'transferCross':718 await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});719 break;720 case 'transferFrom':721 await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});722 break;723 case 'transferFromCross':724 await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});725 break;726 }727728 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));729 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);730 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));731 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;732 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));733 expect(userBalanceAfter).to.be.eq(userBalanceBefore);734 }));735});736737describe('evm RFT token sponsoring', () => {738 let donor: IKeyringPair;739740 before(async function() {741 await usingPlaygrounds(async (helper, privateKey) => {742 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);743 donor = await privateKey({url: import.meta.url});744 });745 });746747 [748 'transfer',749 'transferCross',750 'transferFrom',751 'transferFromCross',752 ].map(testCase =>753 itEth(`[${testCase}] Check that token piece transfer via EVM spend money from sponsor address`, async ({helper}) => {754 const owner = await helper.eth.createAccountWithBalance(donor);755756 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');757 const sponsor = await helper.eth.createAccountWithBalance(donor);758 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);759 const receiver = await helper.eth.createAccountWithBalance(donor);760 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);761762 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();763 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});764765 const user = await helper.eth.createAccountWithBalance(donor);766 const userCross = helper.ethCrossAccount.fromAddress(user);767 await collectionEvm.methods.addCollectionAdminCross(userCross).send();768769 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});770 const tokenId = result.events.Transfer.returnValues.tokenId;771772 const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);773 await tokenContract.methods.repartition(2).send();774775 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));776 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));777 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));778779 switch (testCase) {780 case 'transfer':781 await tokenContract.methods.transfer(receiver, 1).send();782 break;783 case 'transferCross':784 await tokenContract.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();785 break;786 case 'transferFrom':787 await tokenContract.methods.transferFrom(user, receiver, 1).send();788 break;789 case 'transferFromCross':790 await tokenContract.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), 1).send();791 break;792 }793794 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));795 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);796 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));797 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;798 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));799 expect(userBalanceAfter).to.be.eq(userBalanceBefore);800 }));801802 [803 'approve',804 'approveCross',805 ].map(testCase =>806 itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => {807 const owner = await helper.eth.createAccountWithBalance(donor);808809 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');810 const sponsor = await helper.eth.createAccountWithBalance(donor);811 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);812 const receiver = await helper.eth.createAccountWithBalance(donor);813 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);814815 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();816 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});817818 const user = await helper.eth.createAccountWithBalance(donor);819 const userCross = helper.ethCrossAccount.fromAddress(user);820 await collectionEvm.methods.addCollectionAdminCross(userCross).send();821822 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});823 const tokenId = result.events.Transfer.returnValues.tokenId;824825 const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);826 await tokenContract.methods.repartition(2).send();827828 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));829 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));830 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));831832 switch (testCase) {833 case 'approve':834 await tokenContract.methods.approve(receiver, 1).send();835 break;836 case 'approveCross':837 await tokenContract.methods.approveCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();838 break;839 }840841 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));842 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);843 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));844 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;845 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));846 expect(userBalanceAfter).to.be.eq(userBalanceBefore);847 }));848});849