git.delta.rocks / unique-network / refs/commits / add44eb3dbb8

difftreelog

Merge branch 'develop' into tests/feed-alices

Fahrrader2022-10-06parents: #535a8e9 #05841c0.patch.diff
in: master

126 files changed

addedtests/src/.outdated/addToContractAllowList.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/balance-transfer-contract/calls.wasmdiffbeforeafterboth

binary blob — no preview

addedtests/src/.outdated/balance-transfer-contract/metadata.jsondiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/admVsOwnerChanges.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/admVsOwnerData.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/admVsOwnerTake.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/adminDestroyCollection.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/adminLimitsOff.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/adminRightsOff.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/setSponsorNewOwner.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/sponsorPayments.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/tokenLimitsOff.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/collision-tests/turnsOffMinting.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/contracts.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/enableContractSponsoring.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/eth/scheduling.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/flipper/flipper.wasmdiffbeforeafterboth

binary blob — no preview

addedtests/src/.outdated/flipper/metadata.jsondiffbeforeafterboth

no changes

addedtests/src/.outdated/load_test_sc/loadtester.wasmdiffbeforeafterboth

binary blob — no preview

addedtests/src/.outdated/load_test_sc/metadata.jsondiffbeforeafterboth

no changes

addedtests/src/.outdated/overflow.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/removeFromContractAllowList.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/scheduler.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/setChainLimits.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/setContractSponsoringRateLimit.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/toggleContractAllowList.test.tsdiffbeforeafterboth

no changes

addedtests/src/.outdated/transfer_contract/metadata.jsondiffbeforeafterboth

no changes

addedtests/src/.outdated/transfer_contract/nft_transfer.wasmdiffbeforeafterboth

binary blob — no preview

addedtests/src/.outdated/xcmTransfer.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
110 const [alice, ...accounts] = await helper.arrange.createAccounts([10n, 0n, 0n, 0n, 0n, 0n, 0n, 0n], donor);110 const [alice, ...accounts] = await helper.arrange.createAccounts([10n, 0n, 0n, 0n, 0n, 0n, 0n, 0n], donor);
111 const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});111 const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});
112112
113 const chainAdminLimit = (helper.api!.consts.common.collectionAdminsLimit as any).toNumber();113 const chainAdminLimit = (helper.getApi().consts.common.collectionAdminsLimit as any).toNumber();
114 expect(chainAdminLimit).to.be.equal(5);114 expect(chainAdminLimit).to.be.equal(5);
115115
116 for (let i = 0; i < chainAdminLimit; i++) {116 for (let i = 0; i < chainAdminLimit; i++) {
deletedtests/src/addToContractAllowList.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/app-promotion.test.tsdiffbeforeafterboth
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {18import {itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip} from './util/playgrounds';
19 normalizeAccountId,
20 getModuleNames,
21 Pallets,
22} from './util/helpers';
23import {itSub, usingPlaygrounds} from './util/playgrounds';
24import {encodeAddress} from '@polkadot/util-crypto';19import {encodeAddress} from '@polkadot/util-crypto';
25import {stringToU8a} from '@polkadot/util';20import {stringToU8a} from '@polkadot/util';
26import {SponsoringMode} from './eth/util/helpers';
27import {DevUniqueHelper} from './util/playgrounds/unique.dev';21import {DevUniqueHelper} from './util/playgrounds/unique.dev';
28import {itEth, expect} from './eth/util/playgrounds';22import {itEth, expect, SponsoringMode} from './eth/util/playgrounds';
2923
30let alice: IKeyringPair;24let alice: IKeyringPair;
31let palletAdmin: IKeyringPair;25let palletAdmin: IKeyringPair;
42describe('App promotion', () => {36describe('App promotion', () => {
43 before(async function () {37 before(async function () {
44 await usingPlaygrounds(async (helper, privateKey) => {38 await usingPlaygrounds(async (helper, privateKey) => {
45 if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) this.skip();39 requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]);
46 alice = await privateKey({filename: __filename});40 alice = await privateKey({filename: __filename});
47 [palletAdmin] = await helper.arrange.createAccounts([100n], alice);41 [palletAdmin] = await helper.arrange.createAccounts([100n], alice);
48 await helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));42 const api = helper.getApi();
43 await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
49 nominal = helper.balance.getOneTokenNominal();44 nominal = helper.balance.getOneTokenNominal();
50 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 1000n * nominal);45 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 1000n * nominal);
51 await helper.balance.transferToSubstrate(alice, palletAddress, 1000n * nominal);46 await helper.balance.transferToSubstrate(alice, palletAddress, 1000n * nominal);
231 226
232 describe('admin adress', () => {227 describe('admin adress', () => {
233 itSub('can be set by sudo only', async ({helper}) => {228 itSub('can be set by sudo only', async ({helper}) => {
229 const api = helper.getApi();
234 const nonAdmin = accounts.pop()!;230 const nonAdmin = accounts.pop()!;
235 // nonAdmin can not set admin not from himself nor as a sudo231 // nonAdmin can not set admin not from himself nor as a sudo
236 await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected;232 await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected;
237 await expect(helper.signTransaction(nonAdmin, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected;233 await expect(helper.signTransaction(nonAdmin, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected;
238 234
239 // Alice can235 // Alice can
240 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled;236 await expect(helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled;
241 });237 });
242 238
243 itSub('can be any valid CrossAccountId', async ({helper}) => {239 itSub('can be any valid CrossAccountId', async ({helper}) => {
244 // We are not going to set an eth address as a sponsor,240 // We are not going to set an eth address as a sponsor,
245 // but we do want to check, it doesn't break anything;241 // but we do want to check, it doesn't break anything;
242 const api = helper.getApi();
246 const account = accounts.pop()!;243 const account = accounts.pop()!;
247 const ethAccount = helper.address.substrateToEth(account.address); 244 const ethAccount = helper.address.substrateToEth(account.address);
248 // Alice sets Ethereum address as a sudo. Then Substrate address back...245 // Alice sets Ethereum address as a sudo. Then Substrate address back...
249 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled;246 await expect(helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled;
250 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled;247 await expect(helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled;
251 248
252 // ...It doesn't break anything;249 // ...It doesn't break anything;
253 const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});250 const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
254 await expect(helper.signTransaction(account, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;251 await expect(helper.signTransaction(account, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
255 });252 });
256 253
257 itSub('can be reassigned', async ({helper}) => {254 itSub('can be reassigned', async ({helper}) => {
255 const api = helper.getApi();
258 const [oldAdmin, newAdmin, collectionOwner] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];256 const [oldAdmin, newAdmin, collectionOwner] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
259 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});257 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
260 258
261 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress(normalizeAccountId(oldAdmin))))).to.be.fulfilled;259 await expect(helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: oldAdmin.address})))).to.be.fulfilled;
262 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress(normalizeAccountId(newAdmin))))).to.be.fulfilled;260 await expect(helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: newAdmin.address})))).to.be.fulfilled;
263 await expect(helper.signTransaction(oldAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;261 await expect(helper.signTransaction(oldAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
264 262
265 await expect(helper.signTransaction(newAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;263 await expect(helper.signTransaction(newAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
266 });264 });
267 });265 });
268 266
269 describe('collection sponsoring', () => {267 describe('collection sponsoring', () => {
270 before(async function () {268 before(async function () {
271 await usingPlaygrounds(async (helper) => {269 await usingPlaygrounds(async (helper) => {
272 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address}));270 const api = helper.getApi();
271 const tx = api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address}));
273 await helper.signTransaction(alice, tx);272 await helper.signTransaction(alice, tx);
274 });273 });
275 });274 });
276 275
277 itSub('should actually sponsor transactions', async ({helper}) => {276 itSub('should actually sponsor transactions', async ({helper}) => {
277 const api = helper.getApi();
278 const [collectionOwner, tokenSender, receiver] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];278 const [collectionOwner, tokenSender, receiver] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
279 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'Name', description: 'Description', tokenPrefix: 'Prefix', limits: {sponsorTransferTimeout: 0}});279 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'Name', description: 'Description', tokenPrefix: 'Prefix', limits: {sponsorTransferTimeout: 0}});
280 const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address});280 const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address});
281 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId));281 await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
282 const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);282 const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);
283 283
284 await token.transfer(tokenSender, {Substrate: receiver.address});284 await token.transfer(tokenSender, {Substrate: receiver.address});
291 });291 });
292 292
293 itSub('can not be set by non admin', async ({helper}) => {293 itSub('can not be set by non admin', async ({helper}) => {
294 const api = helper.getApi();
294 const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];295 const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];
295 296
296 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});297 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
297 298
298 await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;299 await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
299 expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled');300 expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled');
300 });301 });
301 302
302 itSub('should set pallet address as confirmed admin', async ({helper}) => {303 itSub('should set pallet address as confirmed admin', async ({helper}) => {
304 const api = helper.getApi();
303 const [collectionOwner, oldSponsor] = [accounts.pop()!, accounts.pop()!];305 const [collectionOwner, oldSponsor] = [accounts.pop()!, accounts.pop()!];
304 306
305 // Can set sponsoring for collection without sponsor307 // Can set sponsoring for collection without sponsor
306 const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});308 const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});
307 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.fulfilled;309 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.fulfilled;
308 expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});310 expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
309 311
310 // Can set sponsoring for collection with unconfirmed sponsor312 // Can set sponsoring for collection with unconfirmed sponsor
311 const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});313 const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});
312 expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address});314 expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address});
313 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.fulfilled;315 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.fulfilled;
314 expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});316 expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
315 317
316 // Can set sponsoring for collection with confirmed sponsor318 // Can set sponsoring for collection with confirmed sponsor
317 const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});319 const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});
318 await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor);320 await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor);
319 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.fulfilled;321 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.fulfilled;
320 expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});322 expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
321 });323 });
322 324
323 itSub('can be overwritten by collection owner', async ({helper}) => { 325 itSub('can be overwritten by collection owner', async ({helper}) => {
326 const api = helper.getApi();
324 const [collectionOwner, newSponsor] = [accounts.pop()!, accounts.pop()!];327 const [collectionOwner, newSponsor] = [accounts.pop()!, accounts.pop()!];
325 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});328 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
326 const collectionId = collection.collectionId;329 const collectionId = collection.collectionId;
327 330
328 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionId))).to.be.fulfilled;331 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionId))).to.be.fulfilled;
329 332
330 // Collection limits still can be changed by the owner333 // Collection limits still can be changed by the owner
331 expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true;334 expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true;
338 });341 });
339 342
340 itSub('should not overwrite collection limits set by the owner earlier', async ({helper}) => {343 itSub('should not overwrite collection limits set by the owner earlier', async ({helper}) => {
344 const api = helper.getApi();
341 const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};345 const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};
342 const collectionWithLimits = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});346 const collectionWithLimits = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
343 347
344 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.fulfilled;348 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.fulfilled;
345 expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);349 expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);
346 });350 });
347 351
348 itSub('should reject transaction if collection doesn\'t exist', async ({helper}) => {352 itSub('should reject transaction if collection doesn\'t exist', async ({helper}) => {
353 const api = helper.getApi();
349 const collectionOwner = accounts.pop()!;354 const collectionOwner = accounts.pop()!;
350 355
351 // collection has never existed356 // collection has never existed
352 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(999999999))).to.be.rejected;357 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(999999999))).to.be.rejected;
353 // collection has been burned358 // collection has been burned
354 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});359 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
355 await collection.burn(collectionOwner);360 await collection.burn(collectionOwner);
356 361
357 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;362 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected;
358 });363 });
359 });364 });
360 365
361 describe('stopSponsoringCollection', () => {366 describe('stopSponsoringCollection', () => {
362 itSub('can not be called by non-admin', async ({helper}) => { 367 itSub('can not be called by non-admin', async ({helper}) => {
368 const api = helper.getApi();
363 const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];369 const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];
364 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});370 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
365 371
366 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;372 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
367 373
368 await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;374 await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;
369 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});375 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
370 });376 });
371 377
372 itSub('should set sponsoring as disabled', async ({helper}) => {378 itSub('should set sponsoring as disabled', async ({helper}) => {
379 const api = helper.getApi();
373 const [collectionOwner, recepient] = [accounts.pop()!, accounts.pop()!];380 const [collectionOwner, recepient] = [accounts.pop()!, accounts.pop()!];
374 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}});381 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}});
375 const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address});382 const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address});
376 383
377 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId));384 await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
378 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId));385 await helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId));
379 386
380 expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');387 expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');
381 388
387 });394 });
388 395
389 itSub('should not affect collection which is not sponsored by pallete', async ({helper}) => {396 itSub('should not affect collection which is not sponsored by pallete', async ({helper}) => {
397 const api = helper.getApi();
390 const collectionOwner = accounts.pop()!;398 const collectionOwner = accounts.pop()!;
391 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: collectionOwner.address});399 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: collectionOwner.address});
392 await collection.confirmSponsorship(collectionOwner);400 await collection.confirmSponsorship(collectionOwner);
393 401
394 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;402 await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected;
395 403
396 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address});404 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address});
397 });405 });
415 await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]);423 await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]);
416 424
417 expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; 425 expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
418 expect((await helper.api!.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner); 426 expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
419 expect((await helper.api!.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({427 expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
420 confirmed: {428 confirmed: {
421 substrate: palletAddress,429 substrate: palletAddress,
422 },430 },
431 await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;439 await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled;
432 440
433 // Contract is self sponsored441 // Contract is self sponsored
434 expect((await helper.api!.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.be.deep.equal({442 expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.be.deep.equal({
435 confirmed: {443 confirmed: {
436 ethereum: flipper.options.address.toLowerCase(),444 ethereum: flipper.options.address.toLowerCase(),
437 },445 },
462 await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;470 await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
463 471
464 expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; 472 expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true;
465 expect((await helper.api!.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner); 473 expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
466 expect((await helper.api!.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({474 expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
467 confirmed: {475 confirmed: {
468 ethereum: flipper.options.address.toLowerCase(),476 ethereum: flipper.options.address.toLowerCase(),
469 },477 },
482 await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission');490 await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission');
483 491
484 // contract still self-sponsored 492 // contract still self-sponsored
485 expect((await helper.api!.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({493 expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
486 confirmed: {494 confirmed: {
487 ethereum: flipper.options.address.toLowerCase(),495 ethereum: flipper.options.address.toLowerCase(),
488 },496 },
505 await helper.eth.transferBalanceFromSubstrate(alice, flipper.options.address, 1000n); // transferBalanceToEth(api, alice, flipper.options.address, 1000n);513 await helper.eth.transferBalanceFromSubstrate(alice, flipper.options.address, 1000n); // transferBalanceToEth(api, alice, flipper.options.address, 1000n);
506 514
507 // Set promotion to the Flipper515 // Set promotion to the Flipper
508 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorContract(flipper.options.address));516 await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true);
509 517
510 // Caller calls Flipper518 // Caller calls Flipper
511 await flipper.methods.flip().send({from: caller});519 await flipper.methods.flip().send({from: caller});
536 await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true);544 await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true);
537 545
538 expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false; 546 expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false;
539 expect((await helper.api!.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner); 547 expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner);
540 expect((await helper.api!.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({548 expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({
541 disabled: null,549 disabled: null,
542 });550 });
543 551
717// Wait while promotion period less than specified block, to avoid boundary cases725// Wait while promotion period less than specified block, to avoid boundary cases
718// 0 if this should be the beginning of the period.726// 0 if this should be the beginning of the period.
719async function waitPromotionPeriodDoesntEnd(helper: DevUniqueHelper, waitBlockLessThan = LOCKING_PERIOD / 3n) {727async function waitPromotionPeriodDoesntEnd(helper: DevUniqueHelper, waitBlockLessThan = LOCKING_PERIOD / 3n) {
720 const relayBlockNumber = (await helper.api!.query.parachainSystem.validationData()).value.relayParentNumber.toNumber(); // await helper.chain.getLatestBlockNumber();728 const relayBlockNumber = (await helper.callRpc('api.query.parachainSystem.validationData', [])).value.relayParentNumber.toNumber(); // await helper.chain.getLatestBlockNumber();
721 const currentPeriodBlock = BigInt(relayBlockNumber) % LOCKING_PERIOD;729 const currentPeriodBlock = BigInt(relayBlockNumber) % LOCKING_PERIOD;
722730
723 if (currentPeriodBlock > waitBlockLessThan) {731 if (currentPeriodBlock > waitBlockLessThan) {
modifiedtests/src/approve.test.tsdiffbeforeafterboth
60 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});60 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
61 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});61 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
62 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;62 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
63 await helper.signTransaction(alice, helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0));63 await helper.signTransaction(alice, helper.constructApiCall('api.tx.unique.approve', [{Substrate: bob.address}, collectionId, tokenId, 0]));
64 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;64 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
65 });65 });
6666
275 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});275 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
276 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});276 await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
277 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;277 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
278 await helper.signTransaction(alice, helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0));278 await helper.signTransaction(alice, helper.constructApiCall('api.tx.unique.approve', [{Substrate: bob.address}, collectionId, tokenId, 0]));
279 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;279 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
280 const transferTokenFromTx = async () => helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: bob.address});280 const transferTokenFromTx = async () => helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: bob.address});
281 await expect(transferTokenFromTx()).to.be.rejected;281 await expect(transferTokenFromTx()).to.be.rejected;
328 itSub('1 for NFT', async ({helper}) => {328 itSub('1 for NFT', async ({helper}) => {
329 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});329 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
330 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});330 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
331 const approveTx = async () => helper.signTransaction(bob, helper.api?.tx.unique.approve({Substrate: charlie.address}, collectionId, tokenId, 2));331 const approveTx = async () => helper.signTransaction(bob, helper.constructApiCall('api.tx.unique.approve', [{Substrate: charlie.address}, collectionId, tokenId, 2]));
332 await expect(approveTx()).to.be.rejected;332 await expect(approveTx()).to.be.rejected;
333 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;333 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;
334 });334 });
deletedtests/src/balance-transfer-contract/calls.wasmdiffbeforeafterboth

binary blob — no preview

deletedtests/src/balance-transfer-contract/metadata.jsondiffbeforeafterboth

no changes

modifiedtests/src/block-production.test.tsdiffbeforeafterboth
3737
38describe('Block Production smoke test', () => {38describe('Block Production smoke test', () => {
39 itSub('Node produces new blocks', async ({helper}) => {39 itSub('Node produces new blocks', async ({helper}) => {
40 const blocks: number[] | undefined = await getBlocks(helper.api!);40 const blocks: number[] | undefined = await getBlocks(helper.getApi());
41 expect(blocks[0]).to.be.lessThan(blocks[1]);41 expect(blocks[0]).to.be.lessThan(blocks[1]);
42 });42 });
43});43});
modifiedtests/src/calibrate.tsdiffbeforeafterboth
1import {ApiPromise} from '@polkadot/api';
2import {IKeyringPair} from '@polkadot/types/types';1import {IKeyringPair} from '@polkadot/types/types';
3import Web3 from 'web3';2
4import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, recordEthFee, usingWeb3} from './eth/util/helpers';3import {usingEthPlaygrounds, EthUniqueHelper} from './eth/util/playgrounds';
5import usingApi, {executeTransaction} from './substrate/substrate-api';4
6import {createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, UNIQUE, waitNewBlocks} from './util/helpers';
7import nonFungibleAbi from './eth/nonFungibleAbi.json';
85
9function linearRegression(points: { x: bigint, y: bigint }[]) {6function linearRegression(points: { x: bigint, y: bigint }[]) {
10 let sumxy = 0n;7 let sumxy = 0n;
59 }).reduce((a, b) => a + b, 0n) / BigInt(points.length));56 }).reduce((a, b) => a + b, 0n) / BigInt(points.length));
60}57}
6158
62async function calibrateWeightToFee(api: ApiPromise, privateKey: (account: string) => IKeyringPair) {59async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (account: string) => IKeyringPair) {
63 const alice = privateKey('//Alice');60 const alice = privateKey('//Alice');
64 const bob = privateKey('//Bob');61 const bob = privateKey('//Bob');
65 const dataPoints = [];62 const dataPoints = [];
6663
67 {64 {
68 const collectionId = await createCollectionExpectSuccess();65 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
69 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');66 const token = await collection.mintToken(alice, {Substrate: alice.address});
70 const aliceBalanceBefore = (await api.query.system.account(alice.address)).data.free.toBigInt();67 const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
71 await transferExpectSuccess(collectionId, tokenId, alice, bob, 1, 'NFT');68 await token.transfer(alice, {Substrate: bob.address});
72 const aliceBalanceAfter = (await api.query.system.account(alice.address)).data.free.toBigInt();69 const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
7370
74 console.log(`Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(UNIQUE)} UNQ`);71 console.log(`Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
75 }72 }
7673
74 const api = helper.getApi();
77 const defaultCoeff = (api.consts.configuration.defaultWeightToFeeCoefficient as any).toBigInt();75 const defaultCoeff = (api.consts.configuration.defaultWeightToFeeCoefficient as any).toBigInt();
78 for (let i = -5; i < 5; i++) {76 for (let i = -5; i < 5; i++) {
79 await executeTransaction(api, alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(defaultCoeff + defaultCoeff / 1000n * BigInt(i))));77 await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(defaultCoeff + defaultCoeff / 1000n * BigInt(i))));
8078
81 const coefficient = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt();79 const coefficient = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt();
82 const collectionId = await createCollectionExpectSuccess();80 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
83 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');81 const token = await collection.mintToken(alice, {Substrate: alice.address});
8482
85 const aliceBalanceBefore = (await api.query.system.account(alice.address)).data.free.toBigInt();83 const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
86 await transferExpectSuccess(collectionId, tokenId, alice, bob, 1, 'NFT');84 await token.transfer(alice, {Substrate: bob.address});
87 const aliceBalanceAfter = (await api.query.system.account(alice.address)).data.free.toBigInt();85 const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
8886
89 const transferPrice = aliceBalanceBefore - aliceBalanceAfter;87 const transferPrice = aliceBalanceBefore - aliceBalanceAfter;
9088
9492
95 // console.log(`Error: ${error(dataPoints, x => a*x+b)}`);93 // console.log(`Error: ${error(dataPoints, x => a*x+b)}`);
9694
97 const perfectValue = a * UNIQUE / 10n + b;95 const perfectValue = a * helper.balance.getOneTokenNominal() / 10n + b;
98 await executeTransaction(api, alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toString())));96 await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toString())));
9997
100 {98 {
101 const collectionId = await createCollectionExpectSuccess();99 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
102 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');100 const token = await collection.mintToken(alice, {Substrate: alice.address});
103 const aliceBalanceBefore = (await api.query.system.account(alice.address)).data.free.toBigInt();101 const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
104 await transferExpectSuccess(collectionId, tokenId, alice, bob, 1, 'NFT');102 await token.transfer(alice, {Substrate: bob.address});
105 const aliceBalanceAfter = (await api.query.system.account(alice.address)).data.free.toBigInt();103 const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
106104
107 console.log(`Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(UNIQUE)} UNQ`);105 console.log(`Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
108 }106 }
109}107}
110108
111async function calibrateMinGasPrice(api: ApiPromise, web3: Web3, privateKey: (account: string) => IKeyringPair) {109async function calibrateMinGasPrice(helper: EthUniqueHelper, privateKey: (account: string) => IKeyringPair) {
112 const alice = privateKey('//Alice');110 const alice = privateKey('//Alice');
113 const caller = await createEthAccountWithBalance(api, web3, privateKey);111 const caller = await helper.eth.createAccountWithBalance(alice);
114 const receiver = createEthAccount(web3);112 const receiver = helper.eth.createAccount();
115 const dataPoints = [];113 const dataPoints = [];
116114
117 {115 {
118 const collectionId = await createCollectionExpectSuccess();116 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
119 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Ethereum: caller});117 const token = await collection.mintToken(alice, {Ethereum: caller});
120118
121 const address = collectionIdToAddress(collectionId);119 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
122 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});120 const contract = helper.ethNativeContract.collection(address, 'nft', caller);
123121
124 const cost = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, tokenId).send(caller));122 const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
125123
126 console.log(`Original price: ${Number(cost) / Number(UNIQUE)} UNQ`);124 console.log(`Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
127 }125 }
128126
127 const api = helper.getApi();
129 const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt();128 const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt();
130 for (let i = -8; i < 8; i++) {129 for (let i = -8; i < 8; i++) {
131 const gasPrice = defaultCoeff + defaultCoeff / 100000n * BigInt(i);130 const gasPrice = defaultCoeff + defaultCoeff / 100000n * BigInt(i);
132 const gasPriceStr = '0x' + gasPrice.toString(16);131 const gasPriceStr = '0x' + gasPrice.toString(16);
133 await executeTransaction(api, alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(gasPrice)));132 await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(gasPrice)));
134133
135 const coefficient = (await api.query.configuration.minGasPriceOverride() as any).toBigInt();134 const coefficient = (await api.query.configuration.minGasPriceOverride() as any).toBigInt();
136 const collectionId = await createCollectionExpectSuccess();135 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
137 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Ethereum: caller});136 const token = await collection.mintToken(alice, {Ethereum: caller});
138137
139 const address = collectionIdToAddress(collectionId);138 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
140 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, gasPrice: gasPriceStr, ...GAS_ARGS});139 const contract = helper.ethNativeContract.collection(address, 'nft', caller);
141140
142 const transferPrice = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, tokenId).send(caller));141 const transferPrice = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS}));
143142
144 dataPoints.push({x: transferPrice, y: coefficient});143 dataPoints.push({x: transferPrice, y: coefficient});
145 }144 }
149 // console.log(`Error: ${error(dataPoints, x => a*x+b)}`);148 // console.log(`Error: ${error(dataPoints, x => a*x+b)}`);
150149
151 // * 0.15 = * 10000 / 66666150 // * 0.15 = * 10000 / 66666
152 const perfectValue = a * UNIQUE * 1000000n / 6666666n + b;151 const perfectValue = a * helper.balance.getOneTokenNominal() * 1000000n / 6666666n + b;
153 await executeTransaction(api, alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toString())));152 await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toString())));
154153
155 {154 {
156 const collectionId = await createCollectionExpectSuccess();155 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
157 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Ethereum: caller});156 const token = await collection.mintToken(alice, {Ethereum: caller});
158157
159 const address = collectionIdToAddress(collectionId);158 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
160 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});159 const contract = helper.ethNativeContract.collection(address, 'nft', caller);
161160
162 const cost = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, tokenId).send(caller));161 const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
163162
164 console.log(`Calibrated price: ${Number(cost) / Number(UNIQUE)} UNQ`);163 console.log(`Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
165 }164 }
166}165}
167166
168(async () => {167(async () => {
169 await usingApi(async (api, privateKey) => {168 await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
170 // Second run slightly reduces error sometimes, as price line is not actually straight, this is a curve169 // Second run slightly reduces error sometimes, as price line is not actually straight, this is a curve
171170
172 await calibrateWeightToFee(api, privateKey);171 await calibrateWeightToFee(helper, privateKey);
173 await calibrateWeightToFee(api, privateKey);172 await calibrateWeightToFee(helper, privateKey);
174173
175 await usingWeb3(async web3 => {174 await calibrateMinGasPrice(helper, privateKey);
176 await calibrateMinGasPrice(api, web3, privateKey);
177 await calibrateMinGasPrice(api, web3, privateKey);
178 });
179
180 await api.disconnect();175 await calibrateMinGasPrice(helper, privateKey);
181 });176 });
182})();177})();
183178
deletedtests/src/collision-tests/admVsOwnerChanges.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/admVsOwnerData.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/admVsOwnerTake.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/adminDestroyCollection.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/adminLimitsOff.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/adminRightsOff.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/setSponsorNewOwner.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/sponsorPayments.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/tokenLimitsOff.test.tsdiffbeforeafterboth

no changes

deletedtests/src/collision-tests/turnsOffMinting.test.tsdiffbeforeafterboth

no changes

deletedtests/src/contracts.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth
178 tokenPrefix: 'COL',178 tokenPrefix: 'COL',
179 }, 0);179 }, 0);
180180
181 const api = helper.api;
182 await helper.signTransaction(alice, api?.tx.unique.createMultipleItemsEx(collection.collectionId, {181 await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
183 Fungible: new Map([182 Fungible: new Map([
184 [JSON.stringify({Substrate: alice.address}), 50],183 [JSON.stringify({Substrate: alice.address}), 50],
185 [JSON.stringify({Substrate: bob.address}), 100],184 [JSON.stringify({Substrate: bob.address}), 100],
186 ]),185 ]),
187 }));186 }], true);
188187
189 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(50n);188 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(50n);
190 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(100n);189 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(100n);
200 ],199 ],
201 });200 });
202201
203 const api = helper.api;
204 await helper.signTransaction(alice, api?.tx.unique.createMultipleItemsEx(collection.collectionId, {202 await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx', [collection.collectionId, {
205 RefungibleMultipleOwners: {203 RefungibleMultipleOwners: {
206 users: new Map([204 users: new Map([
207 [JSON.stringify({Substrate: alice.address}), 1],205 [JSON.stringify({Substrate: alice.address}), 1],
211 {key: 'k', value: 'v'},209 {key: 'k', value: 'v'},
212 ],210 ],
213 },211 },
214 }));212 }], true);
215 const tokenId = await collection.getLastTokenId();213 const tokenId = await collection.getLastTokenId();
216 expect(tokenId).to.be.equal(1);214 expect(tokenId).to.be.equal(1);
217 expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);215 expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);
228 ],226 ],
229 });227 });
230
231 const api = helper.api;
232228
233 await helper.signTransaction(alice, api?.tx.unique.createMultipleItemsEx(collection.collectionId, {229 await helper.executeExtrinsic(alice, 'api.tx.unique.createMultipleItemsEx', [collection.collectionId, {
234 RefungibleMultipleItems: [230 RefungibleMultipleItems: [
235 {231 {
236 user: {Substrate: alice.address}, pieces: 1,232 user: {Substrate: alice.address}, pieces: 1,
245 ],241 ],
246 },242 },
247 ],243 ],
248 }));244 }], true);
249245
250 expect(await collection.getLastTokenId()).to.be.equal(2);246 expect(await collection.getLastTokenId()).to.be.equal(2);
251 expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);247 expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n);
modifiedtests/src/creditFeesToTreasury.test.tsdiffbeforeafterboth
29/*eslint no-async-promise-executor: "off"*/29/*eslint no-async-promise-executor: "off"*/
30function skipInflationBlock(api: ApiPromise): Promise<void> {30function skipInflationBlock(api: ApiPromise): Promise<void> {
31 const promise = new Promise<void>(async (resolve) => {31 const promise = new Promise<void>(async (resolve) => {
32 const blockInterval = (await api.consts.inflation.inflationBlockInterval).toNumber();32 const blockInterval = api.consts.inflation.inflationBlockInterval.toNumber();
33 const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => {33 const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => {
34 const currentBlock = head.number.toNumber();34 const currentBlock = head.number.toNumber();
35 if (currentBlock % blockInterval < blockInterval - 10) {35 if (currentBlock % blockInterval < blockInterval - 10) {
56 });56 });
5757
58 itSub('Total issuance does not change', async ({helper}) => {58 itSub('Total issuance does not change', async ({helper}) => {
59 const api = helper.api!;59 const api = helper.getApi();
60 await skipInflationBlock(api);60 await skipInflationBlock(api);
61 await helper.wait.newBlocks(1);61 await helper.wait.newBlocks(1);
6262
63 const totalBefore = (await api.query.balances.totalIssuance()).toBigInt();63 const totalBefore = (await helper.callRpc('api.query.balances.totalIssuance', [])).toBigInt();
6464
65 await helper.balance.transferToSubstrate(alice, bob.address, 1n);65 await helper.balance.transferToSubstrate(alice, bob.address, 1n);
6666
67 const totalAfter = (await api.query.balances.totalIssuance()).toBigInt();67 const totalAfter = (await helper.callRpc('api.query.balances.totalIssuance', [])).toBigInt();
6868
69 expect(totalAfter).to.be.equal(totalBefore);69 expect(totalAfter).to.be.equal(totalBefore);
70 });70 });
7171
72 itSub('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async ({helper}) => {72 itSub('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async ({helper}) => {
73 await skipInflationBlock(helper.api!);73 await skipInflationBlock(helper.getApi());
74 await helper.wait.newBlocks(1);74 await helper.wait.newBlocks(1);
7575
76 const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);76 const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
89 });89 });
9090
91 itSub('Treasury balance increased by failed tx fee', async ({helper}) => {91 itSub('Treasury balance increased by failed tx fee', async ({helper}) => {
92 const api = helper.api!;92 const api = helper.getApi();
93 await helper.wait.newBlocks(1);93 await helper.wait.newBlocks(1);
9494
95 const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);95 const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
107 });107 });
108108
109 itSub('NFT Transactions also send fees to Treasury', async ({helper}) => {109 itSub('NFT Transactions also send fees to Treasury', async ({helper}) => {
110 await skipInflationBlock(helper.api!);110 await skipInflationBlock(helper.getApi());
111 await helper.wait.newBlocks(1);111 await helper.wait.newBlocks(1);
112112
113 const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);113 const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY);
125125
126 itSub('Fees are sane', async ({helper}) => {126 itSub('Fees are sane', async ({helper}) => {
127 const unique = helper.balance.getOneTokenNominal();127 const unique = helper.balance.getOneTokenNominal();
128 await skipInflationBlock(helper.api!);128 await skipInflationBlock(helper.getApi());
129 await helper.wait.newBlocks(1);129 await helper.wait.newBlocks(1);
130130
131 const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);131 const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
140 });140 });
141141
142 itSub('NFT Transfer fee is close to 0.1 Unique', async ({helper}) => {142 itSub('NFT Transfer fee is close to 0.1 Unique', async ({helper}) => {
143 await skipInflationBlock(helper.api!);143 await skipInflationBlock(helper.getApi());
144 await helper.wait.newBlocks(1);144 await helper.wait.newBlocks(1);
145145
146 const collection = await helper.nft.mintCollection(alice, {146 const collection = await helper.nft.mintCollection(alice, {
addedtests/src/deprecated-helpers/contracthelpers.tsdiffbeforeafterboth

no changes

addedtests/src/deprecated-helpers/eth/helpers.d.tsdiffbeforeafterboth

no changes

addedtests/src/deprecated-helpers/eth/helpers.tsdiffbeforeafterboth

no changes

addedtests/src/deprecated-helpers/helpers.tsdiffbeforeafterboth

no changes

addedtests/src/deprecated-helpers/util.tsdiffbeforeafterboth

no changes

deletedtests/src/enableContractSponsoring.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {
18 ethBalanceViaSub,
19 GAS_ARGS,
20 recordEthFee,
21} from './util/helpers';
22import {Contract} from 'web3-eth-contract';17import {Contract} from 'web3-eth-contract';
2318
24import {IKeyringPair} from '@polkadot/types/types';19import {IKeyringPair} from '@polkadot/types/types';
37 const deployer = await helper.eth.createAccountWithBalance(donor);33 const deployer = await helper.eth.createAccountWithBalance(donor);
38 const flipper = await helper.eth.deployFlipper(deployer);34 const flipper = await helper.eth.deployFlipper(deployer);
3935
40 const cost = await recordEthFee(helper.api!, deployer, () => flipper.methods.flip().send({from: deployer}));36 const cost = await helper.eth.calculateFee({Ethereum: deployer}, () => flipper.methods.flip().send({from: deployer}));
41 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;37 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
42 });38 });
4339
44 itEth('Balance transfer fee is less than 0.2 UNQ', async ({helper}) => {40 itEth('Balance transfer fee is less than 0.2 UNQ', async ({helper}) => {
45 const userA = await helper.eth.createAccountWithBalance(donor);41 const userA = await helper.eth.createAccountWithBalance(donor);
46 const userB = helper.eth.createAccount();42 const userB = helper.eth.createAccount();
47 const cost = await recordEthFee(helper.api!, userA, () => helper.web3!.eth.sendTransaction({from: userA, to: userB, value: '1000000', ...GAS_ARGS}));43 const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({from: userA, to: userB, value: '1000000', gas: helper.eth.DEFAULT_GAS}));
48 const balanceB = await ethBalanceViaSub(helper.api!, userB);44 const balanceB = await helper.balance.getEthereum(userB);
49 expect(cost - balanceB < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;45 expect(cost - balanceB < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true;
50 });46 });
5147
60 const address = helper.ethAddress.fromCollectionId(collection.collectionId);56 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
61 const contract = helper.ethNativeContract.collection(address, 'nft', caller);57 const contract = helper.ethNativeContract.collection(address, 'nft', caller);
6258
63 const cost = await recordEthFee(helper.api!, caller, () => contract.methods.transfer(receiver, tokenId).send(caller));59 const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, tokenId).send(caller));
6460
65 const fee = Number(cost) / Number(helper.balance.getOneTokenNominal());61 const fee = Number(cost) / Number(helper.balance.getOneTokenNominal());
66 const expectedFee = 0.15;62 const expectedFee = 0.15;
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
1import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess, UNIQUE} from '../util/helpers';1import {IKeyringPair} from '@polkadot/types/types';
2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub} from './util/helpers';2import {usingPlaygrounds} from './../util/playgrounds/index';
3import nonFungibleAbi from './nonFungibleAbi.json';
4import {expect} from 'chai';3import {itEth, expect} from '../eth/util/playgrounds';
5import {evmToAddress} from '@polkadot/util-crypto';
64
7describe('evm collection sponsoring', () => {5describe('evm collection sponsoring', () => {
8 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {6 let donor: IKeyringPair;
7 let alice: IKeyringPair;
9 const alice = privateKeyWrapper('//Alice');8 let nominal: bigint;
109
11 const collection = await createCollectionExpectSuccess();10 before(async () => {
11 await usingPlaygrounds(async (helper, privateKey) => {
12 await setCollectionSponsorExpectSuccess(collection, alice.address);12 donor = privateKey('//Alice');
13 nominal = helper.balance.getOneTokenNominal();
13 await confirmSponsorshipExpectSuccess(collection);14 });
15 });
1416
15 const minter = createEthAccount(web3);17 beforeEach(async () => {
18 await usingPlaygrounds(async (helper) => {
16 expect(await web3.eth.getBalance(minter)).to.equal('0');19 [alice] = await helper.arrange.createAccounts([1000n], donor);
20 });
21 });
1722
18 const address = collectionIdToAddress(collection);23 itEth('sponsors mint transactions', async ({helper}) => {
19 const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});24 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}});
25 await collection.setSponsor(alice, alice.address);
26 await collection.confirmSponsorship(alice);
2027
21 await enablePublicMintingExpectSuccess(alice, collection);28 const minter = helper.eth.createAccount();
22 await addToAllowListExpectSuccess(alice, collection, {Ethereum: minter});29 expect(await helper.balance.getEthereum(minter)).to.equal(0n);
2330
31 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
32 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', minter);
33
34 await collection.addToAllowList(alice, {Ethereum: minter});
35
24 const nextTokenId = await contract.methods.nextTokenId().call();36 const nextTokenId = await contract.methods.nextTokenId().call();
25 expect(nextTokenId).to.equal('1');37 expect(nextTokenId).to.equal('1');
26 const result = await contract.methods.mint(minter, nextTokenId).send();38 const result = await contract.methods.mint(minter, nextTokenId).send();
27 const events = normalizeEvents(result.events);39 const events = helper.eth.normalizeEvents(result.events);
28 expect(events).to.be.deep.equal([40 expect(events).to.be.deep.equal([
29 {41 {
30 address,42 address: collectionAddress,
31 event: 'Transfer',43 event: 'Transfer',
32 args: {44 args: {
33 from: '0x0000000000000000000000000000000000000000',45 from: '0x0000000000000000000000000000000000000000',
59 // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);71 // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);
60 // });72 // });
6173
62 itWeb3('Remove sponsor', async ({api, web3, privateKeyWrapper}) => {74 itEth('Remove sponsor', async ({helper}) => {
63 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);75 const owner = await helper.eth.createAccountWithBalance(donor);
64 const collectionHelpers = evmCollectionHelpers(web3, owner);76 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
65 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * UNIQUE)});
66 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
67 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
68 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
6977
78 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
79 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
80 const sponsor = await helper.eth.createAccountWithBalance(donor);
81 const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner);
82
70 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;83 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
71 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});84 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
72 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;85 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
80 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');93 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');
81 });94 });
8295
83 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {96 itEth('Sponsoring collection from evm address via access list', async ({helper}) => {
84 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);97 const owner = await helper.eth.createAccountWithBalance(donor);
85 const collectionHelpers = evmCollectionHelpers(web3, owner);98 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
99
86 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * UNIQUE)});100 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
87 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);101 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
102 const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress);
103 const collection = helper.nft.getCollectionObject(collectionId);
88 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const sponsor = await helper.eth.createAccountWithBalance(donor);
89 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);105 const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner);
106
90 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});107 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
91 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;108 let collectionData = (await collection.getData())!;
92 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;
93 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;109 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
94 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));
95 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');110 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
96111
97 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});112 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
98 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;113 collectionData = (await collection.getData())!;
99 expect(collectionSub.sponsorship.isConfirmed).to.be.true;114 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
100 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));
101115
102 const user = createEthAccount(web3);116 const user = helper.eth.createAccount();
103 const nextTokenId = await collectionEvm.methods.nextTokenId().call();117 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
104 expect(nextTokenId).to.be.equal('1');118 expect(nextTokenId).to.be.equal('1');
105119
106 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();120 const oldPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
107 expect(oldPermissions.mintMode).to.be.false;121 expect(oldPermissions.mintMode).to.be.false;
108 expect(oldPermissions.access).to.be.equal('Normal');122 expect(oldPermissions.access).to.be.equal('Normal');
109123
110 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});124 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
111 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});125 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
112 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});126 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
113127
114 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();128 const newPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
115 expect(newPermissions.mintMode).to.be.true;129 expect(newPermissions.mintMode).to.be.true;
116 expect(newPermissions.access).to.be.equal('AllowList');130 expect(newPermissions.access).to.be.equal('AllowList');
117131
118 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);132 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
119 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);133 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
120134
121 {135 {
122 const nextTokenId = await collectionEvm.methods.nextTokenId().call();136 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
126 nextTokenId,140 nextTokenId,
127 'Test URI',141 'Test URI',
128 ).send({from: user});142 ).send({from: user});
129 const events = normalizeEvents(result.events);143 const events = helper.eth.normalizeEvents(result.events);
130144
131 expect(events).to.be.deep.equal([145 expect(events).to.be.deep.equal([
132 {146 {
140 },154 },
141 ]);155 ]);
142156
143 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);157 const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner));
144 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);158 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
145159
146 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');160 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
147 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);161 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
205 // }219 // }
206 // });220 // });
207221
208 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {222 itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => {
209 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);223 const owner = await helper.eth.createAccountWithBalance(donor);
210 const collectionHelpers = evmCollectionHelpers(web3, owner);224 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
225
211 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * UNIQUE)});226 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
212 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);227 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
228 const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress);
229 const collection = helper.nft.getCollectionObject(collectionId);
213 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);230 const sponsor = await helper.eth.createAccountWithBalance(donor);
214 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);231 const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner);
232
215 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();233 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();
216 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;234 let collectionData = (await collection.getData())!;
217 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;
218 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;235 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
219 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));
220 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');236 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
237
221 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);238 const sponsorCollection = helper.ethNativeContract.collection(collectionIdAddress, 'nft', sponsor);
222 await sponsorCollection.methods.confirmCollectionSponsorship().send();239 await sponsorCollection.methods.confirmCollectionSponsorship().send();
223 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;240 collectionData = (await collection.getData())!;
224 expect(collectionSub.sponsorship.isConfirmed).to.be.true;241 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
225 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));
226242
227 const user = createEthAccount(web3);243 const user = helper.eth.createAccount();
228 await collectionEvm.methods.addCollectionAdmin(user).send();244 await collectionEvm.methods.addCollectionAdmin(user).send();
229 245
230 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);246 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
231 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);247 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
232 248
233 249 const userCollectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', user);
234 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);
235 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();250 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();
236 expect(nextTokenId).to.be.equal('1');251 expect(nextTokenId).to.be.equal('1');
237 result = await userCollectionEvm.methods.mintWithTokenURI(252 result = await userCollectionEvm.methods.mintWithTokenURI(
240 'Test URI',255 'Test URI',
241 ).send();256 ).send();
242257
243 const events = normalizeEvents(result.events);258 const events = helper.eth.normalizeEvents(result.events);
244 const address = collectionIdToAddress(collectionId);259 const address = helper.ethAddress.fromCollectionId(collectionId);
245260
246 expect(events).to.be.deep.equal([261 expect(events).to.be.deep.equal([
247 {262 {
256 ]);271 ]);
257 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');272 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
258 273
259 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);274 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
260 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);275 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
261 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);276 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
262 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;277 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
263 });278 });
264});279});
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {IKeyringPair} from '@polkadot/types/types';
17import * as solc from 'solc';18import * as solc from 'solc';
18import {expect} from 'chai';19import {EthUniqueHelper} from './util/playgrounds/unique.dev';
20import {itEth, expect, SponsoringMode, usingEthPlaygrounds} from '../eth/util/playgrounds';
19import {expectSubstrateEventsAtBlock} from '../util/helpers';21import {usingPlaygrounds} from '../util/playgrounds';
20import Web3 from 'web3';22import {CompiledContract} from './util/playgrounds/types';
2123
22import {24describe('Sponsoring EVM contracts', () => {
23 contractHelpers,
24 createEthAccountWithBalance,
25 transferBalanceToEth,
26 deployFlipper,25 let donor: IKeyringPair;
27 itWeb3,
28 SponsoringMode,
29 createEthAccount,
30 ethBalanceViaSub,
31 normalizeEvents,
32 CompiledContract,
33 GAS_ARGS,
34 subToEth,
35} from './util/helpers';
36import {submitTransactionAsync} from '../substrate/substrate-api';
3726
38describe('Sponsoring EVM contracts', () => {27 before(async () => {
28 await usingPlaygrounds(async (_helper, privateKey) => {
39 itWeb3('Self sponsored can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {29 donor = privateKey('//Alice');
30 });
31 });
32
33 itEth('Self sponsored can be set by the address that deployed the contract', async ({helper, privateKey}) => {
40 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);34 const owner = await helper.eth.createAccountWithBalance(donor);
41 const flipper = await deployFlipper(web3, owner);35 const flipper = await helper.eth.deployFlipper(owner);
42 const helpers = contractHelpers(web3, owner);36 const helpers = helper.ethNativeContract.contractHelpers(owner);
37
43 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;38 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
44 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;39 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
45 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;40 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
46 });41 });
4742
48 itWeb3('Set self sponsored events', async ({api, web3, privateKeyWrapper}) => {43 itEth('Set self sponsored events', async ({helper}) => {
49 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);44 const owner = await helper.eth.createAccountWithBalance(donor);
50 const flipper = await deployFlipper(web3, owner);45 const flipper = await helper.eth.deployFlipper(owner);
51 const helpers = contractHelpers(web3, owner);46 const helpers = helper.ethNativeContract.contractHelpers(owner);
52 47
53 const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send();48 const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
54 // console.log(result);49 const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events);
55 const ethEvents = normalizeEvents(result.events);
56 expect(ethEvents).to.be.deep.equal([50 expect(ethEvents).to.be.deep.equal([
57 {51 {
58 address: flipper.options.address,52 address: flipper.options.address,
71 },65 },
72 },66 },
73 ]);67 ]);
74
75 await expectSubstrateEventsAtBlock(
76 api,
77 result.blockNumber,
78 'evmContractHelpers',
79 ['ContractSponsorSet','ContractSponsorshipConfirmed'],
80 );
81 });68 });
8269
83 itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {70 itEth('Self sponsored can not be set by the address that did not deployed the contract', async ({helper}) => {
84 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);71 const owner = await helper.eth.createAccountWithBalance(donor);
85 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);72 const notOwner = await helper.eth.createAccountWithBalance(donor);
86 const flipper = await deployFlipper(web3, owner);73 const helpers = helper.ethNativeContract.contractHelpers(owner);
87 const helpers = contractHelpers(web3, owner);74 const flipper = await helper.eth.deployFlipper(owner);
75
88 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;76 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
89 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');77 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');
90 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;78 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
91 });79 });
9280
93 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {81 itEth('Sponsoring can be set by the address that has deployed the contract', async ({helper}) => {
94 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);82 const owner = await helper.eth.createAccountWithBalance(donor);
95 const flipper = await deployFlipper(web3, owner);83 const helpers = helper.ethNativeContract.contractHelpers(owner);
96 const helpers = contractHelpers(web3, owner);84 const flipper = await helper.eth.deployFlipper(owner);
85
97 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;86 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
98 await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected;87 await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected;
99 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;88 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
100 });89 });
10190
102 itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {91 itEth('Sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => {
103 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);92 const owner = await helper.eth.createAccountWithBalance(donor);
104 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);93 const notOwner = await helper.eth.createAccountWithBalance(donor);
105 const flipper = await deployFlipper(web3, owner);94 const helpers = helper.ethNativeContract.contractHelpers(owner);
106 const helpers = contractHelpers(web3, owner);95 const flipper = await helper.eth.deployFlipper(owner);
96
107 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;97 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
108 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');98 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');
109 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;99 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
110 });100 });
111 101
112 itWeb3('Sponsor can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {102 itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => {
113 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);103 const owner = await helper.eth.createAccountWithBalance(donor);
114 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const sponsor = await helper.eth.createAccountWithBalance(donor);
115 const flipper = await deployFlipper(web3, owner);105 const helpers = helper.ethNativeContract.contractHelpers(owner);
116 const helpers = contractHelpers(web3, owner);106 const flipper = await helper.eth.deployFlipper(owner);
107
117 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;108 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
118 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;109 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
119 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;110 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;
120 });111 });
121 112
122 itWeb3('Set sponsor event', async ({api, web3, privateKeyWrapper}) => {113 itEth('Set sponsor event', async ({helper}) => {
123 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);114 const owner = await helper.eth.createAccountWithBalance(donor);
124 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);115 const sponsor = await helper.eth.createAccountWithBalance(donor);
125 const flipper = await deployFlipper(web3, owner);116 const helpers = helper.ethNativeContract.contractHelpers(owner);
126 const helpers = contractHelpers(web3, owner);117 const flipper = await helper.eth.deployFlipper(owner);
127 118
128 const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();119 const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
129 const events = normalizeEvents(result.events);120 const events = helper.eth.normalizeEvents(result.events);
130 expect(events).to.be.deep.equal([121 expect(events).to.be.deep.equal([
131 {122 {
132 address: flipper.options.address,123 address: flipper.options.address,
137 },128 },
138 },129 },
139 ]);130 ]);
140
141 await expectSubstrateEventsAtBlock(
142 api,
143 result.blockNumber,
144 'evmContractHelpers',
145 ['ContractSponsorSet'],
146 );
147 });131 });
148 132
149 itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {133 itEth('Sponsor can not be set by the address that did not deployed the contract', async ({helper}) => {
150 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);134 const owner = await helper.eth.createAccountWithBalance(donor);
151 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);135 const sponsor = await helper.eth.createAccountWithBalance(donor);
152 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);136 const notOwner = await helper.eth.createAccountWithBalance(donor);
153 const flipper = await deployFlipper(web3, owner);137 const helpers = helper.ethNativeContract.contractHelpers(owner);
154 const helpers = contractHelpers(web3, owner);138 const flipper = await helper.eth.deployFlipper(owner);
139
155 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;140 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
156 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');141 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');
157 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;142 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;
158 });143 });
159144
160 itWeb3('Sponsorship can be confirmed by the address that pending as sponsor', async ({api, web3, privateKeyWrapper}) => {145 itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => {
161 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);146 const owner = await helper.eth.createAccountWithBalance(donor);
162 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);147 const sponsor = await helper.eth.createAccountWithBalance(donor);
163 const flipper = await deployFlipper(web3, owner);148 const helpers = helper.ethNativeContract.contractHelpers(owner);
164 const helpers = contractHelpers(web3, owner);149 const flipper = await helper.eth.deployFlipper(owner);
150
165 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;151 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
166 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;152 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
167 await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected;153 await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected;
168 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;154 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
169 });155 });
170156
171 itWeb3('Confirm sponsorship event', async ({api, web3, privateKeyWrapper}) => {157 itEth('Confirm sponsorship event', async ({helper}) => {
172 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);158 const owner = await helper.eth.createAccountWithBalance(donor);
173 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);159 const sponsor = await helper.eth.createAccountWithBalance(donor);
174 const flipper = await deployFlipper(web3, owner);160 const helpers = helper.ethNativeContract.contractHelpers(owner);
175 const helpers = contractHelpers(web3, owner);161 const flipper = await helper.eth.deployFlipper(owner);
162
176 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;163 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
177 const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});164 const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
178 const events = normalizeEvents(result.events);165 const events = helper.eth.normalizeEvents(result.events);
179 expect(events).to.be.deep.equal([166 expect(events).to.be.deep.equal([
180 {167 {
181 address: flipper.options.address,168 address: flipper.options.address,
186 },173 },
187 },174 },
188 ]);175 ]);
189
190 await expectSubstrateEventsAtBlock(
191 api,
192 result.blockNumber,
193 'evmContractHelpers',
194 ['ContractSponsorshipConfirmed'],
195 );
196 });176 });
197177
198 itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {178 itEth('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({helper}) => {
199 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);179 const owner = await helper.eth.createAccountWithBalance(donor);
200 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);180 const sponsor = await helper.eth.createAccountWithBalance(donor);
201 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);181 const notSponsor = await helper.eth.createAccountWithBalance(donor);
202 const flipper = await deployFlipper(web3, owner);182 const helpers = helper.ethNativeContract.contractHelpers(owner);
203 const helpers = contractHelpers(web3, owner);183 const flipper = await helper.eth.deployFlipper(owner);
184
204 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;185 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
205 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;186 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
206 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');187 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');
207 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;188 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
208 });189 });
209190
210 itWeb3('Sponsorship can not be confirmed by the address that not set as sponsor', async ({api, web3, privateKeyWrapper}) => {191 itEth('Sponsorship can not be confirmed by the address that not set as sponsor', async ({helper}) => {
211 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);192 const owner = await helper.eth.createAccountWithBalance(donor);
212 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);193 const notSponsor = await helper.eth.createAccountWithBalance(donor);
213 const flipper = await deployFlipper(web3, owner);194 const helpers = helper.ethNativeContract.contractHelpers(owner);
214 const helpers = contractHelpers(web3, owner);195 const flipper = await helper.eth.deployFlipper(owner);
196
215 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;197 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
216 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');198 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');
217 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;199 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
218 });200 });
219201
220 itWeb3('Get self sponsored sponsor', async ({api, web3, privateKeyWrapper}) => {202 itEth('Get self sponsored sponsor', async ({helper}) => {
221 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);203 const owner = await helper.eth.createAccountWithBalance(donor);
222 const flipper = await deployFlipper(web3, owner);204 const helpers = helper.ethNativeContract.contractHelpers(owner);
223 const helpers = contractHelpers(web3, owner);205 const flipper = await helper.eth.deployFlipper(owner);
206
224 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();207 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
225 208
229 expect(result[1]).to.be.eq('0');212 expect(result[1]).to.be.eq('0');
230 });213 });
231214
232 itWeb3('Get confirmed sponsor', async ({api, web3, privateKeyWrapper}) => {215 itEth('Get confirmed sponsor', async ({helper}) => {
233 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);216 const owner = await helper.eth.createAccountWithBalance(donor);
234 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);217 const sponsor = await helper.eth.createAccountWithBalance(donor);
235 const flipper = await deployFlipper(web3, owner);218 const helpers = helper.ethNativeContract.contractHelpers(owner);
236 const helpers = contractHelpers(web3, owner);219 const flipper = await helper.eth.deployFlipper(owner);
220
237 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();221 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
238 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});222 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
243 expect(result[1]).to.be.eq('0');227 expect(result[1]).to.be.eq('0');
244 });228 });
245229
246 itWeb3('Sponsor can be removed by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {230 itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => {
247 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);231 const owner = await helper.eth.createAccountWithBalance(donor);
248 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);232 const sponsor = await helper.eth.createAccountWithBalance(donor);
249 const flipper = await deployFlipper(web3, owner);233 const helpers = helper.ethNativeContract.contractHelpers(owner);
250 const helpers = contractHelpers(web3, owner);234 const flipper = await helper.eth.deployFlipper(owner);
251235
252 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;236 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
253 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();237 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
258 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;242 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
259 });243 });
260244
261 itWeb3('Remove sponsor event', async ({api, web3, privateKeyWrapper}) => {245 itEth('Remove sponsor event', async ({helper}) => {
262 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);246 const owner = await helper.eth.createAccountWithBalance(donor);
263 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);247 const sponsor = await helper.eth.createAccountWithBalance(donor);
264 const flipper = await deployFlipper(web3, owner);248 const helpers = helper.ethNativeContract.contractHelpers(owner);
265 const helpers = contractHelpers(web3, owner);249 const flipper = await helper.eth.deployFlipper(owner);
266250
267 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();251 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
268 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});252 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
269 253
270 const result = await helpers.methods.removeSponsor(flipper.options.address).send();254 const result = await helpers.methods.removeSponsor(flipper.options.address).send();
271 const events = normalizeEvents(result.events);255 const events = helper.eth.normalizeEvents(result.events);
272 expect(events).to.be.deep.equal([256 expect(events).to.be.deep.equal([
273 {257 {
274 address: flipper.options.address,258 address: flipper.options.address,
278 },262 },
279 },263 },
280 ]);264 ]);
281
282 await expectSubstrateEventsAtBlock(
283 api,
284 result.blockNumber,
285 'evmContractHelpers',
286 ['ContractSponsorRemoved'],
287 );
288 });265 });
289266
290 itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {267 itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => {
291 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);268 const owner = await helper.eth.createAccountWithBalance(donor);
292 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);269 const notOwner = await helper.eth.createAccountWithBalance(donor);
293 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);270 const sponsor = await helper.eth.createAccountWithBalance(donor);
294 const flipper = await deployFlipper(web3, owner);271 const helpers = helper.ethNativeContract.contractHelpers(owner);
295 const helpers = contractHelpers(web3, owner);272 const flipper = await helper.eth.deployFlipper(owner);
296273
297 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;274 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
298 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();275 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
303 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;280 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
304 });281 });
305282
306 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {283 itEth('In generous mode, non-allowlisted user transaction will be sponsored', async ({helper}) => {
307 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);284 const owner = await helper.eth.createAccountWithBalance(donor);
285 const sponsor = await helper.eth.createAccountWithBalance(donor);
308 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);286 const caller = await helper.eth.createAccountWithBalance(donor);
287 const helpers = helper.ethNativeContract.contractHelpers(owner);
309 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);288 const flipper = await helper.eth.deployFlipper(owner);
310289
311 const flipper = await deployFlipper(web3, owner);
312
313 const helpers = contractHelpers(web3, owner);
314
315 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();290 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
316 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});291 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
317292
318 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});293 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
319 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});294 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
320295
321 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);296 const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
322 const callerBalanceBefore = await ethBalanceViaSub(api, caller);297 const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
323298
324 await flipper.methods.flip().send({from: caller});299 await flipper.methods.flip().send({from: caller});
325 expect(await flipper.methods.getValue().call()).to.be.true;300 expect(await flipper.methods.getValue().call()).to.be.true;
326301
327 // Balance should be taken from sponsor instead of caller302 // Balance should be taken from sponsor instead of caller
328 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);303 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
329 const callerBalanceAfter = await ethBalanceViaSub(api, caller);304 const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
330 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;305 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
331 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);306 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);
332 });307 });
333308
334 itWeb3('In generous mode, non-allowlisted user transaction will be self sponsored', async ({api, web3, privateKeyWrapper}) => {309 itEth('In generous mode, non-allowlisted user transaction will be self sponsored', async ({helper}) => {
335 const alice = privateKeyWrapper('//Alice');310 const owner = await helper.eth.createAccountWithBalance(donor);
311 const caller = await helper.eth.createAccountWithBalance(donor);
312 const helpers = helper.ethNativeContract.contractHelpers(owner);
313 const flipper = await helper.eth.deployFlipper(owner);
336314
337 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
338 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
339
340 const flipper = await deployFlipper(web3, owner);
341
342 const helpers = contractHelpers(web3, owner);
343
344 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();315 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
345316
346 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});317 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
347 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});318 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
348319
349 await transferBalanceToEth(api, alice, flipper.options.address);320 await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
350321
351 const contractBalanceBefore = await ethBalanceViaSub(api, flipper.options.address);322 const contractBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address));
352 const callerBalanceBefore = await ethBalanceViaSub(api, caller);323 const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
353324
354 await flipper.methods.flip().send({from: caller});325 await flipper.methods.flip().send({from: caller});
355 expect(await flipper.methods.getValue().call()).to.be.true;326 expect(await flipper.methods.getValue().call()).to.be.true;
356327
357 // Balance should be taken from sponsor instead of caller328 // Balance should be taken from sponsor instead of caller
358 const contractBalanceAfter = await ethBalanceViaSub(api, flipper.options.address);329 const contractBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address));
359 const callerBalanceAfter = await ethBalanceViaSub(api, caller);330 const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
360 expect(contractBalanceAfter < contractBalanceBefore).to.be.true;331 expect(contractBalanceAfter < contractBalanceBefore).to.be.true;
361 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);332 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);
362 });333 });
363334
364 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}) => {335 itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({helper}) => {
365 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);336 const owner = await helper.eth.createAccountWithBalance(donor);
366 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);337 const sponsor = await helper.eth.createAccountWithBalance(donor);
338 const caller = helper.eth.createAccount();
367 const caller = createEthAccount(web3);339 const helpers = helper.ethNativeContract.contractHelpers(owner);
340 const flipper = await helper.eth.deployFlipper(owner);
368341
369 const flipper = await deployFlipper(web3, owner);
370
371 const helpers = contractHelpers(web3, owner);
372 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});342 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
373 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});343 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
374344
378 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();348 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
379 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});349 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
380350
381 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);351 const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
382 expect(sponsorBalanceBefore).to.be.not.equal('0');352 expect(sponsorBalanceBefore).to.be.not.equal('0');
383353
384 await flipper.methods.flip().send({from: caller});354 await flipper.methods.flip().send({from: caller});
385 expect(await flipper.methods.getValue().call()).to.be.true;355 expect(await flipper.methods.getValue().call()).to.be.true;
386356
387 // Balance should be taken from flipper instead of caller357 // Balance should be taken from flipper instead of caller
388 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);358 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
389 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;359 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
390 });360 });
391361
392 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}) => {362 itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({helper}) => {
393 const alice = privateKeyWrapper('//Alice');363 const owner = await helper.eth.createAccountWithBalance(donor);
364 const caller = await helper.eth.createAccount();
365 const helpers = helper.ethNativeContract.contractHelpers(owner);
366 const flipper = await helper.eth.deployFlipper(owner);
394367
395 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
396 const caller = createEthAccount(web3);
397
398 const flipper = await deployFlipper(web3, owner);
399
400 const helpers = contractHelpers(web3, owner);
401
402 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});368 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
403 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});369 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
404370
405 await transferBalanceToEth(api, alice, flipper.options.address);371 await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);
406372
407 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);373 const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address);
408 expect(originalFlipperBalance).to.be.not.equal('0');374 expect(originalFlipperBalance).to.be.not.equal('0');
409375
410 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);376 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);
411 expect(await flipper.methods.getValue().call()).to.be.false;377 expect(await flipper.methods.getValue().call()).to.be.false;
412378
413 // Balance should be taken from flipper instead of caller379 // Balance should be taken from flipper instead of caller
414 const balanceAfter = await web3.eth.getBalance(flipper.options.address);380 // FIXME the comment is wrong! What check should be here?
381 const balanceAfter = await helper.balance.getEthereum(flipper.options.address);
415 expect(+balanceAfter).to.be.equals(+originalFlipperBalance);382 expect(balanceAfter).to.be.equals(originalFlipperBalance);
416 });383 });
417384
418 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}) => {385 itEth('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({helper}) => {
419 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);386 const owner = await helper.eth.createAccountWithBalance(donor);
387 const sponsor = await helper.eth.createAccountWithBalance(donor);
420 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);388 const caller = await helper.eth.createAccountWithBalance(donor);
389 const helpers = helper.ethNativeContract.contractHelpers(owner);
421 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);390 const flipper = await helper.eth.deployFlipper(owner);
422391
423 const flipper = await deployFlipper(web3, owner);
424
425 const helpers = contractHelpers(web3, owner);
426 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});392 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
427 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});393 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
428394
432 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();398 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
433 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});399 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
434400
435 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);401 const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
436 const callerBalanceBefore = await ethBalanceViaSub(api, caller);402 const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
437403
438 await flipper.methods.flip().send({from: caller});404 await flipper.methods.flip().send({from: caller});
439 expect(await flipper.methods.getValue().call()).to.be.true;405 expect(await flipper.methods.getValue().call()).to.be.true;
440406
441 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);407 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
442 const callerBalanceAfter = await ethBalanceViaSub(api, caller);408 const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));
443 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;409 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
444 expect(callerBalanceAfter).to.be.equals(callerBalanceBefore);410 expect(callerBalanceAfter).to.be.equals(callerBalanceBefore);
445 });411 });
446412
447 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}) => {413 itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => {
448 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);414 const owner = await helper.eth.createAccountWithBalance(donor);
449 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);415 const sponsor = await helper.eth.createAccountWithBalance(donor);
450 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);416 const caller = await helper.eth.createAccountWithBalance(donor);
451 const originalCallerBalance = await web3.eth.getBalance(caller);417 const helpers = helper.ethNativeContract.contractHelpers(owner);
452
453 const flipper = await deployFlipper(web3, owner);418 const flipper = await helper.eth.deployFlipper(owner);
454419
455 const helpers = contractHelpers(web3, owner);420 const originalCallerBalance = await helper.balance.getEthereum(caller);
456 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});421 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
457 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});422 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
458423
462 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();427 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
463 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});428 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
464429
465 const originalFlipperBalance = await web3.eth.getBalance(sponsor);430 const originalFlipperBalance = await helper.balance.getEthereum(sponsor);
466 expect(originalFlipperBalance).to.be.not.equal('0');431 expect(originalFlipperBalance).to.be.not.equal('0');
467432
468 await flipper.methods.flip().send({from: caller});433 await flipper.methods.flip().send({from: caller});
469 expect(await flipper.methods.getValue().call()).to.be.true;434 expect(await flipper.methods.getValue().call()).to.be.true;
470 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);435 expect(await helper.balance.getEthereum(caller)).to.be.equals(originalCallerBalance);
471436
472 const newFlipperBalance = await web3.eth.getBalance(sponsor);437 const newFlipperBalance = await helper.balance.getEthereum(sponsor);
473 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);438 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);
474439
475 await flipper.methods.flip().send({from: caller});440 await flipper.methods.flip().send({from: caller});
476 expect(await web3.eth.getBalance(sponsor)).to.be.equal(newFlipperBalance);441 expect(await helper.balance.getEthereum(sponsor)).to.be.equal(newFlipperBalance);
477 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);442 expect(await helper.balance.getEthereum(caller)).to.be.not.equals(originalCallerBalance);
478 });443 });
479444
480 // TODO: Find a way to calculate default rate limit445 // TODO: Find a way to calculate default rate limit
481 itWeb3('Default rate limit equals 7200', async ({api, web3, privateKeyWrapper}) => {446 itEth('Default rate limit equals 7200', async ({helper}) => {
482 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);447 const owner = await helper.eth.createAccountWithBalance(donor);
483 const flipper = await deployFlipper(web3, owner);448 const helpers = helper.ethNativeContract.contractHelpers(owner);
484 const helpers = contractHelpers(web3, owner);449 const flipper = await helper.eth.deployFlipper(owner);
450
485 expect(await helpers.methods.sponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');451 expect(await helpers.methods.sponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');
486 });452 });
487});453});
488454
489describe('Sponsoring Fee Limit', () => {455describe('Sponsoring Fee Limit', () => {
456 let donor: IKeyringPair;
457 let alice: IKeyringPair;
458 let DEFAULT_GAS: number;
490459
491 let testContract: CompiledContract;
492
493 function compileTestContract() {460 function compileTestContract() {
494 if (!testContract) {461 if (!testContract) {
495 const input = {462 const input = {
537 return testContract;504 return testContract;
538 }505 }
539 506
540 async function deployTestContract(web3: Web3, owner: string) {507 async function deployTestContract(helper: EthUniqueHelper, owner: string) {
508 const web3 = helper.getWeb3();
541 const compiled = compileTestContract();509 const compiled = compileTestContract();
542 const testContract = new web3.eth.Contract(compiled.abi, undefined, {510 const testContract = new web3.eth.Contract(compiled.abi, undefined, {
543 data: compiled.object,511 data: compiled.object,
544 from: owner,512 from: owner,
545 ...GAS_ARGS,513 gas: DEFAULT_GAS,
546 });514 });
547 return await testContract.deploy({data: compiled.object}).send({from: owner});515 return await testContract.deploy({data: compiled.object}).send({from: owner});
548 }516 }
549517
550 itWeb3('Default fee limit', async ({api, web3, privateKeyWrapper}) => {518 before(async () => {
519 await usingEthPlaygrounds(async (helper, privateKey) => {
520 donor = privateKey('//Alice');
521 DEFAULT_GAS = helper.eth.DEFAULT_GAS;
522 });
523 });
524
525 beforeEach(async () => {
551 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);526 await usingPlaygrounds(async (helper) => {
527 [alice] = await helper.arrange.createAccounts([1000n], donor);
528 });
552 const flipper = await deployFlipper(web3, owner);529 });
530
531 let testContract: CompiledContract;
532
533
534
535 itEth('Default fee limit', async ({helper}) => {
536 const owner = await helper.eth.createAccountWithBalance(donor);
553 const helpers = contractHelpers(web3, owner);537 const helpers = helper.ethNativeContract.contractHelpers(owner);
538 const flipper = await helper.eth.deployFlipper(owner);
539
554 expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equals('115792089237316195423570985008687907853269984665640564039457584007913129639935');540 expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equals('115792089237316195423570985008687907853269984665640564039457584007913129639935');
555 });541 });
556542
557 itWeb3('Set fee limit', async ({api, web3, privateKeyWrapper}) => {543 itEth('Set fee limit', async ({helper}) => {
558 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);544 const owner = await helper.eth.createAccountWithBalance(donor);
559 const flipper = await deployFlipper(web3, owner);545 const helpers = helper.ethNativeContract.contractHelpers(owner);
560 const helpers = contractHelpers(web3, owner);546 const flipper = await helper.eth.deployFlipper(owner);
547
561 await helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send();548 await helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send();
562 expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equals('100');549 expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equals('100');
563 });550 });
564551
565 itWeb3('Negative test - set fee limit by non-owner', async ({api, web3, privateKeyWrapper}) => {552 itEth('Negative test - set fee limit by non-owner', async ({helper}) => {
566 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);553 const owner = await helper.eth.createAccountWithBalance(donor);
567 const stranger = await createEthAccountWithBalance(api, web3, privateKeyWrapper);554 const stranger = await helper.eth.createAccountWithBalance(donor);
568 const flipper = await deployFlipper(web3, owner);555 const helpers = helper.ethNativeContract.contractHelpers(owner);
569 const helpers = contractHelpers(web3, owner);556 const flipper = await helper.eth.deployFlipper(owner);
557
570 await expect(helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send({from: stranger})).to.be.rejected;558 await expect(helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send({from: stranger})).to.be.rejected;
571 });559 });
572560
573 itWeb3('Negative test - check that eth transactions exceeding fee limit are not executed', async ({api, web3, privateKeyWrapper}) => {561 itEth('Negative test - check that eth transactions exceeding fee limit are not executed', async ({helper}) => {
574 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);562 const owner = await helper.eth.createAccountWithBalance(donor);
575 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);563 const sponsor = await helper.eth.createAccountWithBalance(donor);
576 const user = await createEthAccountWithBalance(api, web3, privateKeyWrapper);564 const user = await helper.eth.createAccountWithBalance(donor);
565 const helpers = helper.ethNativeContract.contractHelpers(owner);
577566
578 const testContract = await deployTestContract(web3, owner);567 const testContract = await deployTestContract(helper, owner);
579 const helpers = contractHelpers(web3, owner);
580 568
581 await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});569 await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});
582 await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});570 await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});
583 571
584 await helpers.methods.setSponsor(testContract.options.address, sponsor).send();572 await helpers.methods.setSponsor(testContract.options.address, sponsor).send();
585 await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});573 await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});
586574
587 const gasPrice = BigInt(await web3.eth.getGasPrice());575 const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
588576
589 await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();577 await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();
590578
591 const originalUserBalance = await web3.eth.getBalance(user);579 const originalUserBalance = await helper.balance.getEthereum(user);
592 await testContract.methods.test(100).send({from: user, gas: 2_000_000});580 await testContract.methods.test(100).send({from: user, gas: 2_000_000});
593 expect(await web3.eth.getBalance(user)).to.be.equal(originalUserBalance);581 expect(await helper.balance.getEthereum(user)).to.be.equal(originalUserBalance);
594582
595 await testContract.methods.test(100).send({from: user, gas: 2_100_000});583 await testContract.methods.test(100).send({from: user, gas: 2_100_000});
596 expect(await web3.eth.getBalance(user)).to.not.be.equal(originalUserBalance);584 expect(await helper.balance.getEthereum(user)).to.not.be.equal(originalUserBalance);
597 });585 });
598586
599 itWeb3('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({api, web3, privateKeyWrapper}) => {587 itEth('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({helper, privateKey}) => {
600 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);588 const owner = await helper.eth.createAccountWithBalance(donor);
601 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);589 const sponsor = await helper.eth.createAccountWithBalance(donor);
590 const helpers = helper.ethNativeContract.contractHelpers(owner);
602591
603 const testContract = await deployTestContract(web3, owner);592 const testContract = await deployTestContract(helper, owner);
604 const helpers = contractHelpers(web3, owner);
605 593
606 await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});594 await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner});
607 await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});595 await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner});
608 596
609 await helpers.methods.setSponsor(testContract.options.address, sponsor).send();597 await helpers.methods.setSponsor(testContract.options.address, sponsor).send();
610 await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});598 await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor});
611599
612 const gasPrice = BigInt(await web3.eth.getGasPrice());600 const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
613601
614 await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();602 await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send();
615603
616 const alice = privateKeyWrapper('//Alice');604 const originalAliceBalance = await helper.balance.getSubstrate(alice.address);
617 const originalAliceBalance = (await api.query.system.account(alice.address)).data.free.toBigInt();605
618
619 await submitTransactionAsync(606 await helper.eth.sendEVM(
620 alice,607 alice,
621 api.tx.evm.call(608 testContract.options.address,
622 subToEth(alice.address),
623 testContract.options.address,
624 testContract.methods.test(100).encodeABI(),609 testContract.methods.test(100).encodeABI(),
625 Uint8Array.from([]),610 '0',
626 2_000_000n,611 2_000_000,
627 gasPrice,
628 null,
629 null,
630 [],
631 ),
632 );612 );
633 expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance);613 // expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance);
614 expect(await helper.balance.getSubstrate(alice.address)).to.be.equal(originalAliceBalance);
634 615
635 await submitTransactionAsync(616 await helper.eth.sendEVM(
636 alice,617 alice,
637 api.tx.evm.call(618 testContract.options.address,
638 subToEth(alice.address),
639 testContract.options.address,
640 testContract.methods.test(100).encodeABI(),619 testContract.methods.test(100).encodeABI(),
641 Uint8Array.from([]),620 '0',
642 2_100_000n,621 2_100_000,
643 gasPrice,
644 null,
645 null,
646 [],
647 ),
648 );622 );
649 expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.not.be.equal(originalAliceBalance);623 expect(await helper.balance.getSubstrate(alice.address)).to.not.be.equal(originalAliceBalance);
650 });624 });
651});625});
652626
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
17import {evmToAddress} from '@polkadot/util-crypto';17import {evmToAddress} from '@polkadot/util-crypto';
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
19import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';19import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
20import {UNIQUE} from '../util/helpers';20
2121
22describe('Create NFT collection from EVM', () => {22describe('Create NFT collection from EVM', () => {
23 let donor: IKeyringPair;23 let donor: IKeyringPair;
6565
66 await collectionHelpers.methods66 await collectionHelpers.methods
67 .createNonfungibleCollection('A', 'A', 'A')67 .createNonfungibleCollection('A', 'A', 'A')
68 .send({value: Number(2n * UNIQUE)});68 .send({value: Number(2n * helper.balance.getOneTokenNominal())});
69 69
70 expect(await collectionHelpers.methods70 expect(await collectionHelpers.methods
71 .isCollectionExist(expectedCollectionAddress)71 .isCollectionExist(expectedCollectionAddress)
147147
148describe('(!negative tests!) Create NFT collection from EVM', () => {148describe('(!negative tests!) Create NFT collection from EVM', () => {
149 let donor: IKeyringPair;149 let donor: IKeyringPair;
150 let nominal: bigint;
150151
151 before(async function() {152 before(async function() {
152 await usingEthPlaygrounds(async (_helper, privateKey) => {153 await usingEthPlaygrounds(async (helper, privateKey) => {
153 donor = await privateKey({filename: __filename});154 donor = await privateKey({filename: __filename});
155 nominal = helper.balance.getOneTokenNominal();
154 });156 });
155 });157 });
156158
165167
166 await expect(collectionHelper.methods168 await expect(collectionHelper.methods
167 .createNonfungibleCollection(collectionName, description, tokenPrefix)169 .createNonfungibleCollection(collectionName, description, tokenPrefix)
168 .call({value: Number(2n * UNIQUE)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);170 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
169 171
170 }172 }
171 {173 {
175 const tokenPrefix = 'A';177 const tokenPrefix = 'A';
176 await expect(collectionHelper.methods178 await expect(collectionHelper.methods
177 .createNonfungibleCollection(collectionName, description, tokenPrefix)179 .createNonfungibleCollection(collectionName, description, tokenPrefix)
178 .call({value: Number(2n * UNIQUE)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);180 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
179 }181 }
180 {182 {
181 const MAX_TOKEN_PREFIX_LENGTH = 16;183 const MAX_TOKEN_PREFIX_LENGTH = 16;
184 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);186 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
185 await expect(collectionHelper.methods187 await expect(collectionHelper.methods
186 .createNonfungibleCollection(collectionName, description, tokenPrefix)188 .createNonfungibleCollection(collectionName, description, tokenPrefix)
187 .call({value: Number(2n * UNIQUE)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);189 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
188 }190 }
189 });191 });
190 192
193 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);195 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
194 await expect(collectionHelper.methods196 await expect(collectionHelper.methods
195 .createNonfungibleCollection('Peasantry', 'absolutely anything', 'CVE')197 .createNonfungibleCollection('Peasantry', 'absolutely anything', 'CVE')
196 .call({value: Number(1n * UNIQUE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');198 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
197 });199 });
198200
199 itEth('(!negative test!) Check owner', async ({helper}) => {201 itEth('(!negative test!) Check owner', async ({helper}) => {
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
19import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';19import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
20import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';20import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
21import {UNIQUE} from '../util/helpers';21
2222
23describe('Create RFT collection from EVM', () => {23describe('Create RFT collection from EVM', () => {
24 let donor: IKeyringPair;24 let donor: IKeyringPair;
6666
67 await collectionHelpers.methods67 await collectionHelpers.methods
68 .createRFTCollection('A', 'A', 'A')68 .createRFTCollection('A', 'A', 'A')
69 .send({value: Number(2n * UNIQUE)});69 .send({value: Number(2n * helper.balance.getOneTokenNominal())});
70 70
71 expect(await collectionHelpers.methods71 expect(await collectionHelpers.methods
72 .isCollectionExist(expectedCollectionAddress)72 .isCollectionExist(expectedCollectionAddress)
148148
149describe('(!negative tests!) Create RFT collection from EVM', () => {149describe('(!negative tests!) Create RFT collection from EVM', () => {
150 let donor: IKeyringPair;150 let donor: IKeyringPair;
151 let nominal: bigint;
151152
152 before(async function() {153 before(async function() {
153 await usingEthPlaygrounds(async (helper, privateKey) => {154 await usingEthPlaygrounds(async (helper, privateKey) => {
154 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);155 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
155 donor = await privateKey({filename: __filename});156 donor = await privateKey({filename: __filename});
157 nominal = helper.balance.getOneTokenNominal();
156 });158 });
157 });159 });
158160
167169
168 await expect(collectionHelper.methods170 await expect(collectionHelper.methods
169 .createRFTCollection(collectionName, description, tokenPrefix)171 .createRFTCollection(collectionName, description, tokenPrefix)
170 .call({value: Number(2n * UNIQUE)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);172 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);
171 }173 }
172 {174 {
173 const MAX_DESCRIPTION_LENGTH = 256;175 const MAX_DESCRIPTION_LENGTH = 256;
176 const tokenPrefix = 'A';178 const tokenPrefix = 'A';
177 await expect(collectionHelper.methods179 await expect(collectionHelper.methods
178 .createRFTCollection(collectionName, description, tokenPrefix)180 .createRFTCollection(collectionName, description, tokenPrefix)
179 .call({value: Number(2n * UNIQUE)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);181 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);
180 }182 }
181 {183 {
182 const MAX_TOKEN_PREFIX_LENGTH = 16;184 const MAX_TOKEN_PREFIX_LENGTH = 16;
185 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);187 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);
186 await expect(collectionHelper.methods188 await expect(collectionHelper.methods
187 .createRFTCollection(collectionName, description, tokenPrefix)189 .createRFTCollection(collectionName, description, tokenPrefix)
188 .call({value: Number(2n * UNIQUE)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);190 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);
189 }191 }
190 });192 });
191 193
194 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);196 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
195 await expect(collectionHelper.methods197 await expect(collectionHelper.methods
196 .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')198 .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')
197 .call({value: Number(1n * UNIQUE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');199 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
198 });200 });
199201
200 itEth('(!negative test!) Check owner', async ({helper}) => {202 itEth('(!negative test!) Check owner', async ({helper}) => {
modifiedtests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {usingPlaygrounds} from './../../util/playgrounds/index';
18import {IKeyringPair} from '@polkadot/types/types';
17import {readFile} from 'fs/promises';19import {readFile} from 'fs/promises';
18import {getBalanceSingle} from '../../substrate/get-balance';20import {itEth, expect, SponsoringMode} from '../util/playgrounds';
19import {
20 addToAllowListExpectSuccess,
21 confirmSponsorshipExpectSuccess,
22 createCollectionExpectSuccess,
23 createItemExpectSuccess,
24 getTokenOwner,
25 setCollectionLimitsExpectSuccess,
26 setCollectionSponsorExpectSuccess,
27 transferExpectSuccess,
28 transferFromExpectSuccess,
29 transferBalanceTo,
30} from '../../util/helpers';
31import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, SponsoringMode, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';
32import {evmToAddress} from '@polkadot/util-crypto';
33import nonFungibleAbi from '../nonFungibleAbi.json';
3421
35import {expect} from 'chai';22describe('Matcher contract usage', () => {
23 const PRICE = 2000n;
24 let donor: IKeyringPair;
25 let alice: IKeyringPair;
26 let aliceMirror: string;
27 let aliceDoubleMirror: string;
28 let seller: IKeyringPair;
29 let sellerMirror: string;
3630
37const PRICE = 2000n;31 before(async () => {
32 await usingPlaygrounds(async (_helper, privateKey) => {
33 donor = privateKey('//Alice');
34 });
35 });
3836
39describe('Matcher contract usage', () => {37 beforeEach(async () => {
40 itWeb3('With UNQ', async ({api, web3, privateKeyWrapper}) => {38 await usingPlaygrounds(async (helper, privateKey) => {
41 const alice = privateKeyWrapper('//Alice');39 [alice] = await helper.arrange.createAccounts([10000n], donor);
40 aliceMirror = helper.address.substrateToEth(alice.address).toLowerCase();
41 aliceDoubleMirror = helper.address.ethToSubstrate(aliceMirror);
42 seller = privateKey(`//Seller/${Date.now()}`);
42 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 sellerMirror = helper.address.substrateToEth(seller.address).toLowerCase();
44
45 await helper.balance.transferToSubstrate(donor, aliceDoubleMirror, 10_000_000_000_000_000_000n);
43 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);46 });
47 });
48
49 itEth('With UNQ', async ({helper}) => {
50 const web3 = helper.getWeb3();
51 const matcherOwner = await helper.eth.createAccountWithBalance(donor);
44 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {52 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {
45 from: matcherOwner,53 from: matcherOwner,
46 ...GAS_ARGS,54 gas: helper.eth.DEFAULT_GAS,
47 });55 });
48 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});56 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});
57
49 const helpers = contractHelpers(web3, matcherOwner);58 const sponsor = await helper.eth.createAccountWithBalance(donor);
59 const helpers = helper.ethNativeContract.contractHelpers(matcherOwner);
50 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});60 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
51 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});61 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
52 62
53 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});63 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});
54 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});64 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});
5565
56 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});66 const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: alice.address});
57 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});67 await collection.confirmSponsorship(alice);
68 await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});
58 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});69 const evmCollection = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
59 await setCollectionSponsorExpectSuccess(collectionId, alice.address);70 await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);
60 await transferBalanceToEth(api, alice, subToEth(alice.address));
61 await confirmSponsorshipExpectSuccess(collectionId);
6271
63 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});72 await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});
64 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));73 await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});
6574
66 const seller = privateKeyWrapper(`//Seller/${Date.now()}`);75 const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
67 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});
6876
69 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);
70
71 // To transfer item to matcher it first needs to be transfered to EVM account of bob
72 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});
73
74 // Token is owned by seller initially77 // Token is owned by seller initially
75 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});78 expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
7679
77 // Ask80 // Ask
78 {81 {
79 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));82 await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
80 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));83 await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
81 }84 }
8285
83 // Token is transferred to matcher86 // Token is transferred to matcher
84 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});87 expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
8588
86 // Buy89 // Buy
87 {90 {
88 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);91 const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);
89 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});92 await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());
90 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);93 expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);
91 }94 }
9295
93 // Token is transferred to evm account of alice96 // Token is transferred to evm account of alice
94 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});97 expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
9598
96 // Transfer token to substrate side of alice99 // Transfer token to substrate side of alice
97 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});100 await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
98101
99 // Token is transferred to substrate account of alice, seller received funds102 // Token is transferred to substrate account of alice, seller received funds
100 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});103 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
101 });104 });
102105
103
104 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {106 itEth('With escrow', async ({helper}) => {
105 const alice = privateKeyWrapper('//Alice');107 const web3 = helper.getWeb3();
106 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);108 const matcherOwner = await helper.eth.createAccountWithBalance(donor);
107 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
108 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
109 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {109 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {
110 from: matcherOwner,110 from: matcherOwner,
111 ...GAS_ARGS,111 gas: helper.eth.DEFAULT_GAS,
112 });112 });
113 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});113 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});
114
115 const sponsor = await helper.eth.createAccountWithBalance(donor);
116 const escrow = await helper.eth.createAccountWithBalance(donor);
114 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});117 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});
115 const helpers = contractHelpers(web3, matcherOwner);118 const helpers = helper.ethNativeContract.contractHelpers(matcherOwner);
116 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});119 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
117 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});120 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
118 121
119 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});122 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});
120 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});123 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});
121124
122 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});125 const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: alice.address});
123 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});126 await collection.confirmSponsorship(alice);
127 await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});
124 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});128 const evmCollection = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
125 await setCollectionSponsorExpectSuccess(collectionId, alice.address);129 await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);
126 await transferBalanceToEth(api, alice, subToEth(alice.address));
127 await confirmSponsorshipExpectSuccess(collectionId);
128130
129 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});
130 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));
131131
132 const seller = privateKeyWrapper(`//Seller/${Date.now()}`);132 await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});
133 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});
134133
135 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);134 await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});
136135
137 // To transfer item to matcher it first needs to be transfered to EVM account of bob136 const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
138 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});
139137
140 // Token is owned by seller initially138 // Token is owned by seller initially
141 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});139 expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
142140
143 // Ask141 // Ask
144 {142 {
145 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));143 await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
146 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));144 await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
147 }145 }
148146
149 // Token is transferred to matcher147 // Token is transferred to matcher
150 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});148 expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
151149
152 // Give buyer KSM150 // Give buyer KSM
153 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});151 await matcher.methods.depositKSM(PRICE, aliceMirror).send({from: escrow});
154152
155 // Buy153 // Buy
156 {154 {
157 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');155 expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal('0');
158 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());156 expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal(PRICE.toString());
159157
160 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));158 await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buyKSM(evmCollection.options.address, token.tokenId, aliceMirror, aliceMirror).encodeABI(), '0');
161159
162 // Price is removed from buyer balance, and added to seller160 // Price is removed from buyer balance, and added to seller
163 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');161 expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal('0');
164 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());162 expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal(PRICE.toString());
165 }163 }
166164
167 // Token is transferred to evm account of alice165 // Token is transferred to evm account of alice
168 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});166 expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
169167
170 // Transfer token to substrate side of alice168 // Transfer token to substrate side of alice
171 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});169 await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
172170
173 // Token is transferred to substrate account of alice, seller received funds171 // Token is transferred to substrate account of alice, seller received funds
174 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});172 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
175 });173 });
176174
177
178 itWeb3('Sell tokens from substrate user via EVM contract', async ({api, web3, privateKeyWrapper}) => {175 itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {
179 const alice = privateKeyWrapper('//Alice');176 const web3 = helper.getWeb3();
180 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);177 const matcherOwner = await helper.eth.createAccountWithBalance(donor);
181 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {178 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {
182 from: matcherOwner,179 from: matcherOwner,
183 ...GAS_ARGS,180 gas: helper.eth.DEFAULT_GAS,
184 });181 });
185 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});182 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});
186 await transferBalanceToEth(api, alice, matcher.options.address);
187183
188 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});184 await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);
189 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});
190 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});
191185
192 const seller = privateKeyWrapper(`//Seller/${Date.now()}`);186 const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}});
187 const evmCollection = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
188
193 await transferBalanceTo(api, alice, seller.address);189 await helper.balance.transferToSubstrate(donor, seller.address, 100_000_000_000_000_000_000n);
194 190
195 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);191 const token = await collection.mintToken(alice, {Ethereum: sellerMirror});
196
197 // To transfer item to matcher it first needs to be transfered to EVM account of bob
198 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});
199192
200 // Token is owned by seller initially193 // Token is owned by seller initially
201 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});194 expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});
202195
203 // Ask196 // Ask
204 {197 {
205 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));198 await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');
206 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));199 await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');
207 }200 }
208201
209 // Token is transferred to matcher202 // Token is transferred to matcher
210 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});203 expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});
211204
212 // Buy205 // Buy
213 {206 {
214 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);207 const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);
215 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});208 await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());
216 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);209 expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);
217 }210 }
218211
219 // Token is transferred to evm account of alice212 // Token is transferred to evm account of alice
220 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});213 expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});
221214
222 // Transfer token to substrate side of alice215 // Transfer token to substrate side of alice
223 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});216 await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});
224217
225 // Token is transferred to substrate account of alice, seller received funds218 // Token is transferred to substrate account of alice, seller received funds
226 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});219 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
227 });220 });
228});221});
229222
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
17import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';17import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
19import {Contract} from 'web3-eth-contract';19import {Contract} from 'web3-eth-contract';
20import {UNIQUE} from '../util/helpers';20
2121
22describe('NFT: Information getting', () => {22describe('NFT: Information getting', () => {
23 let donor: IKeyringPair;23 let donor: IKeyringPair;
84 const receiver = helper.eth.createAccount();84 const receiver = helper.eth.createAccount();
8585
86 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);86 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
87 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * UNIQUE)});87 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * helper.balance.getOneTokenNominal())});
88 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);88 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
89 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);89 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
90 90
modifiedtests/src/eth/proxy/fungibleProxy.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {GAS_ARGS, normalizeEvents} from '../util/helpers';
18import {expect} from 'chai';17import {expect} from 'chai';
19import {readFile} from 'fs/promises';18import {readFile} from 'fs/promises';
20import {IKeyringPair} from '@polkadot/types/types';19import {IKeyringPair} from '@polkadot/types/types';
26 const web3 = helper.getWeb3();25 const web3 = helper.getWeb3();
27 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueFungibleProxy.abi`)).toString()), undefined, {26 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueFungibleProxy.abi`)).toString()), undefined, {
28 from: owner,27 from: owner,
29 ...GAS_ARGS,28 gas: helper.eth.DEFAULT_GAS,
30 });29 });
31 const proxy = await proxyContract.deploy({data: (await readFile(`${__dirname}/UniqueFungibleProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});30 const proxy = await proxyContract.deploy({data: (await readFile(`${__dirname}/UniqueFungibleProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});
32 return proxy;31 return proxy;
9493
95 {94 {
96 const result = await contract.methods.approve(spender, 100).send({from: caller});95 const result = await contract.methods.approve(spender, 100).send({from: caller});
97 const events = normalizeEvents(result.events);96 const events = helper.eth.normalizeEvents(result.events);
9897
99 expect(events).to.be.deep.equal([98 expect(events).to.be.deep.equal([
100 {99 {
131130
132 {131 {
133 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: caller});132 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: caller});
134 const events = normalizeEvents(result.events);133 const events = helper.eth.normalizeEvents(result.events);
135 expect(events).to.be.deep.equal([134 expect(events).to.be.deep.equal([
136 {135 {
137 address,136 address,
177176
178 {177 {
179 const result = await contract.methods.transfer(receiver, 50).send({from: caller});178 const result = await contract.methods.transfer(receiver, 50).send({from: caller});
180 const events = normalizeEvents(result.events);179 const events = helper.eth.normalizeEvents(result.events);
181 expect(events).to.be.deep.equal([180 expect(events).to.be.deep.equal([
182 {181 {
183 address,182 address,
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {GAS_ARGS, itWeb3, normalizeEvents} from '../util/helpers';
18import {expect} from 'chai';
19import {readFile} from 'fs/promises';17import {readFile} from 'fs/promises';
20import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
21import {EthUniqueHelper, itEth, usingEthPlaygrounds} from '../util/playgrounds';19import {EthUniqueHelper, itEth, usingEthPlaygrounds, expect} from '../util/playgrounds';
20
2221
23async function proxyWrap(helper: EthUniqueHelper, wrapped: any, donor: IKeyringPair) {22async function proxyWrap(helper: EthUniqueHelper, wrapped: any, donor: IKeyringPair) {
24 // Proxy owner has no special privilegies, we don't need to reuse them23 // Proxy owner has no special privilegies, we don't need to reuse them
25 const owner = await helper.eth.createAccountWithBalance(donor);24 const owner = await helper.eth.createAccountWithBalance(donor);
26 const web3 = helper.getWeb3();25 const web3 = helper.getWeb3();
27 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueNFTProxy.abi`)).toString()), undefined, {26 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueNFTProxy.abi`)).toString()), undefined, {
28 from: owner,27 from: owner,
29 ...GAS_ARGS,28 gas: helper.eth.DEFAULT_GAS,
30 });29 });
31 const proxy = await proxyContract.deploy({data: (await readFile(`${__dirname}/UniqueNFTProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});30 const proxy = await proxyContract.deploy({data: (await readFile(`${__dirname}/UniqueNFTProxy.bin`)).toString(), arguments: [wrapped.options.address]}).send({from: owner});
32 return proxy;31 return proxy;
119 nextTokenId,118 nextTokenId,
120 'Test URI',119 'Test URI',
121 ).send({from: caller});120 ).send({from: caller});
122 const events = normalizeEvents(result.events);121 const events = helper.eth.normalizeEvents(result.events);
123 events[0].address = events[0].address.toLocaleLowerCase();122 events[0].address = events[0].address.toLocaleLowerCase();
124123
125 expect(events).to.be.deep.equal([124 expect(events).to.be.deep.equal([
139 });138 });
140139
141 //TODO: CORE-302 add eth methods140 //TODO: CORE-302 add eth methods
142 itWeb3.skip('Can perform mintBulk()', async () => {141 itEth.skip('Can perform mintBulk()', async ({helper}) => {
143 /*142 const collection = await helper.nft.mintCollection(donor, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
144 const collection = await createCollectionExpectSuccess({143
145 mode: {type: 'NFT'},144 const caller = await helper.eth.createAccountWithBalance(donor, 30n);
146 });145 const receiver = helper.eth.createAccount();
147 const alice = privateKeyWrapper('//Alice');146
148147 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
149 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);148 const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller);
150 const receiver = createEthAccount(web3);149 const contract = await proxyWrap(helper, evmCollection, donor);
151150 await collection.addAdmin(donor, {Ethereum: contract.options.address});
152 const address = collectionIdToAddress(collection);151
153 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);152 {
154 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: contract.options.address});153 const nextTokenId = await contract.methods.nextTokenId().call();
155 await submitTransactionAsync(alice, changeAdminTx);154 expect(nextTokenId).to.be.equal('1');
156155 const result = await contract.methods.mintBulkWithTokenURI(
157 {156 receiver,
158 const nextTokenId = await contract.methods.nextTokenId().call();157 [
159 expect(nextTokenId).to.be.equal('1');158 [nextTokenId, 'Test URI 0'],
160 const result = await contract.methods.mintBulkWithTokenURI(159 [+nextTokenId + 1, 'Test URI 1'],
161 receiver,160 [+nextTokenId + 2, 'Test URI 2'],
162 [161 ],
163 [nextTokenId, 'Test URI 0'],162 ).send({from: caller});
164 [+nextTokenId + 1, 'Test URI 1'],163 const events = helper.eth.normalizeEvents(result.events);
165 [+nextTokenId + 2, 'Test URI 2'],164
166 ],165 expect(events).to.be.deep.equal([
167 ).send({from: caller});166 {
168 const events = normalizeEvents(result.events);167 address,
169168 event: 'Transfer',
170 expect(events).to.be.deep.equal([169 args: {
171 {170 from: '0x0000000000000000000000000000000000000000',
172 address,171 to: receiver,
173 event: 'Transfer',172 tokenId: nextTokenId,
174 args: {173 },
175 from: '0x0000000000000000000000000000000000000000',174 },
176 to: receiver,175 {
177 tokenId: nextTokenId,176 address,
178 },177 event: 'Transfer',
179 },178 args: {
180 {179 from: '0x0000000000000000000000000000000000000000',
181 address,180 to: receiver,
182 event: 'Transfer',181 tokenId: String(+nextTokenId + 1),
183 args: {182 },
184 from: '0x0000000000000000000000000000000000000000',183 },
185 to: receiver,184 {
186 tokenId: String(+nextTokenId + 1),185 address,
187 },186 event: 'Transfer',
188 },187 args: {
189 {188 from: '0x0000000000000000000000000000000000000000',
190 address,189 to: receiver,
191 event: 'Transfer',190 tokenId: String(+nextTokenId + 2),
192 args: {191 },
193 from: '0x0000000000000000000000000000000000000000',192 },
194 to: receiver,193 ]);
195 tokenId: String(+nextTokenId + 2),194
196 },195 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
197 },196 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
198 ]);197 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
199198 }
200 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
201 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
202 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
203 }
204 */
205 });199 });
206200
207 itEth('Can perform burn()', async ({helper}) => {201 itEth('Can perform burn()', async ({helper}) => {
216210
217 {211 {
218 const result = await contract.methods.burn(tokenId).send({from: caller});212 const result = await contract.methods.burn(tokenId).send({from: caller});
219 const events = normalizeEvents(result.events);213 const events = helper.eth.normalizeEvents(result.events);
220214
221 expect(events).to.be.deep.equal([215 expect(events).to.be.deep.equal([
222 {216 {
243 const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});237 const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address});
244238
245 {239 {
246 const result = await contract.methods.approve(spender, tokenId).send({from: caller, ...GAS_ARGS});240 const result = await contract.methods.approve(spender, tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS});
247 const events = normalizeEvents(result.events);241 const events = helper.eth.normalizeEvents(result.events);
248242
249 expect(events).to.be.deep.equal([243 expect(events).to.be.deep.equal([
250 {244 {
276270
277 {271 {
278 const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: caller});272 const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: caller});
279 const events = normalizeEvents(result.events);273 const events = helper.eth.normalizeEvents(result.events);
280 expect(events).to.be.deep.equal([274 expect(events).to.be.deep.equal([
281 {275 {
282 address,276 address,
313307
314 {308 {
315 const result = await contract.methods.transfer(receiver, tokenId).send({from: caller});309 const result = await contract.methods.transfer(receiver, tokenId).send({from: caller});
316 const events = normalizeEvents(result.events);310 const events = helper.eth.normalizeEvents(result.events);
317 expect(events).to.be.deep.equal([311 expect(events).to.be.deep.equal([
318 {312 {
319 address,313 address,
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
18import {EthUniqueHelper, expect, itEth, usingEthPlaygrounds} from './util/playgrounds';18import {EthUniqueHelper, expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
19import {IKeyringPair} from '@polkadot/types/types';19import {IKeyringPair} from '@polkadot/types/types';
20import {Contract} from 'web3-eth-contract';20import {Contract} from 'web3-eth-contract';
21import {UNIQUE} from '../util/helpers';21
2222
23describe('Refungible token: Information getting', () => {23describe('Refungible token: Information getting', () => {
24 let donor: IKeyringPair;24 let donor: IKeyringPair;
81 const receiver = helper.eth.createAccount();81 const receiver = helper.eth.createAccount();
8282
83 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);83 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
84 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * UNIQUE)});84 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send({value: Number(2n * helper.balance.getOneTokenNominal())});
85 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);85 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
86 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);86 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
87 87
deletedtests/src/eth/scheduling.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/eth/sponsoring.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {expect} from 'chai';17import {IKeyringPair} from '@polkadot/types/types';
18import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode} from './util/helpers';18import {itEth, expect, SponsoringMode} from '../eth/util/playgrounds';
19import {usingPlaygrounds} from './../util/playgrounds/index';
1920
20describe('EVM sponsoring', () => {21describe('EVM sponsoring', () => {
22 let donor: IKeyringPair;
23
24 before(async () => {
25 await usingPlaygrounds(async (helper, privateKey) => {
26 donor = privateKey('//Alice');
27 });
28 });
29
21 itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3, privateKeyWrapper}) => {30 itEth('Fee is deducted from contract if sponsoring is enabled', async ({helper}) => {
22 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);31 const owner = await helper.eth.createAccountWithBalance(donor);
23 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);32 const sponsor = await helper.eth.createAccountWithBalance(donor);
24 const caller = createEthAccount(web3);33 const caller = helper.eth.createAccount();
25 const originalCallerBalance = await web3.eth.getBalance(caller);34 const originalCallerBalance = await helper.balance.getEthereum(caller);
35
26 expect(originalCallerBalance).to.be.equal('0');36 expect(originalCallerBalance).to.be.equal(0n);
2737
28 const flipper = await deployFlipper(web3, owner);38 const flipper = await helper.eth.deployFlipper(owner);
2939
30 const helpers = contractHelpers(web3, owner);40 const helpers = helper.ethNativeContract.contractHelpers(owner);
41
31 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});42 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
32 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});43 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
39 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});50 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
40 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;51 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
4152
42 const originalSponsorBalance = await web3.eth.getBalance(sponsor);53 const originalSponsorBalance = await helper.balance.getEthereum(sponsor);
43 expect(originalSponsorBalance).to.be.not.equal('0');54 expect(originalSponsorBalance).to.be.not.equal(0n);
4455
45 await flipper.methods.flip().send({from: caller});56 await flipper.methods.flip().send({from: caller});
46 expect(await flipper.methods.getValue().call()).to.be.true;57 expect(await flipper.methods.getValue().call()).to.be.true;
4758
48 // Balance should be taken from flipper instead of caller59 // Balance should be taken from flipper instead of caller
49 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);60 expect(await helper.balance.getEthereum(caller)).to.be.equal(originalCallerBalance);
50 expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance);61 expect(await helper.balance.getEthereum(sponsor)).to.be.not.equal(originalSponsorBalance);
51 });62 });
5263
53 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {64 itEth('...but this doesn\'t applies to payable value', async ({helper}) => {
54 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);65 const owner = await helper.eth.createAccountWithBalance(donor);
55 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);66 const sponsor = await helper.eth.createAccountWithBalance(donor);
56 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);67 const caller = await helper.eth.createAccountWithBalance(donor);
57 const originalCallerBalance = await web3.eth.getBalance(caller);68 const originalCallerBalance = await helper.balance.getEthereum(caller);
69
58 expect(originalCallerBalance).to.be.not.equal('0');70 expect(originalCallerBalance).to.be.not.equal(0n);
5971
60 const collector = await deployCollector(web3, owner);72 const collector = await helper.eth.deployCollectorContract(owner);
6173
62 const helpers = contractHelpers(web3, owner);74 const helpers = helper.ethNativeContract.contractHelpers(owner);
75
63 await helpers.methods.toggleAllowlist(collector.options.address, true).send({from: owner});76 await helpers.methods.toggleAllowlist(collector.options.address, true).send({from: owner});
64 await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner});77 await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner});
71 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});84 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});
72 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});85 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});
7386
74 const originalSponsorBalance = await web3.eth.getBalance(sponsor);87 const originalSponsorBalance = await helper.balance.getEthereum(sponsor);
75 expect(originalSponsorBalance).to.be.not.equal('0');88 expect(originalSponsorBalance).to.be.not.equal(0n);
7689
77 await collector.methods.giveMoney().send({from: caller, value: '10000'});90 await collector.methods.giveMoney().send({from: caller, value: '10000'});
7891
79 // Balance will be taken from both caller (value) and from collector (fee)92 // Balance will be taken from both caller (value) and from collector (fee)
80 expect(await web3.eth.getBalance(caller)).to.be.equals((BigInt(originalCallerBalance) - 10000n).toString());93 expect(await helper.balance.getEthereum(caller)).to.be.equals((originalCallerBalance - 10000n));
81 expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance);94 expect(await helper.balance.getEthereum(sponsor)).to.be.not.equals(originalSponsorBalance);
82 expect(await collector.methods.getCollected().call()).to.be.equal('10000');95 expect(await collector.methods.getCollected().call()).to.be.equal('10000');
83 });96 });
84});97});
modifiedtests/src/eth/tokenProperties.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {itEth, usingEthPlaygrounds, expect, cartesian} from './util/playgrounds';17import {itEth, usingEthPlaygrounds, expect} from './util/playgrounds';
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
1919
20describe('EVM token properties', () => {20describe('EVM token properties', () => {
4848
49 itEth('Can be set', async({helper}) => {49 itEth('Can be set', async({helper}) => {
50 const caller = await helper.eth.createAccountWithBalance(donor);50 const caller = await helper.eth.createAccountWithBalance(donor);
51 const collection = await helper.nft.mintCollection(alice);51 const collection = await helper.nft.mintCollection(alice, {
52 tokenPropertyPermissions: [{
53 key: 'testKey',
54 permission: {
55 collectionAdmin: true,
56 },
57 }],
58 });
52 const token = await collection.mintToken(alice);59 const token = await collection.mintToken(alice);
53
54 await collection.setTokenPropertyPermissions(alice, [{
55 key: 'testKey',
56 permission: {
57 collectionAdmin: true,
58 },
59 }]);
6060
61 await collection.addAdmin(alice, {Ethereum: caller});61 await collection.addAdmin(alice, {Ethereum: caller});
6262
7171
72 itEth('Can be deleted', async({helper}) => {72 itEth('Can be deleted', async({helper}) => {
73 const caller = await helper.eth.createAccountWithBalance(donor);73 const caller = await helper.eth.createAccountWithBalance(donor);
74 const collection = await helper.nft.mintCollection(alice);74 const collection = await helper.nft.mintCollection(alice, {
75 tokenPropertyPermissions: [{
76 key: 'testKey',
77 permission: {
78 mutable: true,
79 collectionAdmin: true,
80 },
81 }],
82 });
83
75 const token = await collection.mintToken(alice);84 const token = await collection.mintToken(alice);
76
77 await collection.setTokenPropertyPermissions(alice, [{
78 key: 'testKey',
79 permission: {
80 mutable: true,
81 collectionAdmin: true,
82 },
83 }]);
84 await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);85 await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);
8586
86 await collection.addAdmin(alice, {Ethereum: caller});87 await collection.addAdmin(alice, {Ethereum: caller});
9697
97 itEth('Can be read', async({helper}) => {98 itEth('Can be read', async({helper}) => {
98 const caller = helper.eth.createAccount();99 const caller = helper.eth.createAccount();
99 const collection = await helper.nft.mintCollection(alice);100 const collection = await helper.nft.mintCollection(alice, {
101 tokenPropertyPermissions: [{
102 key: 'testKey',
103 permission: {
104 collectionAdmin: true,
105 },
106 }],
107 });
108
100 const token = await collection.mintToken(alice);109 const token = await collection.mintToken(alice);
101
102 await collection.setTokenPropertyPermissions(alice, [{
103 key: 'testKey',
104 permission: {
105 collectionAdmin: true,
106 },
107 }]);
108 await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);110 await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);
109111
110 const address = helper.ethAddress.fromCollectionId(collection.collectionId);112 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
116});118});
119
120
121type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
122function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
123 if(args.length === 0) {
124 yield internalRest as any;
125 return;
126 }
127 for(const value of args[0]) {
128 yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
129 }
130}
117131
deletedtests/src/eth/util/helpers.d.tsdiffbeforeafterboth

no changes

deletedtests/src/eth/util/helpers.tsdiffbeforeafterboth

no changes

modifiedtests/src/eth/util/playgrounds/index.tsdiffbeforeafterboth
20chai.use(chaiLike);20chai.use(chaiLike);
21export const expect = chai.expect;21export const expect = chai.expect;
22
23export enum SponsoringMode {
24 Disabled = 0,
25 Allowlisted = 1,
26 Generous = 2,
27}
2228
23export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair>) => Promise<void>) => {29export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair>) => Promise<void>) => {
24 const silentConsole = new SilentConsole();30 const silentConsole = new SilentConsole();
48 }54 }
49 finally {55 finally {
50 await helper.disconnect();56 await helper.disconnect();
51 await helper.disconnectWeb3();
52 silentConsole.disable();57 silentConsole.disable();
53 }58 }
54};59};
77itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});82itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});
78itEth.ifWithPallets = itEthIfWithPallet;83itEth.ifWithPallets = itEthIfWithPallet;
79
80type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
81// I want a fancier api, not a memory efficiency
82export function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
83 if(args.length === 0) {
84 yield internalRest as any;
85 return;
86 }
87 for(const value of args[0]) {
88 yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
89 }
90}
9184
modifiedtests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth
8 object: string;8 object: string;
9}9}
10
11export type NormalizedEvent = {
12 address: string,
13 event: string,
14 args: { [key: string]: string }
15};
16
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
1818
19import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';19import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
2020
21import {ContractImports, CompiledContract} from './types';21import {ContractImports, CompiledContract, NormalizedEvent} from './types';
2222
23// Native contracts ABI23// Native contracts ABI
24import collectionHelpersAbi from '../../collectionHelpersAbi.json';24import collectionHelpersAbi from '../../collectionHelpersAbi.json';
27import refungibleAbi from '../../reFungibleAbi.json';27import refungibleAbi from '../../reFungibleAbi.json';
28import refungibleTokenAbi from '../../reFungibleTokenAbi.json';28import refungibleTokenAbi from '../../reFungibleTokenAbi.json';
29import contractHelpersAbi from './../contractHelpersAbi.json';29import contractHelpersAbi from './../contractHelpersAbi.json';
30import {TEthereumAccount} from '../../../util/playgrounds/types';30import {ICrossAccountId, TEthereumAccount} from '../../../util/playgrounds/types';
3131
32class EthGroupBase {32class EthGroupBase {
33 helper: EthUniqueHelper;33 helper: EthUniqueHelper;
253 return before - after;253 return before - after;
254 }254 }
255
256 normalizeEvents(events: any): NormalizedEvent[] {
257 const output = [];
258 for (const key of Object.keys(events)) {
259 if (key.match(/^[0-9]+$/)) {
260 output.push(events[key]);
261 } else if (Array.isArray(events[key])) {
262 output.push(...events[key]);
263 } else {
264 output.push(events[key]);
265 }
266 }
267 output.sort((a, b) => a.logIndex - b.logIndex);
268 return output.map(({address, event, returnValues}) => {
269 const args: { [key: string]: string } = {};
270 for (const key of Object.keys(returnValues)) {
271 if (!key.match(/^[0-9]+$/)) {
272 args[key] = returnValues[key];
273 }
274 }
275 return {
276 address,
277 event,
278 args,
279 };
280 });
281 }
282
283 async calculateFee(address: ICrossAccountId, code: () => Promise<any>): Promise<bigint> {
284 const wrappedCode = async () => {
285 await code();
286 // In dev mode, the transaction might not finish processing in time
287 await this.helper.wait.newBlocks(1);
288 };
289 return await this.helper.arrange.calculcateFee(address, wrappedCode);
290 }
255} 291}
256292
257class EthAddressGroup extends EthGroupBase {293class EthAddressGroup extends EthGroupBase {
285 }321 }
286} 322}
287 323
324export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;
288325
289export class EthUniqueHelper extends DevUniqueHelper {326export class EthUniqueHelper extends DevUniqueHelper {
290 web3: Web3 | null = null;327 web3: Web3 | null = null;
295 ethNativeContract: NativeContractGroup;332 ethNativeContract: NativeContractGroup;
296 ethContract: ContractGroup;333 ethContract: ContractGroup;
297334
298 constructor(logger: { log: (msg: any, level: any) => void, level: any }) {335 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
336 options.helperBase = options.helperBase ?? EthUniqueHelper;
337
299 super(logger);338 super(logger, options);
300 this.eth = new EthGroup(this);339 this.eth = new EthGroup(this);
301 this.ethAddress = new EthAddressGroup(this);340 this.ethAddress = new EthAddressGroup(this);
302 this.ethNativeContract = new NativeContractGroup(this);341 this.ethNativeContract = new NativeContractGroup(this);
314 this.web3 = new Web3(this.web3Provider);353 this.web3 = new Web3(this.web3Provider);
315 }354 }
316355
317 async disconnectWeb3() {356 async disconnect() {
318 if(this.web3 === null) return;357 if(this.web3 === null) return;
319 this.web3Provider?.connection.close();358 this.web3Provider?.connection.close();
359
320 this.web3 = null;360 await super.disconnect();
321 }361 }
362
363 clearApi() {
364 this.web3 = null;
365 }
366
367 clone(helperCls: EthUniqueHelperConstructor, options?: { [key: string]: any; }): EthUniqueHelper {
368 const newHelper = super.clone(helperCls, options) as EthUniqueHelper;
369 newHelper.web3 = this.web3;
370 newHelper.web3Provider = this.web3Provider;
371
372 return newHelper;
373 }
322}374}
323 375
deletedtests/src/flipper/flipper.wasmdiffbeforeafterboth

binary blob — no preview

deletedtests/src/flipper/metadata.jsondiffbeforeafterboth

no changes

modifiedtests/src/inflation.test.tsdiffbeforeafterboth
40 const tx = helper.constructApiCall('api.tx.inflation.startInflation', [1]);40 const tx = helper.constructApiCall('api.tx.inflation.startInflation', [1]);
41 await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [tx])).to.not.be.rejected;41 await expect(helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [tx])).to.not.be.rejected;
4242
43 const blockInterval = (helper.api!.consts.inflation.inflationBlockInterval as any).toBigInt();43 const blockInterval = (helper.getApi().consts.inflation.inflationBlockInterval as any).toBigInt();
44 const totalIssuanceStart = ((await helper.api!.query.inflation.startingYearTotalIssuance()) as any).toBigInt();44 const totalIssuanceStart = ((await helper.callRpc('api.query.inflation.startingYearTotalIssuance', [])) as any).toBigInt();
45 const blockInflation = (await helper.api!.query.inflation.blockInflation() as any).toBigInt();45 const blockInflation = (await helper.callRpc('api.query.inflation.blockInflation', []) as any).toBigInt();
4646
47 const YEAR = 5259600n; // 6-second block. Blocks in one year47 const YEAR = 5259600n; // 6-second block. Blocks in one year
48 // const YEAR = 2629800n; // 12-second block. Blocks in one year48 // const YEAR = 2629800n; // 12-second block. Blocks in one year
deletedtests/src/load_test_sc/loadtester.wasmdiffbeforeafterboth

binary blob — no preview

deletedtests/src/load_test_sc/metadata.jsondiffbeforeafterboth

no changes

deletedtests/src/nesting/migration-check.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
276 276
277 itSub('Reads access rights to properties of a collection', async ({helper}) => {277 itSub('Reads access rights to properties of a collection', async ({helper}) => {
278 const collection = await helper.nft.mintCollection(alice);278 const collection = await helper.nft.mintCollection(alice);
279 const propertyRights = (await helper.api!.query.common.collectionPropertyPermissions(collection.collectionId)).toJSON();279 const propertyRights = (await helper.callRpc('api.query.common.collectionPropertyPermissions', [collection.collectionId])).toJSON();
280 expect(propertyRights).to.be.empty;280 expect(propertyRights).to.be.empty;
281 });281 });
282 282
817 ).to.be.fulfilled;817 ).to.be.fulfilled;
818 }818 }
819819
820 const originalSpace = await getConsumedSpace(token.collection.helper.api, token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); 820 const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
821 return originalSpace;821 return originalSpace;
822 }822 }
823823
840 ).to.be.rejectedWith(/common\.NoPermission/);840 ).to.be.rejectedWith(/common\.NoPermission/);
841 }841 }
842842
843 const consumedSpace = await getConsumedSpace(token.collection.helper.api, token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); 843 const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
844 expect(consumedSpace).to.be.equal(originalSpace);844 expect(consumedSpace).to.be.equal(originalSpace);
845 }845 }
846846
875 ).to.be.rejectedWith(/common\.NoPermission/);875 ).to.be.rejectedWith(/common\.NoPermission/);
876 }876 }
877 877
878 const consumedSpace = await getConsumedSpace(token.collection.helper.api, token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); 878 const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
879 expect(consumedSpace).to.be.equal(originalSpace);879 expect(consumedSpace).to.be.equal(originalSpace);
880 }880 }
881881
911911
912 expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty;912 expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty;
913 913
914 const consumedSpace = await getConsumedSpace(token.collection.helper.api, token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); 914 const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
915 expect(consumedSpace).to.be.equal(originalSpace);915 expect(consumedSpace).to.be.equal(originalSpace);
916 }916 }
917917
951 ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);951 ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
952 952
953 expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty;953 expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty;
954 const consumedSpace = await getConsumedSpace(token.collection.helper.api, token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); 954 const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
955 expect(consumedSpace).to.be.equal(originalSpace);955 expect(consumedSpace).to.be.equal(originalSpace);
956 }956 }
957957
deletedtests/src/overflow.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
59describe('Pallet presence', () => {59describe('Pallet presence', () => {
60 before(async () => {60 before(async () => {
61 await usingPlaygrounds(async helper => {61 await usingPlaygrounds(async helper => {
62 const chain = await helper.api!.rpc.system.chain();62 const chain = await helper.callRpc('api.rpc.system.chain', []);
6363
64 const refungible = 'refungible';64 const refungible = 'refungible';
65 const scheduler = 'scheduler';65 const scheduler = 'scheduler';
deletedtests/src/removeFromContractAllowList.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/rmrk/acceptNft.test.tsdiffbeforeafterboth
8} from './util/tx';8} from './util/tx';
9import {NftIdTuple} from './util/fetch';9import {NftIdTuple} from './util/fetch';
10import {isNftChildOfAnother, expectTxFailure} from './util/helpers';10import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
11import {requirePallets, Pallets} from '../util/helpers';11import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
1212
13describe('integration test: accept NFT', () => {13describe('integration test: accept NFT', () => {
14 let api: any;14 let api: any;
modifiedtests/src/rmrk/addResource.test.tsdiffbeforeafterboth
12 addNftComposableResource,12 addNftComposableResource,
13} from './util/tx';13} from './util/tx';
14import {RmrkTraitsResourceResourceInfo as ResourceInfo} from '@polkadot/types/lookup';14import {RmrkTraitsResourceResourceInfo as ResourceInfo} from '@polkadot/types/lookup';
15import {requirePallets, Pallets} from '../util/helpers';15import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
1616
17describe('integration test: add NFT resource', () => {17describe('integration test: add NFT resource', () => {
18 const Alice = '//Alice';18 const Alice = '//Alice';
modifiedtests/src/rmrk/addTheme.test.tsdiffbeforeafterboth
3import {createBase, addTheme} from './util/tx';3import {createBase, addTheme} from './util/tx';
4import {expectTxFailure} from './util/helpers';4import {expectTxFailure} from './util/helpers';
5import {getThemeNames} from './util/fetch';5import {getThemeNames} from './util/fetch';
6import {requirePallets, Pallets} from '../util/helpers';6import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
77
8describe('integration test: add Theme to Base', () => {8describe('integration test: add Theme to Base', () => {
9 let api: any;9 let api: any;
modifiedtests/src/rmrk/burnNft.test.tsdiffbeforeafterboth
55
6import chai from 'chai';6import chai from 'chai';
7import chaiAsPromised from 'chai-as-promised';7import chaiAsPromised from 'chai-as-promised';
8import {requirePallets, Pallets} from '../util/helpers';8import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
99
10chai.use(chaiAsPromised);10chai.use(chaiAsPromised);
11const expect = chai.expect;11const expect = chai.expect;
modifiedtests/src/rmrk/changeCollectionIssuer.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {expectTxFailure} from './util/helpers';3import {expectTxFailure} from './util/helpers';
4import {4import {
5 changeIssuer,5 changeIssuer,
modifiedtests/src/rmrk/createBase.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {createCollection, createBase} from './util/tx';3import {createCollection, createBase} from './util/tx';
44
5describe('integration test: create new Base', () => {5describe('integration test: create new Base', () => {
modifiedtests/src/rmrk/createCollection.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {createCollection} from './util/tx';3import {createCollection} from './util/tx';
44
5describe('Integration test: create new collection', () => {5describe('Integration test: create new collection', () => {
modifiedtests/src/rmrk/deleteCollection.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {expectTxFailure} from './util/helpers';3import {expectTxFailure} from './util/helpers';
4import {createCollection, deleteCollection} from './util/tx';4import {createCollection, deleteCollection} from './util/tx';
55
modifiedtests/src/rmrk/equipNft.test.tsdiffbeforeafterboth
1import {ApiPromise} from '@polkadot/api';1import {ApiPromise} from '@polkadot/api';
2import {expect} from 'chai';2import {expect} from 'chai';
3import {getApiConnection} from '../substrate/substrate-api';3import {getApiConnection} from '../substrate/substrate-api';
4import {requirePallets, Pallets} from '../util/helpers';4import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
5import {getNft, getParts, NftIdTuple} from './util/fetch';5import {getNft, getParts, NftIdTuple} from './util/fetch';
6import {expectTxFailure} from './util/helpers';6import {expectTxFailure} from './util/helpers';
7import {7import {
modifiedtests/src/rmrk/getOwnedNfts.test.tsdiffbeforeafterboth
1import {expect} from 'chai';1import {expect} from 'chai';
2import {getApiConnection} from '../substrate/substrate-api';2import {getApiConnection} from '../substrate/substrate-api';
3import {requirePallets, Pallets} from '../util/helpers';3import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
4import {getOwnedNfts} from './util/fetch';4import {getOwnedNfts} from './util/fetch';
5import {mintNft, createCollection} from './util/tx';5import {mintNft, createCollection} from './util/tx';
66
modifiedtests/src/rmrk/lockCollection.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {expectTxFailure} from './util/helpers';3import {expectTxFailure} from './util/helpers';
4import {createCollection, lockCollection, mintNft} from './util/tx';4import {createCollection, lockCollection, mintNft} from './util/tx';
55
modifiedtests/src/rmrk/mintNft.test.tsdiffbeforeafterboth
1import {expect} from 'chai';1import {expect} from 'chai';
2import {getApiConnection} from '../substrate/substrate-api';2import {getApiConnection} from '../substrate/substrate-api';
3import {requirePallets, Pallets} from '../util/helpers';3import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
4import {getNft} from './util/fetch';4import {getNft} from './util/fetch';
5import {expectTxFailure} from './util/helpers';5import {expectTxFailure} from './util/helpers';
6import {createCollection, mintNft} from './util/tx';6import {createCollection, mintNft} from './util/tx';
modifiedtests/src/rmrk/rejectNft.test.tsdiffbeforeafterboth
8} from './util/tx';8} from './util/tx';
9import {getChildren, NftIdTuple} from './util/fetch';9import {getChildren, NftIdTuple} from './util/fetch';
10import {isNftChildOfAnother, expectTxFailure} from './util/helpers';10import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
11import {requirePallets, Pallets} from '../util/helpers';11import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
1212
13describe('integration test: reject NFT', () => {13describe('integration test: reject NFT', () => {
14 let api: any;14 let api: any;
modifiedtests/src/rmrk/removeResource.test.tsdiffbeforeafterboth
1import {expect} from 'chai';1import {expect} from 'chai';
2import privateKey from '../substrate/privateKey';2import privateKey from '../substrate/privateKey';
3import {executeTransaction, getApiConnection} from '../substrate/substrate-api';3import {executeTransaction, getApiConnection} from '../substrate/substrate-api';
4import {requirePallets, Pallets} from '../util/helpers';4import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
5import {getNft, NftIdTuple} from './util/fetch';5import {getNft, NftIdTuple} from './util/fetch';
6import {expectTxFailure} from './util/helpers';6import {expectTxFailure} from './util/helpers';
7import {7import {
modifiedtests/src/rmrk/rmrkIsolation.test.tsdiffbeforeafterboth
9 requirePallets,9 requirePallets,
10 normalizeAccountId,10 normalizeAccountId,
11 Pallets,11 Pallets,
12} from '../util/helpers';12} from '../deprecated-helpers/helpers';
13import {IKeyringPair} from '@polkadot/types/types';13import {IKeyringPair} from '@polkadot/types/types';
14import {ApiPromise} from '@polkadot/api';14import {ApiPromise} from '@polkadot/api';
15import {it} from 'mocha';15import {it} from 'mocha';
modifiedtests/src/rmrk/sendNft.test.tsdiffbeforeafterboth
3import {createCollection, mintNft, sendNft} from './util/tx';3import {createCollection, mintNft, sendNft} from './util/tx';
4import {NftIdTuple} from './util/fetch';4import {NftIdTuple} from './util/fetch';
5import {isNftChildOfAnother, expectTxFailure} from './util/helpers';5import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
6import {requirePallets, Pallets} from '../util/helpers';6import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
77
8describe('integration test: send NFT', () => {8describe('integration test: send NFT', () => {
9 let api: any;9 let api: any;
modifiedtests/src/rmrk/setCollectionProperty.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {expectTxFailure} from './util/helpers';3import {expectTxFailure} from './util/helpers';
4import {createCollection, setPropertyCollection} from './util/tx';4import {createCollection, setPropertyCollection} from './util/tx';
55
modifiedtests/src/rmrk/setEquippableList.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {expectTxFailure} from './util/helpers';3import {expectTxFailure} from './util/helpers';
4import {createCollection, createBase, setEquippableList} from './util/tx';4import {createCollection, createBase, setEquippableList} from './util/tx';
55
modifiedtests/src/rmrk/setNftProperty.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {NftIdTuple} from './util/fetch';3import {NftIdTuple} from './util/fetch';
4import {expectTxFailure} from './util/helpers';4import {expectTxFailure} from './util/helpers';
5import {createCollection, mintNft, sendNft, setNftProperty} from './util/tx';5import {createCollection, mintNft, sendNft, setNftProperty} from './util/tx';
modifiedtests/src/rmrk/setResourcePriorities.test.tsdiffbeforeafterboth
1import {getApiConnection} from '../substrate/substrate-api';1import {getApiConnection} from '../substrate/substrate-api';
2import {requirePallets, Pallets} from '../util/helpers';2import {requirePallets, Pallets} from '../deprecated-helpers/helpers';
3import {expectTxFailure} from './util/helpers';3import {expectTxFailure} from './util/helpers';
4import {mintNft, createCollection, setResourcePriorities} from './util/tx';4import {mintNft, createCollection, setResourcePriorities} from './util/tx';
55
deletedtests/src/rpc.load.tsdiffbeforeafterboth

no changes

deletedtests/src/scheduler.test.tsdiffbeforeafterboth

no changes

deletedtests/src/setChainLimits.test.tsdiffbeforeafterboth

no changes

deletedtests/src/setContractSponsoringRateLimit.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/substrate/get-balance.tsdiffbeforeafterboth
19import promisifySubstrate from './promisify-substrate';19import promisifySubstrate from './promisify-substrate';
20import {IKeyringPair} from '@polkadot/types/types';20import {IKeyringPair} from '@polkadot/types/types';
21import {submitTransactionAsync} from './substrate-api';21import {submitTransactionAsync} from './substrate-api';
22import {getGenericResult} from '../util/helpers';22import {getGenericResult} from '../deprecated-helpers/helpers';
23import {expect} from 'chai';23import {expect} from 'chai';
2424
25export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<Array<bigint>> {25export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<Array<bigint>> {
deletedtests/src/toggleContractAllowList.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/transfer.nload.tsdiffbeforeafterboth
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
19import usingApi, {submitTransactionAsync} from './substrate/substrate-api';19import usingApi, {submitTransactionAsync} from './substrate/substrate-api';
20import waitNewBlocks from './substrate/wait-new-blocks';20import waitNewBlocks from './substrate/wait-new-blocks';
21import {findUnusedAddresses} from './util/helpers';
22import * as cluster from 'cluster';21import * as cluster from 'cluster';
23import os from 'os';22import os from 'os';
23
24async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise<IKeyringPair> {
25 let bal = 0n;
26 let unused;
27 do {
28 const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;
29 unused = privateKeyWrapper(`//${randomSeed}`);
30 bal = (await api.query.system.account(unused.address)).data.free.toBigInt();
31 } while (bal !== 0n);
32 return unused;
33}
34
35function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise<IKeyringPair[]> {
36 return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now())));
37}
2438
25// Innacurate transfer fee39// Innacurate transfer fee
26const FEE = 10n ** 8n;40const FEE = 10n ** 8n;
deletedtests/src/transfer_contract/metadata.jsondiffbeforeafterboth

no changes

deletedtests/src/transfer_contract/nft_transfer.wasmdiffbeforeafterboth

binary blob — no preview

modifiedtests/src/tx-version-presence.test.tsdiffbeforeafterboth
22describe('TxVersion is present', () => {22describe('TxVersion is present', () => {
23 before(async () => {23 before(async () => {
24 await usingPlaygrounds(async helper => {24 await usingPlaygrounds(async helper => {
25 metadata = await helper.api!.rpc.state.getMetadata();25 metadata = await helper.callRpc('api.rpc.state.getMetadata', []);
26 });26 });
27 });27 });
2828
deletedtests/src/util/contracthelpers.tsdiffbeforeafterboth

no changes

deletedtests/src/util/helpers.tsdiffbeforeafterboth

no changes

modifiedtests/src/util/playgrounds/index.tsdiffbeforeafterboth
62 Fungible = 'fungible',62 Fungible = 'fungible',
63 NFT = 'nonfungible',63 NFT = 'nonfungible',
64 Scheduler = 'scheduler',64 Scheduler = 'scheduler',
65 AppPromotion = 'apppromotion',
65}66}
6667
67export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) {68export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) {
modifiedtests/src/util/playgrounds/types.tsdiffbeforeafterboth
14export interface ITransactionResult {14export interface ITransactionResult {
15 status: 'Fail' | 'Success';15 status: 'Fail' | 'Success';
16 result: {16 result: {
17 dispatchError: any,
17 events: {18 events: {
18 phase: any, // {ApplyExtrinsic: number} | 'Initialization',19 phase: any, // {ApplyExtrinsic: number} | 'Initialization',
19 event: IEvent;20 event: IEvent;
47 call: string;48 call: string;
48 params: any[];49 params: any[];
49 moduleError?: string;50 moduleError?: string;
51 dispatchError?: any;
50 events?: any;52 events?: any;
51}53}
5254
162 amount: bigint,164 amount: bigint,
163}165}
166
167export interface ISchedulerOptions {
168 priority?: number,
169 periodic?: {
170 period: number,
171 repetitions: number,
172 },
173}
164174
165export type TSubstrateAccount = string;175export type TSubstrateAccount = string;
166export type TEthereumAccount = string;176export type TEthereumAccount = string;
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
63 wait: WaitGroup;62 wait: WaitGroup;
64 admin: AdminGroup;63 admin: AdminGroup;
6564
66 constructor(logger: { log: (msg: any, level: any) => void, level: any }) {65 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
66 options.helperBase = options.helperBase ?? DevUniqueHelper;
67
67 super(logger);68 super(logger, options);
68 this.arrange = new ArrangeGroup(this);69 this.arrange = new ArrangeGroup(this);
69 this.wait = new WaitGroup(this);70 this.wait = new WaitGroup(this);
70 this.admin = new AdminGroup(this);71 this.admin = new AdminGroup(this);
108}109}
109110
110class ArrangeGroup {111class ArrangeGroup {
111 helper: UniqueHelper;112 helper: DevUniqueHelper;
112113
113 constructor(helper: UniqueHelper) {114 constructor(helper: DevUniqueHelper) {
114 this.helper = helper;115 this.helper = helper;
115 }116 }
116117
215 };216 };
216217
217 isDevNode = async () => {218 isDevNode = async () => {
218 const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));219 const block1 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [1])]);
219 const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));220 const block2 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [2])]);
220 const findCreationDate = async (block: any) => {221 const findCreationDate = async (block: any) => {
221 const humanBlock = block.toHuman();222 const humanBlock = block.toHuman();
222 let date;223 let date;
245}246}
246247
247class WaitGroup {248class WaitGroup {
248 helper: UniqueHelper;249 helper: DevUniqueHelper;
249250
250 constructor(helper: UniqueHelper) {251 constructor(helper: DevUniqueHelper) {
251 this.helper = helper;252 this.helper = helper;
252 }253 }
253254
254 /**255 /**
255 * Wait for specified bnumber of blocks256 * Wait for specified number of blocks
256 * @param blocksCount number of blocks to wait257 * @param blocksCount number of blocks to wait
257 * @returns 258 * @returns
258 */259 */
259 async newBlocks(blocksCount = 1): Promise<void> {260 async newBlocks(blocksCount = 1): Promise<void> {
260 // eslint-disable-next-line no-async-promise-executor261 // eslint-disable-next-line no-async-promise-executor
261 const promise = new Promise<void>(async (resolve) => {262 const promise = new Promise<void>(async (resolve) => {
262 const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {263 const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(() => {
263 if (blocksCount > 0) {264 if (blocksCount > 0) {
264 blocksCount--;265 blocksCount--;
265 } else {266 } else {
274 async forParachainBlockNumber(blockNumber: bigint) {275 async forParachainBlockNumber(blockNumber: bigint) {
275 // eslint-disable-next-line no-async-promise-executor276 // eslint-disable-next-line no-async-promise-executor
276 return new Promise<void>(async (resolve) => {277 return new Promise<void>(async (resolve) => {
277 const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(async (data: any) => {278 const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(async (data: any) => {
278 if (data.number.toNumber() >= blockNumber) {279 if (data.number.toNumber() >= blockNumber) {
279 unsubscribe();280 unsubscribe();
280 resolve();281 resolve();
286 async forRelayBlockNumber(blockNumber: bigint) {287 async forRelayBlockNumber(blockNumber: bigint) {
287 // eslint-disable-next-line no-async-promise-executor288 // eslint-disable-next-line no-async-promise-executor
288 return new Promise<void>(async (resolve) => {289 return new Promise<void>(async (resolve) => {
289 const unsubscribe = await this.helper.api!.query.parachainSystem.validationData(async (data: any) => {290 const unsubscribe = await this.helper.getApi().query.parachainSystem.validationData(async (data: any) => {
290 if (data.value.relayParentNumber.toNumber() >= blockNumber) {291 if (data.value.relayParentNumber.toNumber() >= blockNumber) {
291 // @ts-ignore292 // @ts-ignore
292 unsubscribe();293 unsubscribe();
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';
10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
11import {IKeyringPair} from '@polkadot/types/types';11import {IKeyringPair} from '@polkadot/types/types';
12import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';12import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISchedulerOptions, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
1313
14export class CrossAccountId implements ICrossAccountId {14export class CrossAccountId implements ICrossAccountId {
15 Substrate?: TSubstrateAccount;15 Substrate?: TSubstrateAccount;
275 }275 }
276 276
277 private static extractData(data: any, type: any): any {277 private static extractData(data: any, type: any): any {
278 if(!type) return data.toHuman();
278 if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();279 if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();
279 if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();280 if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();
280 if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);281 if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);
317 forcedNetwork: TUniqueNetworks | null;318 forcedNetwork: TUniqueNetworks | null;
318 network: TUniqueNetworks | null;319 network: TUniqueNetworks | null;
319 chainLog: IUniqueHelperLog[];320 chainLog: IUniqueHelperLog[];
321 children: ChainHelperBase[];
320322
321 constructor(logger?: ILogger) {323 constructor(logger?: ILogger) {
322 this.util = UniqueUtil;324 this.util = UniqueUtil;
327 this.forcedNetwork = null;329 this.forcedNetwork = null;
328 this.network = null;330 this.network = null;
329 this.chainLog = [];331 this.chainLog = [];
332 this.children = [];
330 }333 }
334
335 getApi(): ApiPromise {
336 if(this.api === null) throw Error('API not initialized');
337 return this.api;
338 }
331339
332 clearChainLog(): void {340 clearChainLog(): void {
333 this.chainLog = [];341 this.chainLog = [];
345 }353 }
346354
347 async disconnect() {355 async disconnect() {
356 for (const child of this.children) {
357 child.clearApi();
358 }
359
348 if (this.api === null) return;360 if (this.api === null) return;
349 await this.api.disconnect();361 await this.api.disconnect();
350 this.api = null;362 this.clearApi();
351 this.network = null;
352 }363 }
364
365 clearApi() {
366 this.api = null;
367 this.network = null;
368 }
353369
354 static async detectNetwork(api: ApiPromise): Promise<TUniqueNetworks> {370 static async detectNetwork(api: ApiPromise): Promise<TUniqueNetworks> {
355 const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;371 const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;
473489
474 constructApiCall(apiCall: string, params: any[]) {490 constructApiCall(apiCall: string, params: any[]) {
475 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);491 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);
476 let call = this.api as any;492 let call = this.getApi() as any;
477 for(const part of apiCall.slice(4).split('.')) {493 for(const part of apiCall.slice(4).split('.')) {
478 call = call[part];494 call = call[part];
479 }495 }
508 params,524 params,
509 } as IUniqueHelperLog;525 } as IUniqueHelperLog;
510526
511 if(result.status !== this.transactionStatus.SUCCESS && result.moduleError) log.moduleError = result.moduleError;527 if(result.status !== this.transactionStatus.SUCCESS) {
528 if (result.moduleError) log.moduleError = result.moduleError;
529 else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;
530 }
512 if(events.length > 0) log.events = events;531 if(events.length > 0) log.events = events;
513532
514 this.chainLog.push(log);533 this.chainLog.push(log);
515534
516 if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) throw Error(`${result.moduleError}`);535 if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {
536 if (result.moduleError) throw Error(`${result.moduleError}`);
537 else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));
538 }
517 return result;539 return result;
518 }540 }
519541
1985 * @returns ss58Format, token decimals, and token symbol2007 * @returns ss58Format, token decimals, and token symbol
1986 */2008 */
1987 getChainProperties(): IChainProperties {2009 getChainProperties(): IChainProperties {
1988 const properties = (this.helper.api as any).registry.getChainProperties().toJSON();2010 const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();
1989 return {2011 return {
1990 ss58Format: properties.ss58Format.toJSON(),2012 ss58Format: properties.ss58Format.toJSON(),
1991 tokenDecimals: properties.tokenDecimals.toJSON(),2013 tokenDecimals: properties.tokenDecimals.toJSON(),
2028 * @returns number, account's nonce2050 * @returns number, account's nonce
2029 */2051 */
2030 async getNonce(address: TSubstrateAccount): Promise<number> {2052 async getNonce(address: TSubstrateAccount): Promise<number> {
2031 return (await (this.helper.api as any).query.system.account(address)).nonce.toNumber();2053 return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();
2032 }2054 }
2033}2055}
20342056
2160 */2182 */
2161 async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2183 async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {
2162 if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2184 if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;
2163 const stakeResult = await this.helper.executeExtrinsic(2185 const _stakeResult = await this.helper.executeExtrinsic(
2164 signer, 'api.tx.appPromotion.stake',2186 signer, 'api.tx.appPromotion.stake',
2165 [amountToStake], true,2187 [amountToStake], true,
2166 );2188 );
2177 */2199 */
2178 async unstake(signer: TSigner, label?: string): Promise<number> {2200 async unstake(signer: TSigner, label?: string): Promise<number> {
2179 if(typeof label === 'undefined') label = `${signer.address}`;2201 if(typeof label === 'undefined') label = `${signer.address}`;
2180 const unstakeResult = await this.helper.executeExtrinsic(2202 const _unstakeResult = await this.helper.executeExtrinsic(
2181 signer, 'api.tx.appPromotion.unstake',2203 signer, 'api.tx.appPromotion.unstake',
2182 [], true,2204 [], true,
2183 );2205 );
2236 }2258 }
2237}2259}
2260
2261class SchedulerGroup extends HelperGroup {
2262 constructor(helper: UniqueHelper) {
2263 super(helper);
2264 }
2265
2266 async cancelScheduled(signer: TSigner, scheduledId: string) {
2267 return this.helper.executeExtrinsic(
2268 signer,
2269 'api.tx.scheduler.cancelNamed',
2270 [scheduledId],
2271 true,
2272 );
2273 }
2274
2275 async changePriority(signer: TSigner, scheduledId: string, priority: number) {
2276 return this.helper.executeExtrinsic(
2277 signer,
2278 'api.tx.scheduler.changeNamedPriority',
2279 [scheduledId, priority],
2280 true,
2281 );
2282 }
2283
2284 scheduleAt<T extends UniqueHelper>(
2285 scheduledId: string,
2286 executionBlockNumber: number,
2287 options: ISchedulerOptions = {},
2288 ) {
2289 return this.schedule<T>('scheduleNamed', scheduledId, executionBlockNumber, options);
2290 }
2291
2292 scheduleAfter<T extends UniqueHelper>(
2293 scheduledId: string,
2294 blocksBeforeExecution: number,
2295 options: ISchedulerOptions = {},
2296 ) {
2297 return this.schedule<T>('scheduleNamedAfter', scheduledId, blocksBeforeExecution, options);
2298 }
2299
2300 schedule<T extends UniqueHelper>(
2301 scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter',
2302 scheduledId: string,
2303 blocksNum: number,
2304 options: ISchedulerOptions = {},
2305 ) {
2306 // eslint-disable-next-line @typescript-eslint/naming-convention
2307 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);
2308 return this.helper.clone(ScheduledHelperType, {
2309 scheduleFn,
2310 scheduledId,
2311 blocksNum,
2312 options,
2313 }) as T;
2314 }
2315}
2316
2317export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;
22382318
2239export class UniqueHelper extends ChainHelperBase {2319export class UniqueHelper extends ChainHelperBase {
2320 helperBase: any;
2321
2240 chain: ChainGroup;2322 chain: ChainGroup;
2241 balance: BalanceGroup;2323 balance: BalanceGroup;
2245 rft: RFTGroup;2327 rft: RFTGroup;
2246 ft: FTGroup;2328 ft: FTGroup;
2247 staking: StakingGroup;2329 staking: StakingGroup;
2330 scheduler: SchedulerGroup;
22482331
2249 constructor(logger?: ILogger) {2332 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {
2250 super(logger);2333 super(logger);
2334
2335 this.helperBase = options.helperBase ?? UniqueHelper;
2336
2251 this.chain = new ChainGroup(this);2337 this.chain = new ChainGroup(this);
2252 this.balance = new BalanceGroup(this);2338 this.balance = new BalanceGroup(this);
2256 this.rft = new RFTGroup(this);2342 this.rft = new RFTGroup(this);
2257 this.ft = new FTGroup(this);2343 this.ft = new FTGroup(this);
2258 this.staking = new StakingGroup(this);2344 this.staking = new StakingGroup(this);
2345 this.scheduler = new SchedulerGroup(this);
2259 }2346 }
2347
2348 clone(helperCls: UniqueHelperConstructor, options: {[key: string]: any} = {}) {
2349 Object.setPrototypeOf(helperCls.prototype, this);
2350 const newHelper = new helperCls(this.logger, options);
2351
2352 newHelper.api = this.api;
2353 newHelper.network = this.network;
2354 newHelper.forceNetwork = this.forceNetwork;
2355
2356 this.children.push(newHelper);
2357
2358 return newHelper;
2359 }
2360
2361 getSudo<T extends UniqueHelper>() {
2362 // eslint-disable-next-line @typescript-eslint/naming-convention
2363 const SudoHelperType = SudoUniqueHelper(this.helperBase);
2364 return this.clone(SudoHelperType) as T;
2365 }
2260}2366}
22612367
2368// eslint-disable-next-line @typescript-eslint/naming-convention
2369function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {
2370 return class extends Base {
2371 scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter';
2372 scheduledId: string;
2373 blocksNum: number;
2374 options: ISchedulerOptions;
2375
2376 constructor(...args: any[]) {
2377 const logger = args[0] as ILogger;
2378 const options = args[1] as {
2379 scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter',
2380 scheduledId: string,
2381 blocksNum: number,
2382 options: ISchedulerOptions
2383 };
2384
2385 super(logger);
2386
2387 this.scheduleFn = options.scheduleFn;
2388 this.scheduledId = options.scheduledId;
2389 this.blocksNum = options.blocksNum;
2390 this.options = options.options;
2391 }
2392
2393 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {
2394 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);
2395 const extrinsic = 'api.tx.scheduler.' + this.scheduleFn;
2396
2397 return super.executeExtrinsic(
2398 sender,
2399 extrinsic,
2400 [
2401 this.scheduledId,
2402 this.blocksNum,
2403 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,
2404 this.options.priority ?? null,
2405 {Value: scheduledTx},
2406 ],
2407 expectSuccess,
2408 );
2409 }
2410 };
2411}
2412
2413// eslint-disable-next-line @typescript-eslint/naming-convention
2414function SudoUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {
2415 return class extends Base {
2416 constructor(...args: any[]) {
2417 super(...args);
2418 }
2419
2420 executeExtrinsic (
2421 sender: IKeyringPair,
2422 extrinsic: string,
2423 params: any[],
2424 expectSuccess?: boolean,
2425 ): Promise<ITransactionResult> {
2426 const call = this.constructApiCall(extrinsic, params);
2427
2428 return super.executeExtrinsic(
2429 sender,
2430 'api.tx.sudo.sudo',
2431 [call],
2432 expectSuccess,
2433 );
2434 }
2435 };
2436}
22622437
2263export class UniqueBaseCollection {2438export class UniqueBaseCollection {
2264 helper: UniqueHelper;2439 helper: UniqueHelper;
2361 return await this.helper.collection.burn(signer, this.collectionId);2536 return await this.helper.collection.burn(signer, this.collectionId);
2362 }2537 }
2538
2539 scheduleAt<T extends UniqueHelper>(
2540 scheduledId: string,
2541 executionBlockNumber: number,
2542 options: ISchedulerOptions = {},
2543 ) {
2544 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);
2545 return new UniqueBaseCollection(this.collectionId, scheduledHelper);
2546 }
2547
2548 scheduleAfter<T extends UniqueHelper>(
2549 scheduledId: string,
2550 blocksBeforeExecution: number,
2551 options: ISchedulerOptions = {},
2552 ) {
2553 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
2554 return new UniqueBaseCollection(this.collectionId, scheduledHelper);
2555 }
2556
2557 getSudo<T extends UniqueHelper>() {
2558 return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());
2559 }
2363}2560}
23642561
23652562
2448 return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);2645 return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
2449 }2646 }
2647
2648 scheduleAt<T extends UniqueHelper>(
2649 scheduledId: string,
2650 executionBlockNumber: number,
2651 options: ISchedulerOptions = {},
2652 ) {
2653 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);
2654 return new UniqueNFTCollection(this.collectionId, scheduledHelper);
2655 }
2656
2657 scheduleAfter<T extends UniqueHelper>(
2658 scheduledId: string,
2659 blocksBeforeExecution: number,
2660 options: ISchedulerOptions = {},
2661 ) {
2662 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
2663 return new UniqueNFTCollection(this.collectionId, scheduledHelper);
2664 }
2665
2666 getSudo<T extends UniqueHelper>() {
2667 return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());
2668 }
2450}2669}
24512670
24522671
2531 return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);2750 return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
2532 }2751 }
2752
2753 scheduleAt<T extends UniqueHelper>(
2754 scheduledId: string,
2755 executionBlockNumber: number,
2756 options: ISchedulerOptions = {},
2757 ) {
2758 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);
2759 return new UniqueRFTCollection(this.collectionId, scheduledHelper);
2760 }
2761
2762 scheduleAfter<T extends UniqueHelper>(
2763 scheduledId: string,
2764 blocksBeforeExecution: number,
2765 options: ISchedulerOptions = {},
2766 ) {
2767 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
2768 return new UniqueRFTCollection(this.collectionId, scheduledHelper);
2769 }
2770
2771 getSudo<T extends UniqueHelper>() {
2772 return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());
2773 }
2533}2774}
25342775
25352776
2578 return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);2819 return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);
2579 }2820 }
2821
2822 scheduleAt<T extends UniqueHelper>(
2823 scheduledId: string,
2824 executionBlockNumber: number,
2825 options: ISchedulerOptions = {},
2826 ) {
2827 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);
2828 return new UniqueFTCollection(this.collectionId, scheduledHelper);
2829 }
2830
2831 scheduleAfter<T extends UniqueHelper>(
2832 scheduledId: string,
2833 blocksBeforeExecution: number,
2834 options: ISchedulerOptions = {},
2835 ) {
2836 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
2837 return new UniqueFTCollection(this.collectionId, scheduledHelper);
2838 }
2839
2840 getSudo<T extends UniqueHelper>() {
2841 return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());
2842 }
2580}2843}
25812844
25822845
2615 return this.collection.helper.util.getTokenAccount(this);2878 return this.collection.helper.util.getTokenAccount(this);
2616 }2879 }
2880
2881 scheduleAt<T extends UniqueHelper>(
2882 scheduledId: string,
2883 executionBlockNumber: number,
2884 options: ISchedulerOptions = {},
2885 ) {
2886 const scheduledCollection = this.collection.scheduleAt<T>(scheduledId, executionBlockNumber, options);
2887 return new UniqueBaseToken(this.tokenId, scheduledCollection);
2888 }
2889
2890 scheduleAfter<T extends UniqueHelper>(
2891 scheduledId: string,
2892 blocksBeforeExecution: number,
2893 options: ISchedulerOptions = {},
2894 ) {
2895 const scheduledCollection = this.collection.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
2896 return new UniqueBaseToken(this.tokenId, scheduledCollection);
2897 }
2898
2899 getSudo<T extends UniqueHelper>() {
2900 return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());
2901 }
2617}2902}
26182903
26192904
2673 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);2958 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);
2674 }2959 }
2960
2961 scheduleAt<T extends UniqueHelper>(
2962 scheduledId: string,
2963 executionBlockNumber: number,
2964 options: ISchedulerOptions = {},
2965 ) {
2966 const scheduledCollection = this.collection.scheduleAt<T>(scheduledId, executionBlockNumber, options);
2967 return new UniqueNFToken(this.tokenId, scheduledCollection);
2968 }
2969
2970 scheduleAfter<T extends UniqueHelper>(
2971 scheduledId: string,
2972 blocksBeforeExecution: number,
2973 options: ISchedulerOptions = {},
2974 ) {
2975 const scheduledCollection = this.collection.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
2976 return new UniqueNFToken(this.tokenId, scheduledCollection);
2977 }
2978
2979 getSudo<T extends UniqueHelper>() {
2980 return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());
2981 }
2675}2982}
26762983
2677export class UniqueRFToken extends UniqueBaseToken {2984export class UniqueRFToken extends UniqueBaseToken {
2726 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3033 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);
2727 }3034 }
3035
3036 scheduleAt<T extends UniqueHelper>(
3037 scheduledId: string,
3038 executionBlockNumber: number,
3039 options: ISchedulerOptions = {},
3040 ) {
3041 const scheduledCollection = this.collection.scheduleAt<T>(scheduledId, executionBlockNumber, options);
3042 return new UniqueRFToken(this.tokenId, scheduledCollection);
3043 }
3044
3045 scheduleAfter<T extends UniqueHelper>(
3046 scheduledId: string,
3047 blocksBeforeExecution: number,
3048 options: ISchedulerOptions = {},
3049 ) {
3050 const scheduledCollection = this.collection.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);
3051 return new UniqueRFToken(this.tokenId, scheduledCollection);
3052 }
3053
3054 getSudo<T extends UniqueHelper>() {
3055 return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());
3056 }
2728}3057}
27293058
deletedtests/src/util/util.tsdiffbeforeafterboth

no changes

modifiedtests/src/xcm/xcmOpal.test.tsdiffbeforeafterboth
21import {ApiOptions} from '@polkadot/api/types';21import {ApiOptions} from '@polkadot/api/types';
22import {IKeyringPair} from '@polkadot/types/types';22import {IKeyringPair} from '@polkadot/types/types';
23import usingApi, {executeTransaction} from './../substrate/substrate-api';23import usingApi, {executeTransaction} from './../substrate/substrate-api';
24import {bigIntToDecimals, describe_xcm, getGenericResult, paraSiblingSovereignAccount} from './../util/helpers';24import {bigIntToDecimals, describe_xcm, getGenericResult, paraSiblingSovereignAccount, normalizeAccountId} from './../deprecated-helpers/helpers';
25import waitNewBlocks from './../substrate/wait-new-blocks';25import waitNewBlocks from './../substrate/wait-new-blocks';
26import {normalizeAccountId} from './../util/helpers';
27import getBalance from './../substrate/get-balance';26import getBalance from './../substrate/get-balance';
2827
2928
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
21import {ApiOptions} from '@polkadot/api/types';21import {ApiOptions} from '@polkadot/api/types';
22import {IKeyringPair} from '@polkadot/types/types';22import {IKeyringPair} from '@polkadot/types/types';
23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';
24import {getGenericResult, generateKeyringPair, waitEvent, describe_xcm, bigIntToDecimals} from '../util/helpers';24import {getGenericResult, generateKeyringPair, waitEvent, describe_xcm, bigIntToDecimals} from '../deprecated-helpers/helpers';
25import {MultiLocation} from '@polkadot/types/interfaces';25import {MultiLocation} from '@polkadot/types/interfaces';
26import {blake2AsHex} from '@polkadot/util-crypto';26import {blake2AsHex} from '@polkadot/util-crypto';
27import waitNewBlocks from '../substrate/wait-new-blocks';27import waitNewBlocks from '../substrate/wait-new-blocks';
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
21import {ApiOptions} from '@polkadot/api/types';21import {ApiOptions} from '@polkadot/api/types';
22import {IKeyringPair} from '@polkadot/types/types';22import {IKeyringPair} from '@polkadot/types/types';
23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';
24import {getGenericResult, generateKeyringPair, waitEvent, describe_xcm, bigIntToDecimals} from '../util/helpers';24import {getGenericResult, generateKeyringPair, waitEvent, describe_xcm, bigIntToDecimals} from '../deprecated-helpers/helpers';
25import {MultiLocation} from '@polkadot/types/interfaces';25import {MultiLocation} from '@polkadot/types/interfaces';
26import {blake2AsHex} from '@polkadot/util-crypto';26import {blake2AsHex} from '@polkadot/util-crypto';
27import waitNewBlocks from '../substrate/wait-new-blocks';27import waitNewBlocks from '../substrate/wait-new-blocks';
deletedtests/src/xcmTransfer.test.tsdiffbeforeafterboth

no changes

modifiedtests/tsconfig.jsondiffbeforeafterboth
21 "./src/**/*",21 "./src/**/*",
22 "./src/interfaces/*.ts"22 "./src/interfaces/*.ts"
23 ],23 ],
24 "exclude": [
25 "./src/.outdated"
26 ],
24 "lib": [27 "lib": [
25 "es2017"28 "es2017"
26 ],29 ],