1234567891011121314151617import privateKey from '../substrate/privateKey';18import {expect} from 'chai';19import {20 contractHelpers,21 createEthAccountWithBalance,22 transferBalanceToEth,23 deployFlipper,24 itWeb3,25 SponsoringMode,26 createEthAccount,27 collectionIdToAddress,28 GAS_ARGS,29 normalizeEvents,30 subToEth,31 executeEthTxOnSub,32 evmCollectionHelper,33 getCollectionAddressFromResult,34 evmCollection,35} from './util/helpers';36import {37 addCollectionAdminExpectSuccess,38 createCollectionExpectSuccess,39 getCreateCollectionResult,40 getDetailedCollectionInfo,41 transferBalanceTo,42} from '../util/helpers';43import nonFungibleAbi from './nonFungibleAbi.json';44import {45 submitTransactionAsync,46} from '../substrate/substrate-api';47import getBalance from '../substrate/get-balance';48import {alicesPublicKey} from '../accounts';49import { evmToAddress } from '@polkadot/util-crypto';5051describe('Sponsoring EVM contracts', () => {52 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {53 const owner = await createEthAccountWithBalance(api, web3);54 const flipper = await deployFlipper(web3, owner);55 const helpers = contractHelpers(web3, owner);56 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;57 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});58 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;59 });6061 itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3}) => {62 const owner = await createEthAccountWithBalance(api, web3);63 const notOwner = await createEthAccountWithBalance(api, web3);64 const flipper = await deployFlipper(web3, owner);65 const helpers = contractHelpers(web3, owner);66 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;67 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;68 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;69 });7071 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3}) => {72 const alice = privateKey('//Alice');7374 const owner = await createEthAccountWithBalance(api, web3);75 const caller = await createEthAccountWithBalance(api, web3);7677 const flipper = await deployFlipper(web3, owner);7879 const helpers = contractHelpers(web3, owner);8081 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;82 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});83 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});84 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;8586 await transferBalanceToEth(api, alice, flipper.options.address);8788 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);89 expect(originalFlipperBalance).to.be.not.equal('0');9091 await flipper.methods.flip().send({from: caller});92 expect(await flipper.methods.getValue().call()).to.be.true;9394 95 const balanceAfter = await web3.eth.getBalance(flipper.options.address);96 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);97 });9899 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3}) => {100 const alice = privateKey('//Alice');101102 const owner = await createEthAccountWithBalance(api, web3);103 const caller = createEthAccount(web3);104105 const flipper = await deployFlipper(web3, owner);106107 const helpers = contractHelpers(web3, owner);108 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});109 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});110111 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;112 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});113 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});114 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;115116 await transferBalanceToEth(api, alice, flipper.options.address);117118 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);119 expect(originalFlipperBalance).to.be.not.equal('0');120121 await flipper.methods.flip().send({from: caller});122 expect(await flipper.methods.getValue().call()).to.be.true;123124 125 const balanceAfter = await web3.eth.getBalance(flipper.options.address);126 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);127 });128129 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3}) => {130 const alice = privateKey('//Alice');131132 const owner = await createEthAccountWithBalance(api, web3);133 const caller = createEthAccount(web3);134135 const flipper = await deployFlipper(web3, owner);136137 const helpers = contractHelpers(web3, owner);138139 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;140 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});141 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});142 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;143144 await transferBalanceToEth(api, alice, flipper.options.address);145146 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);147 expect(originalFlipperBalance).to.be.not.equal('0');148149 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);150 expect(await flipper.methods.getValue().call()).to.be.false;151152 153 const balanceAfter = await web3.eth.getBalance(flipper.options.address);154 expect(+balanceAfter).to.be.equals(+originalFlipperBalance);155 });156157 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3}) => {158 const alice = privateKey('//Alice');159160 const owner = await createEthAccountWithBalance(api, web3);161 const caller = await createEthAccountWithBalance(api, web3);162 const originalCallerBalance = await web3.eth.getBalance(caller);163164 const flipper = await deployFlipper(web3, owner);165166 const helpers = contractHelpers(web3, owner);167 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});168 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});169170 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;171 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});172 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});173 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;174175 await transferBalanceToEth(api, alice, flipper.options.address);176177 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);178 expect(originalFlipperBalance).to.be.not.equal('0');179180 await flipper.methods.flip().send({from: caller});181 expect(await flipper.methods.getValue().call()).to.be.true;182183 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);184 });185186 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3}) => {187 const alice = privateKey('//Alice');188189 const owner = await createEthAccountWithBalance(api, web3);190 const caller = await createEthAccountWithBalance(api, web3);191 const originalCallerBalance = await web3.eth.getBalance(caller);192193 const flipper = await deployFlipper(web3, owner);194195 const helpers = contractHelpers(web3, owner);196 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});197 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});198199 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;200 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});201 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});202 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;203204 await transferBalanceToEth(api, alice, flipper.options.address);205206 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);207 expect(originalFlipperBalance).to.be.not.equal('0');208209 await flipper.methods.flip().send({from: caller});210 expect(await flipper.methods.getValue().call()).to.be.true;211 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);212213 const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);214 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);215216 await flipper.methods.flip().send({from: caller});217 expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);218 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);219 });220221 222 itWeb3('Default rate limit equals 7200', async ({api, web3}) => {223 const owner = await createEthAccountWithBalance(api, web3);224 const flipper = await deployFlipper(web3, owner);225 const helpers = contractHelpers(web3, owner);226 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');227 });228229 230 itWeb3.skip('Sponsoring evm address from substrate collection', async ({api, web3}) => {231 const owner = await createEthAccountWithBalance(api, web3);232 const collectionHelper = evmCollectionHelper(web3, owner);233 let result = await collectionHelper.methods.create721Collection('Sponsor collection', '1', '1').send();234 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);235 const sponsor = await createEthAccountWithBalance(api, web3);236 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);237 result = await collectionEvm.methods.ethSetSponsor(sponsor).send();238 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;239 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;240 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));241 await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');242243 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);244 await sponsorCollection.methods.ethConfirmSponsorship().send();245 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;246 expect(collectionSub.sponsorship.isConfirmed).to.be.true;247 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));248249 const user = createEthAccount(web3);250 const userContract = evmCollection(web3, user, collectionIdAddress);251 const nextTokenId = await userContract.methods.nextTokenId().call();252253 expect(nextTokenId).to.be.equal('1');254 await expect(userContract.methods.mintWithTokenURI(255 user,256 nextTokenId,257 'Test URI',258 ).call()).to.be.rejectedWith('PublicMintingNotAllowed');259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279280 281282 {283 const nextTokenId = await userContract.methods.nextTokenId().call();284 expect(nextTokenId).to.be.equal('1');285 const result = await userContract.methods.mintWithTokenURI(286 user,287 nextTokenId,288 'Test URI',289 ).send();290 const events = normalizeEvents(result.events);291292 expect(events).to.be.deep.equal([293 {294 collectionIdAddress,295 event: 'Transfer',296 args: {297 from: '0x0000000000000000000000000000000000000000',298 to: user,299 tokenId: nextTokenId,300 },301 },302 ]);303304 expect(await userContract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');305 }306 });307308 309 itWeb3.skip('Check that transaction via EVM spend money from substrate address', async ({api, web3}) => {310 const owner = privateKey('//Alice');311 const user = privateKey(`//User/${Date.now()}`);312 const userEth = subToEth(user.address);313 const collectionId = await createCollectionExpectSuccess();314 await addCollectionAdminExpectSuccess(owner, collectionId, {Ethereum: userEth});315 await transferBalanceTo(api, owner, user.address);316317 const address = collectionIdToAddress(collectionId);318 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: userEth, ...GAS_ARGS});319320 const [userBalanceBefore] = await getBalance(api, [user.address]);321322 {323 const nextTokenId = await contract.methods.nextTokenId().call();324 expect(nextTokenId).to.be.equal('1');325 await executeEthTxOnSub(web3, api, user, contract, m => m.mintWithTokenURI(326 userEth,327 nextTokenId,328 'Test URI',329 ));330331 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');332 }333334 const [userBalanceAfter] = await getBalance(api, [user.address]);335 expect(userBalanceAfter < userBalanceBefore).to.be.true;336 });337});