1234567891011121314151617import {expect} from 'chai';18import {19 contractHelpers,20 createEthAccountWithBalance,21 transferBalanceToEth,22 deployFlipper,23 itWeb3,24 SponsoringMode,25 createEthAccount,26 ethBalanceViaSub,27} from './util/helpers';28import {evmToAddress} from '@polkadot/util-crypto';2930describe('Sponsoring EVM contracts', () => {31 itWeb3('Self sponsored can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {32 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);33 const flipper = await deployFlipper(web3, owner);34 const helpers = contractHelpers(web3, owner);35 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;36 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;37 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;38 });3940 itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {41 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);42 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const flipper = await deployFlipper(web3, owner);44 const helpers = contractHelpers(web3, owner);45 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;46 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');47 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;48 });4950 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {51 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);52 const flipper = await deployFlipper(web3, owner);53 const helpers = contractHelpers(web3, owner);54 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;55 await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected;56 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;57 });5859 itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {60 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);61 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);62 const flipper = await deployFlipper(web3, owner);63 const helpers = contractHelpers(web3, owner);64 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;65 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');66 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;67 });68 69 itWeb3('Sponsor can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {70 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);71 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);72 const flipper = await deployFlipper(web3, owner);73 const helpers = contractHelpers(web3, owner);74 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;75 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;76 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;77 });78 79 itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {80 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);81 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);82 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);83 const flipper = await deployFlipper(web3, owner);84 const helpers = contractHelpers(web3, owner);85 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;86 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');87 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;88 });8990 itWeb3('Sponsorship can be confirmed by the address that pending as sponsor', async ({api, web3, privateKeyWrapper}) => {91 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);92 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);93 const flipper = await deployFlipper(web3, owner);94 const helpers = contractHelpers(web3, owner);95 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;96 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;97 await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected;98 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;99 });100101 itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {102 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);103 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);105 const flipper = await deployFlipper(web3, owner);106 const helpers = contractHelpers(web3, owner);107 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;108 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;109 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');110 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;111 });112113 itWeb3('Sponsorship can not be confirmed by the address that not set as sponsor', async ({api, web3, privateKeyWrapper}) => {114 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);115 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);116 const flipper = await deployFlipper(web3, owner);117 const helpers = contractHelpers(web3, owner);118 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;119 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');120 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;121 });122123 itWeb3('Get self sponsored sponsor', async ({api, web3, privateKeyWrapper}) => {124 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);125 const flipper = await deployFlipper(web3, owner);126 const helpers = contractHelpers(web3, owner);127 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();128 129 const result = await helpers.methods.getSponsor(flipper.options.address).call();130131 expect(result[0]).to.be.eq(flipper.options.address);132 const sponsorSub = api.registry.createType('AccountId', '0x' + BigInt(result[1]).toString(16).padStart(64, '0')).toJSON();133 expect(sponsorSub).to.be.eq(evmToAddress(flipper.options.address));134 });135136 itWeb3('Get confirmed sponsor', async ({api, web3, privateKeyWrapper}) => {137 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);138 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);139 const flipper = await deployFlipper(web3, owner);140 const helpers = contractHelpers(web3, owner);141 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();142 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});143 144 const result = await helpers.methods.getSponsor(flipper.options.address).call();145146 expect(result[0]).to.be.eq(sponsor);147 const sponsorSub = api.registry.createType('AccountId', '0x' + BigInt(result[1]).toString(16).padStart(64, '0')).toJSON();148 expect(sponsorSub).to.be.eq(evmToAddress(sponsor));149 });150151 itWeb3('Sponsor can be removed by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {152 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);153 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);154 const flipper = await deployFlipper(web3, owner);155 const helpers = contractHelpers(web3, owner);156157 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;158 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();159 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});160 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;161 162 await helpers.methods.removeSponsor(flipper.options.address).send();163 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;164 });165166 itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {167 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);168 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);169 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);170 const flipper = await deployFlipper(web3, owner);171 const helpers = contractHelpers(web3, owner);172173 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;174 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();175 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});176 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;177 178 await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');179 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;180 });181182 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {183 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);184 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);185 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);186187 const flipper = await deployFlipper(web3, owner);188189 const helpers = contractHelpers(web3, owner);190191 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();192 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});193194 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});195 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});196197 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);198 const callerBalanceBefore = await ethBalanceViaSub(api, caller);199200 await flipper.methods.flip().send({from: caller});201 expect(await flipper.methods.getValue().call()).to.be.true;202203 204 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);205 const callerBalanceAfter = await ethBalanceViaSub(api, caller);206 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;207 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);208 });209210 itWeb3('In generous mode, non-allowlisted user transaction will be self sponsored', async ({api, web3, privateKeyWrapper}) => {211 const alice = privateKeyWrapper('//Alice');212213 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);214 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);215216 const flipper = await deployFlipper(web3, owner);217218 const helpers = contractHelpers(web3, owner);219220 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();221222 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});223 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});224225 await transferBalanceToEth(api, alice, flipper.options.address);226227 const contractBalanceBefore = await ethBalanceViaSub(api, flipper.options.address);228 const callerBalanceBefore = await ethBalanceViaSub(api, caller);229230 await flipper.methods.flip().send({from: caller});231 expect(await flipper.methods.getValue().call()).to.be.true;232233 234 const contractBalanceAfter = await ethBalanceViaSub(api, flipper.options.address);235 const callerBalanceAfter = await ethBalanceViaSub(api, caller);236 expect(contractBalanceAfter < contractBalanceBefore).to.be.true;237 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);238 });239240 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}) => {241 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);242 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);243 const caller = createEthAccount(web3);244245 const flipper = await deployFlipper(web3, owner);246247 const helpers = contractHelpers(web3, owner);248 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});249 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});250251 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});252 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});253254 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();255 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});256257 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);258 expect(sponsorBalanceBefore).to.be.not.equal('0');259260 await flipper.methods.flip().send({from: caller});261 expect(await flipper.methods.getValue().call()).to.be.true;262263 264 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);265 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;266 });267268 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}) => {269 const alice = privateKeyWrapper('//Alice');270271 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);272 const caller = createEthAccount(web3);273274 const flipper = await deployFlipper(web3, owner);275276 const helpers = contractHelpers(web3, owner);277278 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});279 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});280281 await transferBalanceToEth(api, alice, flipper.options.address);282283 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);284 expect(originalFlipperBalance).to.be.not.equal('0');285286 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);287 expect(await flipper.methods.getValue().call()).to.be.false;288289 290 const balanceAfter = await web3.eth.getBalance(flipper.options.address);291 expect(+balanceAfter).to.be.equals(+originalFlipperBalance);292 });293294 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}) => {295 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);296 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);297 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);298299 const flipper = await deployFlipper(web3, owner);300301 const helpers = contractHelpers(web3, owner);302 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});303 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});304305 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});306 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});307308 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();309 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});310311 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);312 const callerBalanceBefore = await ethBalanceViaSub(api, caller);313314 await flipper.methods.flip().send({from: caller});315 expect(await flipper.methods.getValue().call()).to.be.true;316317 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);318 const callerBalanceAfter = await ethBalanceViaSub(api, caller);319 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;320 expect(callerBalanceAfter).to.be.equals(callerBalanceBefore);321 });322323 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}) => {324 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);325 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);326 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);327 const originalCallerBalance = await web3.eth.getBalance(caller);328329 const flipper = await deployFlipper(web3, owner);330331 const helpers = contractHelpers(web3, owner);332 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});333 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});334335 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});336 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});337338 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();339 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});340341 const originalFlipperBalance = await web3.eth.getBalance(sponsor);342 expect(originalFlipperBalance).to.be.not.equal('0');343344 await flipper.methods.flip().send({from: caller});345 expect(await flipper.methods.getValue().call()).to.be.true;346 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);347348 const newFlipperBalance = await web3.eth.getBalance(sponsor);349 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);350351 await flipper.methods.flip().send({from: caller});352 expect(await web3.eth.getBalance(sponsor)).to.be.equal(newFlipperBalance);353 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);354 });355356 357 itWeb3('Default rate limit equals 7200', async ({api, web3, privateKeyWrapper}) => {358 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);359 const flipper = await deployFlipper(web3, owner);360 const helpers = contractHelpers(web3, owner);361 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');362 });363});