git.delta.rocks / unique-network / refs/commits / 4906885c14fb

difftreelog

source

tests/src/eth/reFungibleToken.test.ts20.8 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';18import {EthUniqueHelper, expect, itEth, usingEthPlaygrounds} from './util/playgrounds';19import {IKeyringPair} from '@polkadot/types/types';20import {Contract} from 'web3-eth-contract';212223describe('Refungible token: Information getting', () => {24  let donor: IKeyringPair;25  let alice: IKeyringPair;2627  before(async function() {28    await usingEthPlaygrounds(async (helper, privateKey) => {29      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);3031      donor = privateKey('//Alice');32      [alice] = await helper.arrange.createAccounts([20n], donor);33    });34  });3536  itEth('totalSupply', async ({helper}) => {37    const caller = await helper.eth.createAccountWithBalance(donor);38    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});39    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});4041    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);42    const totalSupply = await contract.methods.totalSupply().call();43    expect(totalSupply).to.equal('200');44  });4546  itEth('balanceOf', async ({helper}) => {47    const caller = await helper.eth.createAccountWithBalance(donor);48    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});49    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});5051    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);52    const balance = await contract.methods.balanceOf(caller).call();53    expect(balance).to.equal('200');54  });5556  itEth('decimals', async ({helper}) => {57    const caller = await helper.eth.createAccountWithBalance(donor);58    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});59    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});6061    const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);62    const decimals = await contract.methods.decimals().call();63    expect(decimals).to.equal('0');64  });65});6667// FIXME: Need erc721 for ReFubgible.68describe('Check ERC721 token URI for ReFungible', () => {69  let donor: IKeyringPair;7071  before(async function() {72    await usingEthPlaygrounds(async (helper, privateKey) => {73      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);7475      donor = privateKey('//Alice');76    });77  });7879  async function setup(helper: EthUniqueHelper, baseUri: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {80    const owner = await helper.eth.createAccountWithBalance(donor);81    const receiver = helper.eth.createAccount();8283    const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Mint collection', 'a', 'b', baseUri);84    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);8586    const result = await contract.methods.mint(receiver).send();8788    const event = result.events.Transfer;89    const tokenId = event.returnValues.tokenId;90    expect(tokenId).to.be.equal('1');91    expect(event.address).to.be.equal(collectionAddress);92    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');93    expect(event.returnValues.to).to.be.equal(receiver);9495    if (propertyKey && propertyValue) {96      // Set URL or suffix97      await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send();98    }99100    return {contract, nextTokenId: tokenId};101  }102103  itEth('Empty tokenURI', async ({helper}) => {104    const {contract, nextTokenId} = await setup(helper, '');105    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');106  });107108  itEth('TokenURI from url', async ({helper}) => {109    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URI', 'Token URI');110    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');111  });112113  itEth('TokenURI from baseURI', async ({helper}) => {114    const {contract, nextTokenId} = await setup(helper, 'BaseURI_');115    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_');116  });117118  itEth('TokenURI from baseURI + suffix', async ({helper}) => {119    const suffix = '/some/suffix';120    const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'URISuffix', suffix);121    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);122  });123});124125describe('Refungible: Plain calls', () => {126  let donor: IKeyringPair;127  let alice: IKeyringPair;128129  before(async function() {130    await usingEthPlaygrounds(async (helper, privateKey) => {131      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);132133      donor = privateKey('//Alice');134      [alice] = await helper.arrange.createAccounts([50n], donor);135    });136  });137138  itEth('Can perform approve()', async ({helper}) => {139    const owner = await helper.eth.createAccountWithBalance(donor);140    const spender = helper.eth.createAccount();141    const collection = await helper.rft.mintCollection(alice);142    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});143144    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);145    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);146147    {148      const result = await contract.methods.approve(spender, 100).send({from: owner});149      const event = result.events.Approval;150      expect(event.address).to.be.equal(tokenAddress);151      expect(event.returnValues.owner).to.be.equal(owner);152      expect(event.returnValues.spender).to.be.equal(spender);153      expect(event.returnValues.value).to.be.equal('100');154    }155156    {157      const allowance = await contract.methods.allowance(owner, spender).call();158      expect(+allowance).to.equal(100);159    }160  });161162  itEth('Can perform transferFrom()', async ({helper}) => {163    const owner = await helper.eth.createAccountWithBalance(donor);164    const spender = await helper.eth.createAccountWithBalance(donor);165    const receiver = helper.eth.createAccount();166    const collection = await helper.rft.mintCollection(alice);167    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});168169    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);170    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);171172    await contract.methods.approve(spender, 100).send();173174    {175      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});176      let event = result.events.Transfer;177      expect(event.address).to.be.equal(tokenAddress);178      expect(event.returnValues.from).to.be.equal(owner);179      expect(event.returnValues.to).to.be.equal(receiver);180      expect(event.returnValues.value).to.be.equal('49');181182      event = result.events.Approval;183      expect(event.address).to.be.equal(tokenAddress);184      expect(event.returnValues.owner).to.be.equal(owner);185      expect(event.returnValues.spender).to.be.equal(spender);186      expect(event.returnValues.value).to.be.equal('51');187    }188189    {190      const balance = await contract.methods.balanceOf(receiver).call();191      expect(+balance).to.equal(49);192    }193194    {195      const balance = await contract.methods.balanceOf(owner).call();196      expect(+balance).to.equal(151);197    }198  });199200  itEth('Can perform transfer()', async ({helper}) => {201    const owner = await helper.eth.createAccountWithBalance(donor);202    const receiver = helper.eth.createAccount();203    const collection = await helper.rft.mintCollection(alice);204    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});205206    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);207    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);208209    {210      const result = await contract.methods.transfer(receiver, 50).send({from: owner});211      const event = result.events.Transfer;212      expect(event.address).to.be.equal(tokenAddress);213      expect(event.returnValues.from).to.be.equal(owner);214      expect(event.returnValues.to).to.be.equal(receiver);215      expect(event.returnValues.value).to.be.equal('50');216    }217218    {219      const balance = await contract.methods.balanceOf(owner).call();220      expect(+balance).to.equal(150);221    }222223    {224      const balance = await contract.methods.balanceOf(receiver).call();225      expect(+balance).to.equal(50);226    }227  });228229  itEth('Can perform repartition()', async ({helper}) => {230    const owner = await helper.eth.createAccountWithBalance(donor);231    const receiver = await helper.eth.createAccountWithBalance(donor);232    const collection = await helper.rft.mintCollection(alice);233    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});234235    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);236    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);237238    await contract.methods.repartition(200).send({from: owner});239    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);240    await contract.methods.transfer(receiver, 110).send({from: owner});241    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);242    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);243244    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected; // Transaction is reverted245246    await contract.methods.transfer(receiver, 90).send({from: owner});247    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);248    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);249250    await contract.methods.repartition(150).send({from: receiver});251    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected; // Transaction is reverted252    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);253  });254255  itEth('Can repartition with increased amount', async ({helper}) => {256    const owner = await helper.eth.createAccountWithBalance(donor);257    const collection = await helper.rft.mintCollection(alice);258    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});259260    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);261    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);262263    const result = await contract.methods.repartition(200).send();264265    const event = result.events.Transfer;266    expect(event.address).to.be.equal(tokenAddress);267    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');268    expect(event.returnValues.to).to.be.equal(owner);269    expect(event.returnValues.value).to.be.equal('100');270  });271272  itEth('Can repartition with decreased amount', async ({helper}) => {273    const owner = await helper.eth.createAccountWithBalance(donor);274    const collection = await helper.rft.mintCollection(alice);275    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});276277    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);278    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);279280    const result = await contract.methods.repartition(50).send();281    const event = result.events.Transfer;282    expect(event.address).to.be.equal(tokenAddress);283    expect(event.returnValues.from).to.be.equal(owner);284    expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');285    expect(event.returnValues.value).to.be.equal('50');286  });287288  itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => {289    const caller = await helper.eth.createAccountWithBalance(donor);290    const receiver = await helper.eth.createAccountWithBalance(donor);291    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6');292    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);293294    const result = await contract.methods.mint(caller).send();295    const tokenId = result.events.Transfer.returnValues.tokenId;296    const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);297    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);298299    await tokenContract.methods.repartition(2).send();300    await tokenContract.methods.transfer(receiver, 1).send();301302    const events: any = [];303    contract.events.allEvents((_: any, event: any) => {304      events.push(event);305    });306    await tokenContract.methods.burnFrom(caller, 1).send();307308    const event = events[0];309    expect(event.address).to.be.equal(collectionAddress);310    expect(event.returnValues.from).to.be.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');311    expect(event.returnValues.to).to.be.equal(receiver);312    expect(event.returnValues.tokenId).to.be.equal(tokenId);313  });314});315316describe('Refungible: Fees', () => {317  let donor: IKeyringPair;318  let alice: IKeyringPair;319320  before(async function() {321    await usingEthPlaygrounds(async (helper, privateKey) => {322      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);323324      donor = privateKey('//Alice');325      [alice] = await helper.arrange.createAccounts([50n], donor);326    });327  });328329  itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {330    const owner = await helper.eth.createAccountWithBalance(donor);331    const spender = helper.eth.createAccount();332    const collection = await helper.rft.mintCollection(alice);333    const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});334335    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);336    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);337338    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));339    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));340  });341342  itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {343    const owner = await helper.eth.createAccountWithBalance(donor);344    const spender = await helper.eth.createAccountWithBalance(donor);345    const collection = await helper.rft.mintCollection(alice);346    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});347348    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);349    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);350351    await contract.methods.approve(spender, 100).send({from: owner});352353    const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));354    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));355  });356357  itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {358    const owner = await helper.eth.createAccountWithBalance(donor);359    const receiver = helper.eth.createAccount();360    const collection = await helper.rft.mintCollection(alice);361    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});362363    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);364    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);365366    const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));367    expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));368  });369});370371describe('Refungible: Substrate calls', () => {372  let donor: IKeyringPair;373  let alice: IKeyringPair;374375  before(async function() {376    await usingEthPlaygrounds(async (helper, privateKey) => {377      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);378379      donor = privateKey('//Alice');380      [alice] = await helper.arrange.createAccounts([50n], donor);381    });382  });383384  itEth('Events emitted for approve()', async ({helper}) => {385    const receiver = helper.eth.createAccount();386    const collection = await helper.rft.mintCollection(alice);387    const token = await collection.mintToken(alice, 200n);388389    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);390    const contract = helper.ethNativeContract.rftToken(tokenAddress);391392    const events: any = [];393    contract.events.allEvents((_: any, event: any) => {394      events.push(event);395    });396    expect(await token.approve(alice, {Ethereum: receiver}, 100n)).to.be.true;397398    const event = events[0];399    expect(event.event).to.be.equal('Approval');400    expect(event.address).to.be.equal(tokenAddress);401    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));402    expect(event.returnValues.spender).to.be.equal(receiver);403    expect(event.returnValues.value).to.be.equal('100');404  });405406  itEth('Events emitted for transferFrom()', async ({helper}) => {407    const [bob] = await helper.arrange.createAccounts([10n], donor);408    const receiver = helper.eth.createAccount();409    const collection = await helper.rft.mintCollection(alice);410    const token = await collection.mintToken(alice, 200n);411    await token.approve(alice, {Substrate: bob.address}, 100n);412413    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);414    const contract = helper.ethNativeContract.rftToken(tokenAddress);415416    const events: any = [];417    contract.events.allEvents((_: any, event: any) => {418      events.push(event);419    });420421    expect(await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver},  51n)).to.be.true;422423    let event = events[0];424    expect(event.event).to.be.equal('Transfer');425    expect(event.address).to.be.equal(tokenAddress);426    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));427    expect(event.returnValues.to).to.be.equal(receiver);428    expect(event.returnValues.value).to.be.equal('51');429430    event = events[1];431    expect(event.event).to.be.equal('Approval');432    expect(event.address).to.be.equal(tokenAddress);433    expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));434    expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));435    expect(event.returnValues.value).to.be.equal('49');436  });437438  itEth('Events emitted for transfer()', async ({helper}) => {439    const receiver = helper.eth.createAccount();440    const collection = await helper.rft.mintCollection(alice);441    const token = await collection.mintToken(alice, 200n);442443    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);444    const contract = helper.ethNativeContract.rftToken(tokenAddress);445446    const events: any = [];447    contract.events.allEvents((_: any, event: any) => {448      events.push(event);449    });450451    expect(await token.transfer(alice, {Ethereum: receiver},  51n)).to.be.true;452453    const event = events[0];454    expect(event.event).to.be.equal('Transfer');455    expect(event.address).to.be.equal(tokenAddress);456    expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));457    expect(event.returnValues.to).to.be.equal(receiver);458    expect(event.returnValues.value).to.be.equal('51');459  });460});461462describe('ERC 1633 implementation', () => {463  let donor: IKeyringPair;464465  before(async function() {466    await usingEthPlaygrounds(async (helper, privateKey) => {467      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);468469      donor = privateKey('//Alice');470    });471  });472473  itEth('Default parent token address and id', async ({helper}) => {474    const owner = await helper.eth.createAccountWithBalance(donor);475476    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN');477    const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);478479    const result = await collectionContract.methods.mint(owner).send();480    const tokenId = result.events.Transfer.returnValues.tokenId;481482    const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);483    const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);484485    expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress);486    expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId);487  });488});