1234567891011121314151617import {expect} from 'chai';18import {19 contractHelpers,20 createEthAccountWithBalance,21 transferBalanceToEth,22 deployFlipper,23 itWeb3,24 SponsoringMode,25 createEthAccount,26 collectionIdToAddress,27 GAS_ARGS,28 normalizeEvents,29 subToEth,30 executeEthTxOnSub,31 evmCollectionHelpers,32 getCollectionAddressFromResult,33 evmCollection,34} from './util/helpers';35import {36 addCollectionAdminExpectSuccess,37 createCollectionExpectSuccess,38 getDetailedCollectionInfo,39 transferBalanceTo,40} from '../util/helpers';41import nonFungibleAbi from './nonFungibleAbi.json';42import getBalance from '../substrate/get-balance';43import {evmToAddress} from '@polkadot/util-crypto';4445describe('Sponsoring EVM contracts', () => {46 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {47 const owner = await createEthAccountWithBalance(api, web3);48 const flipper = await deployFlipper(web3, owner);49 const helpers = contractHelpers(web3, owner);50 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;51 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});52 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;53 });5455 itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3}) => {56 const owner = await createEthAccountWithBalance(api, web3);57 const notOwner = await createEthAccountWithBalance(api, web3);58 const flipper = await deployFlipper(web3, owner);59 const helpers = contractHelpers(web3, owner);60 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;61 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;62 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;63 });6465 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {66 const alice = privateKeyWrapper('//Alice');6768 const owner = await createEthAccountWithBalance(api, web3);69 const caller = await createEthAccountWithBalance(api, web3);7071 const flipper = await deployFlipper(web3, owner);7273 const helpers = contractHelpers(web3, owner);7475 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;76 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});77 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});78 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;7980 await transferBalanceToEth(api, alice, flipper.options.address);8182 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);83 expect(originalFlipperBalance).to.be.not.equal('0');8485 await flipper.methods.flip().send({from: caller});86 expect(await flipper.methods.getValue().call()).to.be.true;8788 89 const balanceAfter = await web3.eth.getBalance(flipper.options.address);90 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);91 });9293 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, privateKeyWrapper}) => {94 const alice = privateKeyWrapper('//Alice');9596 const owner = await createEthAccountWithBalance(api, web3);97 const caller = createEthAccount(web3);9899 const flipper = await deployFlipper(web3, owner);100101 const helpers = contractHelpers(web3, owner);102 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});103 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});104105 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;106 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});107 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});108 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;109110 await transferBalanceToEth(api, alice, flipper.options.address);111112 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);113 expect(originalFlipperBalance).to.be.not.equal('0');114115 await flipper.methods.flip().send({from: caller});116 expect(await flipper.methods.getValue().call()).to.be.true;117118 119 const balanceAfter = await web3.eth.getBalance(flipper.options.address);120 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);121 });122123 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, privateKeyWrapper}) => {124 const alice = privateKeyWrapper('//Alice');125126 const owner = await createEthAccountWithBalance(api, web3);127 const caller = createEthAccount(web3);128129 const flipper = await deployFlipper(web3, owner);130131 const helpers = contractHelpers(web3, owner);132133 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;134 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});135 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});136 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;137138 await transferBalanceToEth(api, alice, flipper.options.address);139140 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);141 expect(originalFlipperBalance).to.be.not.equal('0');142143 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);144 expect(await flipper.methods.getValue().call()).to.be.false;145146 147 const balanceAfter = await web3.eth.getBalance(flipper.options.address);148 expect(+balanceAfter).to.be.equals(+originalFlipperBalance);149 });150151 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => {152 const alice = privateKeyWrapper('//Alice');153154 const owner = await createEthAccountWithBalance(api, web3);155 const caller = await createEthAccountWithBalance(api, web3);156 const originalCallerBalance = await web3.eth.getBalance(caller);157158 const flipper = await deployFlipper(web3, owner);159160 const helpers = contractHelpers(web3, owner);161 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});162 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});163164 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;165 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});166 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});167 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;168169 await transferBalanceToEth(api, alice, flipper.options.address);170171 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);172 expect(originalFlipperBalance).to.be.not.equal('0');173174 await flipper.methods.flip().send({from: caller});175 expect(await flipper.methods.getValue().call()).to.be.true;176177 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);178 });179180 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => {181 const alice = privateKeyWrapper('//Alice');182183 const owner = await createEthAccountWithBalance(api, web3);184 const caller = await createEthAccountWithBalance(api, web3);185 const originalCallerBalance = await web3.eth.getBalance(caller);186187 const flipper = await deployFlipper(web3, owner);188189 const helpers = contractHelpers(web3, owner);190 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});191 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});192193 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;194 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});195 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});196 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;197198 await transferBalanceToEth(api, alice, flipper.options.address);199200 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);201 expect(originalFlipperBalance).to.be.not.equal('0');202203 await flipper.methods.flip().send({from: caller});204 expect(await flipper.methods.getValue().call()).to.be.true;205 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);206207 const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);208 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);209210 await flipper.methods.flip().send({from: caller});211 expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);212 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);213 });214215 216 itWeb3('Default rate limit equals 7200', async ({api, web3}) => {217 const owner = await createEthAccountWithBalance(api, web3);218 const flipper = await deployFlipper(web3, owner);219 const helpers = contractHelpers(web3, owner);220 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');221 });222223 224 itWeb3.skip('Sponsoring evm address from substrate collection', async ({api, web3}) => {225 const owner = await createEthAccountWithBalance(api, web3);226 const collectionHelpers = evmCollectionHelpers(web3, owner);227 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();228 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);229 const sponsor = await createEthAccountWithBalance(api, web3);230 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);231 result = await collectionEvm.methods.ethSetSponsor(sponsor).send();232 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;233 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;234 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));235 await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');236237 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);238 await sponsorCollection.methods.ethConfirmSponsorship().send();239 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;240 expect(collectionSub.sponsorship.isConfirmed).to.be.true;241 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));242243 const user = createEthAccount(web3);244 const userContract = evmCollection(web3, user, collectionIdAddress);245 const nextTokenId = await userContract.methods.nextTokenId().call();246247 expect(nextTokenId).to.be.equal('1');248 await expect(userContract.methods.mintWithTokenURI(249 user,250 nextTokenId,251 'Test URI',252 ).call()).to.be.rejectedWith('PublicMintingNotAllowed');253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273274 275276 {277 const nextTokenId = await userContract.methods.nextTokenId().call();278 expect(nextTokenId).to.be.equal('1');279 const result = await userContract.methods.mintWithTokenURI(280 user,281 nextTokenId,282 'Test URI',283 ).send();284 const events = normalizeEvents(result.events);285286 expect(events).to.be.deep.equal([287 {288 collectionIdAddress,289 event: 'Transfer',290 args: {291 from: '0x0000000000000000000000000000000000000000',292 to: user,293 tokenId: nextTokenId,294 },295 },296 ]);297298 expect(await userContract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');299 }300 });301302 303 itWeb3.skip('Check that transaction via EVM spend money from substrate address', async ({api, web3, privateKeyWrapper}) => {304 const owner = privateKeyWrapper('//Alice');305 const user = privateKeyWrapper(`//User/${Date.now()}`);306 const userEth = subToEth(user.address);307 const collectionId = await createCollectionExpectSuccess();308 await addCollectionAdminExpectSuccess(owner, collectionId, {Ethereum: userEth});309 await transferBalanceTo(api, owner, user.address);310311 const address = collectionIdToAddress(collectionId);312 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: userEth, ...GAS_ARGS});313314 const [userBalanceBefore] = await getBalance(api, [user.address]);315316 {317 const nextTokenId = await contract.methods.nextTokenId().call();318 expect(nextTokenId).to.be.equal('1');319 await executeEthTxOnSub(web3, api, user, contract, m => m.mintWithTokenURI(320 userEth,321 nextTokenId,322 'Test URI',323 ));324325 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');326 }327328 const [userBalanceAfter] = await getBalance(api, [user.address]);329 expect(userBalanceAfter < userBalanceBefore).to.be.true;330 });331});