--- a/tests/package.json +++ b/tests/package.json @@ -30,6 +30,7 @@ "testEth": "mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.test.ts'", "testEthMarketplace": "mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.test.ts'", "testEthNesting": "mocha --timeout 9999999 -r ts-node/register './**/eth/nesting/**/*.test.ts'", + "testEthPayable": "mocha --timeout 9999999 -r ts-node/register './**/eth/payable.test.ts'", "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'", "loadTransfer": "ts-node src/transfer.nload.ts", "testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts", @@ -84,7 +85,8 @@ "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts", "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts", "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts", - "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts", + "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts", + "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.test.ts", "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts", "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts", "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts", --- a/tests/src/eth/collectionAdmin.test.ts +++ b/tests/src/eth/collectionAdmin.test.ts @@ -24,7 +24,6 @@ getCollectionAddressFromResult, itWeb3, recordEthFee, - subToEth, } from './util/helpers'; describe('Add collection admins', () => { @@ -37,7 +36,7 @@ .send(); const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); - const newAdmin = await createEthAccount(web3); + const newAdmin = createEthAccount(web3); const collectionEvm = evmCollection(web3, owner, collectionIdAddress); await collectionEvm.methods.addCollectionAdmin(newAdmin).send(); const adminList = await api.rpc.unique.adminlist(collectionId); @@ -92,7 +91,7 @@ const collectionEvm = evmCollection(web3, owner, collectionIdAddress); await collectionEvm.methods.addCollectionAdmin(admin).send(); - const user = await createEthAccount(web3); + const user = createEthAccount(web3); await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin})) .to.be.rejectedWith('NoPermission'); @@ -114,7 +113,7 @@ const notAdmin = await createEthAccountWithBalance(api, web3, privateKeyWrapper); const collectionEvm = evmCollection(web3, owner, collectionIdAddress); - const user = await createEthAccount(web3); + const user = createEthAccount(web3); await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin})) .to.be.rejectedWith('NoPermission'); @@ -175,7 +174,7 @@ .send(); const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); - const newAdmin = await createEthAccount(web3); + const newAdmin = createEthAccount(web3); const collectionEvm = evmCollection(web3, owner, collectionIdAddress); await collectionEvm.methods.addCollectionAdmin(newAdmin).send(); { @@ -226,7 +225,7 @@ const admin0 = await createEthAccountWithBalance(api, web3, privateKeyWrapper); await collectionEvm.methods.addCollectionAdmin(admin0).send(); - const admin1 = await createEthAccount(web3); + const admin1 = createEthAccount(web3); await collectionEvm.methods.addCollectionAdmin(admin1).send(); await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0})) @@ -253,7 +252,7 @@ const admin = await createEthAccountWithBalance(api, web3, privateKeyWrapper); await collectionEvm.methods.addCollectionAdmin(admin).send(); - const notAdmin = await createEthAccount(web3); + const notAdmin = createEthAccount(web3); await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin})) .to.be.rejectedWith('NoPermission'); --- a/tests/src/eth/collectionSponsoring.test.ts +++ b/tests/src/eth/collectionSponsoring.test.ts @@ -1,5 +1,5 @@ import {addToAllowListExpectSuccess, bigIntToSub, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers'; -import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub, subToEth} from './util/helpers'; +import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub} from './util/helpers'; import nonFungibleAbi from './nonFungibleAbi.json'; import {expect} from 'chai'; import {evmToAddress} from '@polkadot/util-crypto'; --- a/tests/src/eth/createNFTCollection.test.ts +++ b/tests/src/eth/createNFTCollection.test.ts @@ -181,7 +181,7 @@ }); itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => { - const owner = await createEthAccount(web3); + const owner = createEthAccount(web3); const helper = evmCollectionHelpers(web3, owner); const collectionName = 'A'; const description = 'A'; @@ -194,7 +194,7 @@ itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => { const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notOwner = await createEthAccount(web3); + const notOwner = createEthAccount(web3); const collectionHelpers = evmCollectionHelpers(web3, owner); const result = await collectionHelpers.methods.createNonfungibleCollection('A', 'A', 'A').send(); const {collectionIdAddress} = await getCollectionAddressFromResult(api, result); --- a/tests/src/eth/createRFTCollection.test.ts +++ b/tests/src/eth/createRFTCollection.test.ts @@ -189,7 +189,7 @@ }); itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => { - const owner = await createEthAccount(web3); + const owner = createEthAccount(web3); const helper = evmCollectionHelpers(web3, owner); const collectionName = 'A'; const description = 'A'; @@ -202,7 +202,7 @@ itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => { const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notOwner = await createEthAccount(web3); + const notOwner = createEthAccount(web3); const collectionHelpers = evmCollectionHelpers(web3, owner); const result = await collectionHelpers.methods.createRefungibleCollection('A', 'A', 'A').send(); const {collectionIdAddress} = await getCollectionAddressFromResult(api, result); --- a/tests/src/eth/nesting/nest.test.ts +++ b/tests/src/eth/nesting/nest.test.ts @@ -1,217 +1,220 @@ -import {ApiPromise} from '@polkadot/api'; +import {IKeyringPair} from '@polkadot/types/types'; import {Contract} from 'web3-eth-contract'; -import {expect} from 'chai'; -import Web3 from 'web3'; -import {createEthAccountWithBalance, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, tokenIdToAddress} from '../../eth/util/helpers'; -import nonFungibleAbi from '../nonFungibleAbi.json'; +import {itEth, EthUniqueHelper, usingEthPlaygrounds, expect} from '../util/playgrounds'; + const createNestingCollection = async ( - api: ApiPromise, - web3: Web3, + helper: EthUniqueHelper, owner: string, ): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => { - const collectionHelper = evmCollectionHelpers(web3, owner); - - const result = await collectionHelper.methods - .createNonfungibleCollection('A', 'B', 'C') - .send(); - const {collectionIdAddress: collectionAddress, collectionId} = await getCollectionAddressFromResult(api, result); + const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C'); - const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionAddress, {from: owner, ...GAS_ARGS}); + const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await contract.methods.setCollectionNesting(true).send({from: owner}); return {collectionId, collectionAddress, contract}; }; -describe('Integration Test: EVM Nesting', () => { - itWeb3('NFT: allows an Owner to nest/unnest their token', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const {collectionId, contract} = await createNestingCollection(api, web3, owner); - // Create a token to be nested - const targetNFTTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - targetNFTTokenId, - ).send({from: owner}); - - const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId); - - // Create a nested token - const firstTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - targetNftTokenAddress, - firstTokenId, - ).send({from: owner}); +describe('EVM nesting tests group', () => { + let donor: IKeyringPair; - expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress); - - // Create a token to be nested and nest - const secondTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - secondTokenId, - ).send({from: owner}); - - await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner}); - - expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress); - - // Unnest token back - await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner}); - expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner); + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = privateKey('//Alice'); + }); }); - itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner); - const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner); - await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner}); - - // Create a token to nest into - const targetNftTokenId = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - targetNftTokenId, - ).send({from: owner}); - const nftTokenAddressA1 = tokenIdToAddress(collectionIdA, targetNftTokenId); - - // Create a token for nesting in the same collection as the target - const nftTokenIdA = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - nftTokenIdA, - ).send({from: owner}); - - // Create a token for nesting in a different collection - const nftTokenIdB = await contractB.methods.nextTokenId().call(); - await contractB.methods.mint( - owner, - nftTokenIdB, - ).send({from: owner}); - - // Nest - await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner}); - expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1); - - await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner}); - expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1); - }); -}); - -describe('Negative Test: EVM Nesting', async() => { - itWeb3('NFT: disallows to nest token if nesting is disabled', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const {collectionId, contract} = await createNestingCollection(api, web3, owner); - await contract.methods.setCollectionNesting(false).send({from: owner}); - - // Create a token to nest into - const targetNftTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - targetNftTokenId, - ).send({from: owner}); - - const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNftTokenId); - - // Create a token to nest - const nftTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - nftTokenId, - ).send({from: owner}); - - // Try to nest - await expect(contract.methods - .transfer(targetNftTokenAddress, nftTokenId) - .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest'); - }); - - itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const {collectionId, contract} = await createNestingCollection(api, web3, owner); - - // Mint a token - const targetTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - targetTokenId, - ).send({from: owner}); - const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId); - - // Mint a token belonging to a different account - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - malignant, - tokenId, - ).send({from: owner}); - - // Try to nest one token in another as a non-owner account - await expect(contract.methods - .transfer(targetTokenAddress, tokenId) - .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); - }); - - itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner); - const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner); - - await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner}); - - // Create a token in one collection - const nftTokenIdA = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - nftTokenIdA, - ).send({from: owner}); - const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA); - - // Create a token in another collection belonging to someone else - const nftTokenIdB = await contractB.methods.nextTokenId().call(); - await contractB.methods.mint( - malignant, - nftTokenIdB, - ).send({from: owner}); - - // Try to drag someone else's token into the other collection and nest - await expect(contractB.methods - .transfer(nftTokenAddressA, nftTokenIdB) - .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); + describe('Integration Test: EVM Nesting', () => { + itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionId, contract} = await createNestingCollection(helper, owner); + + // Create a token to be nested + const targetNFTTokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + owner, + targetNFTTokenId, + ).send({from: owner}); + + const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId); + + // Create a nested token + const firstTokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + targetNftTokenAddress, + firstTokenId, + ).send({from: owner}); + + expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress); + + // Create a token to be nested and nest + const secondTokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + owner, + secondTokenId, + ).send({from: owner}); + + await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner}); + + expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress); + + // Unnest token back + await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner}); + expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner); + }); + + itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner); + const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner); + await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner}); + + // Create a token to nest into + const targetNftTokenId = await contractA.methods.nextTokenId().call(); + await contractA.methods.mint( + owner, + targetNftTokenId, + ).send({from: owner}); + const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId); + + // Create a token for nesting in the same collection as the target + const nftTokenIdA = await contractA.methods.nextTokenId().call(); + await contractA.methods.mint( + owner, + nftTokenIdA, + ).send({from: owner}); + + // Create a token for nesting in a different collection + const nftTokenIdB = await contractB.methods.nextTokenId().call(); + await contractB.methods.mint( + owner, + nftTokenIdB, + ).send({from: owner}); + + // Nest + await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner}); + expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1); + + await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner}); + expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1); + }); }); - itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner); - const {contract: contractB} = await createNestingCollection(api, web3, owner); - - await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner}); - - // Create a token in one collection - const nftTokenIdA = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - nftTokenIdA, - ).send({from: owner}); - const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA); - - // Create a token in another collection - const nftTokenIdB = await contractB.methods.nextTokenId().call(); - await contractB.methods.mint( - owner, - nftTokenIdB, - ).send({from: owner}); - - // Try to nest into a token in the other collection, disallowed in the first - await expect(contractB.methods - .transfer(nftTokenAddressA, nftTokenIdB) - .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest'); + describe('Negative Test: EVM Nesting', async() => { + itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionId, contract} = await createNestingCollection(helper, owner); + await contract.methods.setCollectionNesting(false).send({from: owner}); + + // Create a token to nest into + const targetNftTokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + owner, + targetNftTokenId, + ).send({from: owner}); + + const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNftTokenId); + + // Create a token to nest + const nftTokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + owner, + nftTokenId, + ).send({from: owner}); + + // Try to nest + await expect(contract.methods + .transfer(targetNftTokenAddress, nftTokenId) + .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest'); + }); + + itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const malignant = await helper.eth.createAccountWithBalance(donor); + + const {collectionId, contract} = await createNestingCollection(helper, owner); + + // Mint a token + const targetTokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + owner, + targetTokenId, + ).send({from: owner}); + const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId); + + // Mint a token belonging to a different account + const tokenId = await contract.methods.nextTokenId().call(); + await contract.methods.mint( + malignant, + tokenId, + ).send({from: owner}); + + // Try to nest one token in another as a non-owner account + await expect(contract.methods + .transfer(targetTokenAddress, tokenId) + .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); + }); + + itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const malignant = await helper.eth.createAccountWithBalance(donor); + + const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner); + const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner); + + await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner}); + + // Create a token in one collection + const nftTokenIdA = await contractA.methods.nextTokenId().call(); + await contractA.methods.mint( + owner, + nftTokenIdA, + ).send({from: owner}); + const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA); + + // Create a token in another collection belonging to someone else + const nftTokenIdB = await contractB.methods.nextTokenId().call(); + await contractB.methods.mint( + malignant, + nftTokenIdB, + ).send({from: owner}); + + // Try to drag someone else's token into the other collection and nest + await expect(contractB.methods + .transfer(nftTokenAddressA, nftTokenIdB) + .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); + }); + + itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner); + const {contract: contractB} = await createNestingCollection(helper, owner); + + await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner}); + + // Create a token in one collection + const nftTokenIdA = await contractA.methods.nextTokenId().call(); + await contractA.methods.mint( + owner, + nftTokenIdA, + ).send({from: owner}); + const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA); + + // Create a token in another collection + const nftTokenIdB = await contractB.methods.nextTokenId().call(); + await contractB.methods.mint( + owner, + nftTokenIdB, + ).send({from: owner}); + + // Try to nest into a token in the other collection, disallowed in the first + await expect(contractB.methods + .transfer(nftTokenAddressA, nftTokenIdB) + .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest'); + }); }); }); --- a/tests/src/eth/payable.test.ts +++ b/tests/src/eth/payable.test.ts @@ -14,97 +14,91 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {expect} from 'chai'; -import {submitTransactionAsync} from '../substrate/substrate-api'; -import {createEthAccountWithBalance, deployCollector, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers'; -import {evmToAddress} from '@polkadot/util-crypto'; -import {getGenericResult, UNIQUE} from '../util/helpers'; -import {getBalanceSingle, transferBalanceExpectSuccess} from '../substrate/get-balance'; +import {IKeyringPair} from '@polkadot/types/types'; + +import {itEth, expect, usingEthPlaygrounds} from './util/playgrounds'; describe('EVM payable contracts', () => { - itWeb3('Evm contract can receive wei from eth account', async ({api, web3, privateKeyWrapper}) => { - const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const contract = await deployCollector(web3, deployer); + let donor: IKeyringPair; - await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', ...GAS_ARGS}); + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = privateKey('//Alice'); + }); + }); + + itEth('Evm contract can receive wei from eth account', async ({helper}) => { + const deployer = await helper.eth.createAccountWithBalance(donor); + const contract = await helper.eth.deployCollectorContract(deployer); + + const web3 = helper.getWeb3(); + + await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', gas: helper.eth.DEFAULT_GAS}); expect(await contract.methods.getCollected().call()).to.be.equal('10000'); }); - itWeb3('Evm contract can receive wei from substrate account', async ({api, web3, privateKeyWrapper}) => { - const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const contract = await deployCollector(web3, deployer); - const alice = privateKeyWrapper('//Alice'); + itEth('Evm contract can receive wei from substrate account', async ({helper}) => { + const deployer = await helper.eth.createAccountWithBalance(donor); + const contract = await helper.eth.deployCollectorContract(deployer); + const [alice] = await helper.arrange.createAccounts([10n], donor); + + const weiCount = '10000'; // Transaction fee/value will be payed from subToEth(sender) evm balance, // which is backed by evmToAddress(subToEth(sender)) substrate balance - await transferBalanceToEth(api, alice, subToEth(alice.address)); + await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address), 5n); + - { - const tx = api.tx.evm.call( - subToEth(alice.address), - contract.options.address, - contract.methods.giveMoney().encodeABI(), - '10000', - GAS_ARGS.gas, - await web3.eth.getGasPrice(), - null, - null, - [], - ); - const events = await submitTransactionAsync(alice, tx); - const result = getGenericResult(events); - expect(result.success).to.be.true; - } + await helper.eth.callEVM(alice, contract.options.address, contract.methods.giveMoney().encodeABI(), weiCount); - expect(await contract.methods.getCollected().call()).to.be.equal('10000'); + expect(await contract.methods.getCollected().call()).to.be.equal(weiCount); }); // We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible - itWeb3('Wei sent directly to backing storage of evm contract balance is unaccounted', async({api, web3, privateKeyWrapper}) => { - const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const contract = await deployCollector(web3, deployer); - const alice = privateKeyWrapper('//Alice'); + itEth('Wei sent directly to backing storage of evm contract balance is unaccounted', async({helper}) => { + const deployer = await helper.eth.createAccountWithBalance(donor); + const contract = await helper.eth.deployCollectorContract(deployer); + const [alice] = await helper.arrange.createAccounts([10n], donor); + + const weiCount = 10_000n; - await transferBalanceExpectSuccess(api, alice, evmToAddress(contract.options.address), '10000'); + await helper.eth.transferBalanceFromSubstrate(alice, contract.options.address, weiCount, false); - expect(await contract.methods.getUnaccounted().call()).to.be.equal('10000'); + expect(await contract.methods.getUnaccounted().call()).to.be.equal(weiCount.toString()); }); - itWeb3('Balance can be retrieved from evm contract', async({api, web3, privateKeyWrapper}) => { - const FEE_BALANCE = 1000n * UNIQUE; - const CONTRACT_BALANCE = 1n * UNIQUE; + itEth('Balance can be retrieved from evm contract', async({helper, privateKey}) => { + const FEE_BALANCE = 10n * helper.balance.getOneTokenNominal(); + const CONTRACT_BALANCE = 1n * helper.balance.getOneTokenNominal(); + + const deployer = await helper.eth.createAccountWithBalance(donor); + const contract = await helper.eth.deployCollectorContract(deployer); + const [alice] = await helper.arrange.createAccounts([20n], donor); - const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const contract = await deployCollector(web3, deployer); - const alice = privateKeyWrapper('//Alice'); + const web3 = helper.getWeb3(); - await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), ...GAS_ARGS}); + await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS}); - const receiver = privateKeyWrapper(`//Receiver${Date.now()}`); + const receiver = privateKey(`//Receiver${Date.now()}`); // First receive balance on eth balance of bob { - const ethReceiver = subToEth(receiver.address); + const ethReceiver = helper.address.substrateToEth(receiver.address); expect(await web3.eth.getBalance(ethReceiver)).to.be.equal('0'); await contract.methods.withdraw(ethReceiver).send({from: deployer}); expect(await web3.eth.getBalance(ethReceiver)).to.be.equal(CONTRACT_BALANCE.toString()); } // Some balance is required to pay fee for evm.withdraw call - await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString()); + await helper.balance.transferToSubstrate(alice, receiver.address, FEE_BALANCE); + // await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString()); // Withdraw balance from eth to substrate { - const initialReceiverBalance = await getBalanceSingle(api, receiver.address); - const tx = api.tx.evm.withdraw( - subToEth(receiver.address), - CONTRACT_BALANCE.toString(), - ); - const events = await submitTransactionAsync(receiver, tx); - const result = getGenericResult(events); - expect(result.success).to.be.true; - const finalReceiverBalance = await getBalanceSingle(api, receiver.address); + const initialReceiverBalance = await helper.balance.getSubstrate(receiver.address); + await helper.executeExtrinsic(receiver, 'api.tx.evm.withdraw', [helper.address.substrateToEth(receiver.address), CONTRACT_BALANCE.toString()], true); + const finalReceiverBalance = await helper.balance.getSubstrate(receiver.address); expect(finalReceiverBalance > initialReceiverBalance).to.be.true; } --- a/tests/src/eth/reFungibleToken.test.ts +++ b/tests/src/eth/reFungibleToken.test.ts @@ -15,7 +15,7 @@ // along with Unique Network. If not, see . import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers'; -import {collectionIdFromAddress, collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createNonfungibleCollection, createRefungibleCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueNFT, uniqueRefungible, uniqueRefungibleToken} from './util/helpers'; +import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRefungibleCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; --- /dev/null +++ b/tests/src/eth/util/playgrounds/index.ts @@ -0,0 +1,49 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +import {IKeyringPair} from '@polkadot/types/types'; + +import config from '../../../config'; + +import {EthUniqueHelper} from './unique.dev'; +import {SilentLogger, SilentConsole} from '../../../util/playgrounds/unique.dev'; + +export {EthUniqueHelper} from './unique.dev'; + +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); +export const expect = chai.expect; + +export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise) => { + const silentConsole = new SilentConsole(); + silentConsole.enable(); + + const helper = new EthUniqueHelper(new SilentLogger()); + + try { + await helper.connect(config.substrateUrl); + await helper.connectWeb3(config.substrateUrl); + const ss58Format = helper.chain.getChainProperties().ss58Format; + const privateKey = (seed: string) => helper.util.fromSeed(seed, ss58Format); + await code(helper, privateKey); + } + finally { + await helper.disconnect(); + await helper.disconnectWeb3(); + silentConsole.disable(); + } +}; + +export async function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) { + let i: any = it; + if (opts.only) i = i.only; + else if (opts.skip) i = i.skip; + i(name, async () => { + await usingEthPlaygrounds(async (helper, privateKey) => { + await cb({helper, privateKey}); + }); + }); +} +itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itEth(name, cb, {only: true}); +itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itEth(name, cb, {skip: true}); \ No newline at end of file --- /dev/null +++ b/tests/src/eth/util/playgrounds/types.ts @@ -0,0 +1,9 @@ +export interface ContractImports { + solPath: string; + fsPath: string; +} + +export interface CompiledContract { + abi: any; + object: string; +} \ No newline at end of file --- /dev/null +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -0,0 +1,268 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +/* eslint-disable function-call-argument-newline */ + +import {readFile} from 'fs/promises'; + +import Web3 from 'web3'; +import {WebsocketProvider} from 'web3-core'; +import {Contract} from 'web3-eth-contract'; + +import * as solc from 'solc'; + +import {evmToAddress} from '@polkadot/util-crypto'; +import {IKeyringPair} from '@polkadot/types/types'; + +import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev'; + +import {ContractImports, CompiledContract} from './types'; + +// Native contracts ABI +import collectionHelpersAbi from '../../collectionHelpersAbi.json'; +import fungibleAbi from '../../fungibleAbi.json'; +import nonFungibleAbi from '../../nonFungibleAbi.json'; +import refungibleAbi from '../../reFungibleAbi.json'; +import refungibleTokenAbi from '../../reFungibleTokenAbi.json'; +import contractHelpersAbi from './../contractHelpersAbi.json'; + +class EthGroupBase { + helper: EthUniqueHelper; + + constructor(helper: EthUniqueHelper) { + this.helper = helper; + } +} + + +class ContractGroup extends EthGroupBase { + async findImports(imports?: ContractImports[]){ + if(!imports) return function(path: string) { + return {error: `File not found: ${path}`}; + }; + + const knownImports = {} as any; + for(const imp of imports) { + knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString(); + } + + return function(path: string) { + if(knownImports.hasOwnPropertyDescriptor(path)) return {contents: knownImports[path]}; + return {error: `File not found: ${path}`}; + }; + } + + async compile(name: string, src: string, imports?: ContractImports[]): Promise { + const out = JSON.parse(solc.compile(JSON.stringify({ + language: 'Solidity', + sources: { + [`${name}.sol`]: { + content: src, + }, + }, + settings: { + outputSelection: { + '*': { + '*': ['*'], + }, + }, + }, + }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name]; + + return { + abi: out.abi, + object: '0x' + out.evm.bytecode.object, + }; + } + + async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[]): Promise { + const compiledContract = await this.compile(name, src, imports); + return this.deployByAbi(signer, compiledContract.abi, compiledContract.object); + } + + async deployByAbi(signer: string, abi: any, object: string): Promise { + const web3 = this.helper.getWeb3(); + const contract = new web3.eth.Contract(abi, undefined, { + data: object, + from: signer, + gas: this.helper.eth.DEFAULT_GAS, + }); + return await contract.deploy({data: object}).send({from: signer}); + } + +} + +class NativeContractGroup extends EthGroupBase { + + contractHelpers(caller: string): Contract { + const web3 = this.helper.getWeb3(); + return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, gas: this.helper.eth.DEFAULT_GAS}); + } + + collectionHelpers(caller: string) { + const web3 = this.helper.getWeb3(); + return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS}); + } + + collection(address: string, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract { + const abi = { + 'nft': nonFungibleAbi, + 'rft': refungibleAbi, + 'ft': fungibleAbi, + }[mode]; + const web3 = this.helper.getWeb3(); + return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})}); + } + + rftTokenByAddress(address: string, caller?: string): Contract { + const web3 = this.helper.getWeb3(); + return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})}); + } + + rftToken(collectionId: number, tokenId: number, caller?: string): Contract { + return this.rftTokenByAddress(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller); + } +} + + +class EthGroup extends EthGroupBase { + DEFAULT_GAS = 2_500_000; + + createAccount() { + const web3 = this.helper.getWeb3(); + const account = web3.eth.accounts.create(); + web3.eth.accounts.wallet.add(account.privateKey); + return account.address; + } + + async createAccountWithBalance(donor: IKeyringPair, amount=1000n) { + const account = this.createAccount(); + await this.transferBalanceFromSubstrate(donor, account, amount); + + return account; + } + + async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount=1000n, inTokens=true) { + return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n)); + } + + async callEVM(signer: IKeyringPair, contractAddress: string, abi: any, value: string, gasLimit?: number) { + if(!gasLimit) gasLimit = this.DEFAULT_GAS; + const web3 = this.helper.getWeb3(); + const gasPrice = await web3.eth.getGasPrice(); + // TODO: check execution status + await this.helper.executeExtrinsic( + signer, + 'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []], + true, + ); + } + + async createNonfungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { + const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); + + const result = await collectionHelper.methods.createNonfungibleCollection(name, description, tokenPrefix).send(); + + const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + + return {collectionId, collectionAddress}; + } + + async deployCollectorContract(signer: string): Promise { + return await this.helper.ethContract.deployByCode(signer, 'Collector', ` + // SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.8.6; + + contract Collector { + uint256 collected; + fallback() external payable { + giveMoney(); + } + function giveMoney() public payable { + collected += msg.value; + } + function getCollected() public view returns (uint256) { + return collected; + } + function getUnaccounted() public view returns (uint256) { + return address(this).balance - collected; + } + + function withdraw(address payable target) public { + target.transfer(collected); + collected = 0; + } + } + `); + } +} + + +class EthAddressGroup extends EthGroupBase { + extractCollectionId(address: string): number { + if (!(address.length === 42 || address.length === 40)) throw new Error('address wrong format'); + return parseInt(address.substr(address.length - 8), 16); + } + + fromCollectionId(collectionId: number): string { + if (collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow'); + return Web3.utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`); + } + + extractTokenId(address: string): {collectionId: number, tokenId: number} { + if (!address.startsWith('0x')) + throw 'address not starts with "0x"'; + if (address.length > 42) + throw 'address length is more than 20 bytes'; + return { + collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)), + tokenId: Number('0x' + address.substring(address.length - 8)), + }; + } + + fromTokenId(collectionId: number, tokenId: number): string { + return this.helper.util.getNestingTokenAddress(collectionId, tokenId); + } + + normalizeAddress(address: string): string { + return '0x' + address.substring(address.length - 40); + } +} + + +export class EthUniqueHelper extends DevUniqueHelper { + web3: Web3 | null = null; + web3Provider: WebsocketProvider | null = null; + + eth: EthGroup; + ethAddress: EthAddressGroup; + ethNativeContract: NativeContractGroup; + ethContract: ContractGroup; + + constructor(logger: { log: (msg: any, level: any) => void, level: any }) { + super(logger); + this.eth = new EthGroup(this); + this.ethAddress = new EthAddressGroup(this); + this.ethNativeContract = new NativeContractGroup(this); + this.ethContract = new ContractGroup(this); + } + + getWeb3(): Web3 { + if(this.web3 === null) throw Error('Web3 not connected'); + return this.web3; + } + + async connectWeb3(wsEndpoint: string) { + if(this.web3 !== null) return; + this.web3Provider = new Web3.providers.WebsocketProvider(wsEndpoint); + this.web3 = new Web3(this.web3Provider); + } + + async disconnectWeb3() { + if(this.web3 === null) return; + this.web3Provider?.connection.close(); + this.web3 = null; + } +} + \ No newline at end of file --- a/tests/src/substrate/substrate-api.ts +++ b/tests/src/substrate/substrate-api.ts @@ -25,6 +25,8 @@ import privateKey from './privateKey'; import promisifySubstrate from './promisify-substrate'; +import {SilentConsole} from '../util/playgrounds/unique.dev'; + function defaultApiOptions(): ApiOptions { @@ -74,26 +76,9 @@ settings = settings || defaultApiOptions(); const api: ApiPromise = new ApiPromise(settings); let result: T = null as unknown as T; - - // TODO: Remove, this is temporary: Filter unneeded API output - // (Jaco promised it will be removed in the next version) - const consoleErr = console.error; - const consoleLog = console.log; - const consoleWarn = console.warn; - const outFn = (printer: any) => (...args: any[]) => { - for (const arg of args) { - if (typeof arg !== 'string') - continue; - if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure') - return; - } - printer(...args); - }; - - console.error = outFn(consoleErr.bind(console)); - console.log = outFn(consoleLog.bind(console)); - console.warn = outFn(consoleWarn.bind(console)); + const silentConsole = new SilentConsole(); + silentConsole.enable(); try { await promisifySubstrate(api, async () => { @@ -106,9 +91,7 @@ })(); } finally { await api.disconnect(); - console.error = consoleErr; - console.log = consoleLog; - console.warn = consoleWarn; + silentConsole.disable(); } return result as T; } --- a/tests/src/util/playgrounds/index.ts +++ b/tests/src/util/playgrounds/index.ts @@ -4,37 +4,13 @@ import {IKeyringPair} from '@polkadot/types/types'; import config from '../../config'; import '../../interfaces/augment-api-events'; -import {DevUniqueHelper} from './unique.dev'; +import {DevUniqueHelper, SilentLogger, SilentConsole} from './unique.dev'; -class SilentLogger { - log(msg: any, level: any): void { } - level = { - ERROR: 'ERROR' as const, - WARNING: 'WARNING' as const, - INFO: 'INFO' as const, - }; -} export const usingPlaygrounds = async (code: (helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise) => { - // TODO: Remove, this is temporary: Filter unneeded API output - // (Jaco promised it will be removed in the next version) - const consoleErr = console.error; - const consoleLog = console.log; - const consoleWarn = console.warn; + const silentConsole = new SilentConsole(); + silentConsole.enable(); - const outFn = (printer: any) => (...args: any[]) => { - for (const arg of args) { - if (typeof arg !== 'string') - continue; - if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure') - return; - } - printer(...args); - }; - - console.error = outFn(consoleErr.bind(console)); - console.log = outFn(consoleLog.bind(console)); - console.warn = outFn(consoleWarn.bind(console)); const helper = new DevUniqueHelper(new SilentLogger()); try { @@ -45,8 +21,6 @@ } finally { await helper.disconnect(); - console.error = consoleErr; - console.log = consoleLog; - console.warn = consoleWarn; + silentConsole.disable(); } }; --- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -5,10 +5,56 @@ import {UniqueHelper} from './unique'; import {ApiPromise, WsProvider} from '@polkadot/api'; import * as defs from '../../interfaces/definitions'; -import {TSigner} from './types'; import {IKeyringPair} from '@polkadot/types/types'; +export class SilentLogger { + log(_msg: any, _level: any): void { } + level = { + ERROR: 'ERROR' as const, + WARNING: 'WARNING' as const, + INFO: 'INFO' as const, + }; +} + + +export class SilentConsole { + // TODO: Remove, this is temporary: Filter unneeded API output + // (Jaco promised it will be removed in the next version) + consoleErr: any; + consoleLog: any; + consoleWarn: any; + + constructor() { + this.consoleErr = console.error; + this.consoleLog = console.log; + this.consoleWarn = console.warn; + } + + enable() { + const outFn = (printer: any) => (...args: any[]) => { + for (const arg of args) { + if (typeof arg !== 'string') + continue; + if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis: UniqueApi/2, RmrkApi/1') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure') + return; + } + printer(...args); + }; + + console.error = outFn(this.consoleErr.bind(console)); + console.log = outFn(this.consoleLog.bind(console)); + console.warn = outFn(this.consoleWarn.bind(console)); + } + + disable() { + console.error = this.consoleErr; + console.log = this.consoleLog; + console.warn = this.consoleWarn; + } +} + + export class DevUniqueHelper extends UniqueHelper { /** * Arrange methods for tests @@ -20,7 +66,7 @@ this.arrange = new ArrangeGroup(this); } - async connect(wsEndpoint: string, listeners?: any): Promise { + async connect(wsEndpoint: string, _listeners?: any): Promise { const wsProvider = new WsProvider(wsEndpoint); this.api = new ApiPromise({ provider: wsProvider, @@ -85,7 +131,7 @@ } } - await Promise.all(transactions).catch(e => {}); + await Promise.all(transactions).catch(_e => {}); //#region TODO remove this region, when nonce problem will be solved const checkBalances = async () => { @@ -113,13 +159,14 @@ return accounts; }; - + /** * Wait for specified bnumber of blocks * @param blocksCount number of blocks to wait * @returns */ async waitNewBlocks(blocksCount = 1): Promise { + // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve) => { const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => { if (blocksCount > 0) { --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -91,9 +91,9 @@ return encodeAddress(decodeAddress(address), ss58Format); } - static extractCollectionIdFromCreationResult(creationResult: ITransactionResult, label = 'new collection') { + static extractCollectionIdFromCreationResult(creationResult: ITransactionResult) { if (creationResult.status !== this.transactionStatus.SUCCESS) { - throw Error(`Unable to create collection for ${label}`); + throw Error('Unable to create collection!'); } let collectionId = null; @@ -104,15 +104,15 @@ }); if (collectionId === null) { - throw Error(`No CollectionCreated event for ${label}`); + throw Error('No CollectionCreated event was found!'); } return collectionId; } - static extractTokensFromCreationResult(creationResult: ITransactionResult, label = 'new tokens') { + static extractTokensFromCreationResult(creationResult: ITransactionResult) { if (creationResult.status !== this.transactionStatus.SUCCESS) { - throw Error(`Unable to create tokens for ${label}`); + throw Error('Unable to create tokens!'); } let success = false; const tokens = [] as any; @@ -130,9 +130,9 @@ return {success, tokens}; } - static extractTokensFromBurnResult(burnResult: ITransactionResult, label = 'burned tokens') { + static extractTokensFromBurnResult(burnResult: ITransactionResult) { if (burnResult.status !== this.transactionStatus.SUCCESS) { - throw Error(`Unable to burn tokens for ${label}`); + throw Error('Unable to burn tokens!'); } let success = false; const tokens = [] as any; @@ -150,7 +150,7 @@ return {success, tokens}; } - static findCollectionInEvents(events: {event: IChainEvent}[], collectionId: number, expectedSection: string, expectedMethod: string, label?: string) { + static findCollectionInEvents(events: {event: IChainEvent}[], collectionId: number, expectedSection: string, expectedMethod: string) { let eventId = null; events.forEach(({event: {data, method, section}}) => { if ((section === expectedSection) && (method === expectedMethod)) { @@ -159,7 +159,7 @@ }); if (eventId === null) { - throw Error(`No ${expectedMethod} event for ${label}`); + throw Error(`No ${expectedMethod} event was found!`); } return eventId === collectionId; } @@ -317,6 +317,7 @@ if(options !== null) return transaction.signAndSend(sender, options, callback); return transaction.signAndSend(sender, callback); }; + // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { try { const unsub = await sign((result: any) => { @@ -364,7 +365,7 @@ return call(...params); } - async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=false, failureMessage='expected success') { + async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=false/*, failureMessage='expected success'*/) { if(this.api === null) throw Error('API not initialized'); if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`); @@ -388,6 +389,7 @@ type: this.chainLogType.EXTRINSIC, status: result.status, call: extrinsic, + signer: this.getSignerAddress(sender), params, } as IUniqueHelperLog; @@ -396,7 +398,7 @@ this.chainLog.push(log); - if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) throw Error(failureMessage); + if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) throw Error(`${result.moduleError}`); return result; } @@ -556,19 +558,17 @@ * * @param signer keyring of signer * @param collectionId ID of collection - * @param label extra label for log * @example await helper.collection.burn(aliceKeyring, 3); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async burn(signer: TSigner, collectionId: number, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async burn(signer: TSigner, collectionId: number): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.destroyCollection', [collectionId], - true, `Unable to burn collection for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed'); } /** @@ -577,19 +577,17 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param sponsorAddress Sponsor substrate address - * @param label extra label for log * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...") * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress], - true, `Unable to set collection sponsor for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet'); } /** @@ -597,19 +595,17 @@ * * @param signer keyring of signer * @param collectionId ID of collection - * @param label extra label for log * @example confirmSponsorship(aliceKeyring, 10) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async confirmSponsorship(signer: TSigner, collectionId: number, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async confirmSponsorship(signer: TSigner, collectionId: number): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.confirmSponsorship', [collectionId], - true, `Unable to confirm collection sponsorship for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed'); } /** @@ -618,7 +614,6 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param limits collection limits object - * @param label extra label for log * @example * await setLimits( * aliceKeyring, @@ -630,15 +625,14 @@ * ) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.setCollectionLimits', [collectionId, limits], - true, `Unable to set collection limits for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet'); } /** @@ -647,19 +641,17 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param ownerAddress substrate address of new owner - * @param label extra label for log * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...") * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress], - true, `Unable to change collection owner for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged'); } /** @@ -668,59 +660,71 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param adminAddressObj Administrator address (substrate or ethereum) - * @param label extra label for log * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj], - true, `Unable to add collection admin for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded'); } /** + * Removes a collection administrator. + * + * @param signer keyring of signer + * @param collectionId ID of collection + * @param adminAddressObj Administrator address (substrate or ethereum) + * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}) + * @returns ```true``` if extrinsic success, otherwise ```false``` + */ + async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise { + const result = await this.helper.executeExtrinsic( + signer, + 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj], + true, + ); + + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved'); + } + + /** * Adds an address to allow list * @param signer keyring of signer * @param collectionId ID of collection * @param addressObj address to add to the allow list - * @param label extra label for log * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.addToAllowList', [collectionId, addressObj], - true, `Unable to add address to allow list for ${label}`, + true, ); return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded'); } /** - * Removes a collection administrator. + * Removes an address from allow list * * @param signer keyring of signer * @param collectionId ID of collection - * @param adminAddressObj Administrator address (substrate or ethereum) - * @param label extra label for log - * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}) + * @param addressObj address to remove from the allow list * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise { const result = await this.helper.executeExtrinsic( signer, - 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj], - true, `Unable to remove collection admin for ${label}`, + 'api.tx.unique.removeFromAllowList', [collectionId, addressObj], + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved'); } /** @@ -729,19 +733,17 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param permissions collection permissions object - * @param label extra label for log * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}}); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.setCollectionPermissions', [collectionId, permissions], - true, `Unable to set collection permissions for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet'); } /** @@ -750,12 +752,11 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param permissions nesting permissions object - * @param label extra label for log * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true}); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions, label?: string): Promise { - return await this.setPermissions(signer, collectionId, {nesting: permissions}, label); + async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise { + return await this.setPermissions(signer, collectionId, {nesting: permissions}); } /** @@ -763,12 +764,11 @@ * * @param signer keyring of signer * @param collectionId ID of collection - * @param label extra label for log * @example disableNesting(aliceKeyring, 10); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async disableNesting(signer: TSigner, collectionId: number, label?: string): Promise { - return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}}, label); + async disableNesting(signer: TSigner, collectionId: number): Promise { + return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}}); } /** @@ -777,19 +777,17 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param properties array of property objects - * @param label extra label for log * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async setProperties(signer: TSigner, collectionId: number, properties: IProperty[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.setCollectionProperties', [collectionId, properties], - true, `Unable to set collection properties for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet'); } /** @@ -798,19 +796,17 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param propertyKeys array of property keys to delete - * @param label * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys], - true, `Unable to delete collection properties for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted'); } /** @@ -828,7 +824,7 @@ const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount], - true, `Unable to transfer token #${tokenId} from collection #${collectionId}`, + true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`, ); return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount); @@ -851,7 +847,7 @@ const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount], - true, `Unable to transfer token #${tokenId} from collection #${collectionId}`, + true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`, ); return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount); } @@ -863,22 +859,20 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token - * @param label * @param amount amount of tokens to be burned. For NFT must be set to 1n * @example burnToken(aliceKeyring, 10, 5); * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null``` */ - async burnToken(signer: TSigner, collectionId: number, tokenId: number, label?: string, amount=1n): Promise<{ + async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<{ success: boolean, token: number | null }> { - if(typeof label === 'undefined') label = `collection #${collectionId}`; const burnResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.burnItem', [collectionId, tokenId, amount], - true, `Unable to burn token for ${label}`, + true, // `Unable to burn token for ${label}`, ); - const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult, label); + const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult); if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens'); return {success: burnedTokens.success, token: burnedTokens.tokens.length > 0 ? burnedTokens.tokens[0] : null}; } @@ -890,19 +884,17 @@ * @param collectionId ID of collection * @param fromAddressObj address on behalf of which the token will be burnt * @param tokenId ID of token - * @param label * @param amount amount of tokens to be burned. For NFT must be set to 1n * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."}) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async burnTokenFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, tokenId: number, label?: string, amount=1n): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async burnTokenFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, tokenId: number, amount=1n): Promise { const burnResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount], - true, `Unable to burn token from for ${label}`, + true, // `Unable to burn token from for ${label}`, ); - const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult, label); + const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult); return burnedTokens.success && burnedTokens.tokens.length > 0; } @@ -912,28 +904,27 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token - * @param toAddressObj - * @param label + * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens * @param amount amount of token to be approved. For NFT must be set to 1n * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, label?: string, amount=1n) { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) { const approveResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount], - true, `Unable to approve token for ${label}`, + true, // `Unable to approve token for ${label}`, ); - return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved', label); + return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved'); } /** - * Get the amount of token pieces approved to transfer + * Get the amount of token pieces approved to transfer or burn. Normally 0. + * * @param collectionId ID of collection * @param tokenId ID of token - * @param toAccountObj - * @param fromAccountObj + * @param toAccountObj address which is approved to use token pieces + * @param fromAccountObj address which may have allowed the use of its owned tokens * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."}) * @returns number of approved to transfer pieces */ @@ -942,7 +933,8 @@ } /** - * Get the last created token id + * Get the last created token ID in a collection + * * @param collectionId ID of collection * @example getLastTokenId(10); * @returns id of the last created token @@ -953,6 +945,7 @@ /** * Check if token exists + * * @param collectionId ID of collection * @param tokenId ID of token * @example isTokenExists(10, 20); @@ -978,14 +971,15 @@ /** * Get token data + * * @param collectionId ID of collection * @param tokenId ID of token - * @param blockHashAt - * @param propertyKeys + * @param propertyKeys optionally filter the token properties to only these keys + * @param blockHashAt optionally query the data at some block with this hash * @example getToken(10, 5); * @returns human readable token data */ - async getToken(collectionId: number, tokenId: number, blockHashAt?: string, propertyKeys?: string[]): Promise<{ + async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{ properties: IProperty[]; owner: ICrossAccountId; normalizedOwner: ICrossAccountId; @@ -995,7 +989,7 @@ tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]); } else { - if(typeof propertyKeys === 'undefined') { + if(propertyKeys.length == 0) { const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman(); if(!collection) return null; propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key); @@ -1014,45 +1008,43 @@ /** * Set permissions to change token properties + * * @param signer keyring of signer * @param collectionId ID of collection * @param permissions permissions to change a property by the collection owner or admin - * @param label * @example setTokenPropertyPermissions( * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}] * ) * @returns true if extrinsic success otherwise false */ - async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions], - true, `Unable to set token property permissions for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet'); } /** * Set token properties + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token - * @param properties - * @param label + * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}]) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[], label?: string): Promise { - if(typeof label === 'undefined') label = `token #${tokenId} from collection #${collectionId}`; + async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties], - true, `Unable to set token properties for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet'); } /** @@ -1061,31 +1053,29 @@ * @param collectionId ID of collection * @param tokenId ID of token * @param propertyKeys property keys to be deleted - * @param label * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"]) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[], label?: string): Promise { - if(typeof label === 'undefined') label = `token #${tokenId} from collection #${collectionId}`; + async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise { const result = await this.helper.executeExtrinsic( signer, 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys], - true, `Unable to delete token properties for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted', label); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted'); } /** * Mint new collection + * * @param signer keyring of signer * @param collectionOptions basic collection options and properties * @param mode NFT or RFT type of a collection - * @param errorLabel * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT") * @returns object of the created collection */ - async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT', errorLabel = 'Unable to mint collection'): Promise { + async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise { collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null}; for (const key of ['name', 'description', 'tokenPrefix']) { @@ -1094,16 +1084,16 @@ const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createCollectionEx', [collectionOptions], - true, errorLabel, + true, // errorLabel, ); - return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult, errorLabel)); + return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult)); } - getCollectionObject(collectionId: number): any { + getCollectionObject(_collectionId: number): any { return null; } - getTokenObject(collectionId: number, tokenId: number): any { + getTokenObject(_collectionId: number, _tokenId: number): any { return null; } } @@ -1135,7 +1125,7 @@ * Get token's owner * @param collectionId ID of collection * @param tokenId ID of token - * @param blockHashAt + * @param blockHashAt optionally query the data at the block with this hash * @example getTokenOwner(10, 5); * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."} */ @@ -1217,7 +1207,7 @@ * Get tokens nested in the provided token * @param collectionId ID of collection * @param tokenId ID of token - * @param blockHashAt + * @param blockHashAt optionally query the data at the block with this hash * @example getTokenChildren(10, 5); * @returns tokens whose depth of nesting is <= 5 */ @@ -1239,15 +1229,14 @@ * @param signer keyring of signer * @param tokenObj token to be nested * @param rootTokenObj token to be parent - * @param label * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, label='nest token'): Promise { + async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise { const rootTokenAddress = {Ethereum: this.helper.util.getNestingTokenAddress(rootTokenObj.collectionId, rootTokenObj.tokenId)}; const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress); if(!result) { - throw Error(`Unable to nest token for ${label}`); + throw Error('Unable to nest token!'); } return result; } @@ -1258,15 +1247,14 @@ * @param tokenObj token to unnest * @param rootTokenObj parent of a token * @param toAddressObj address of a new token owner - * @param label * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."}); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId, label='unnest token'): Promise { + async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise { const rootTokenAddress = {Ethereum: this.helper.util.getNestingTokenAddress(rootTokenObj.collectionId, rootTokenObj.tokenId)}; const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj); if(!result) { - throw Error(`Unable to unnest token for ${label}`); + throw Error('Unable to unnest token!'); } return result; } @@ -1275,7 +1263,6 @@ * Mint new collection * @param signer keyring of signer * @param collectionOptions Collection options - * @param label * @example * mintCollection(aliceKeyring, { * name: 'New', @@ -1284,19 +1271,17 @@ * }) * @returns object of the created collection */ - async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, label = 'new collection'): Promise { - return await super.mintCollection(signer, collectionOptions, 'NFT', `Unable to mint NFT collection for ${label}`) as UniqueNFTCollection; + async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions): Promise { + return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection; } /** * Mint new token * @param signer keyring of signer * @param data token data - * @param label * @returns created token object */ - async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${data.collectionId}`; + async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise { const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, { @@ -1304,9 +1289,9 @@ properties: data.properties, }, }], - true, `Unable to mint NFT token for ${label}`, + true, ); - const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult, label); + const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult); if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens'); if (createdTokens.tokens.length < 1) throw Error('No tokens minted'); return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId); @@ -1317,7 +1302,6 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokens array of tokens with owner and properties - * @param label * @example * mintMultipleTokens(aliceKeyring, 10, [{ * owner: {Substrate: "5DyN4Y92vZCjv38fg..."}, @@ -1328,15 +1312,14 @@ * }]); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise { const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}], - true, `Unable to mint NFT tokens for ${label}`, + true, ); const collection = this.getCollectionObject(collectionId); - return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); + return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); } /** @@ -1345,7 +1328,6 @@ * @param collectionId ID of collection * @param owner tokens owner * @param tokens array of tokens with owner and properties - * @param label * @example * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{ * properties: [{ @@ -1358,8 +1340,7 @@ * }]); * @returns array of newly created tokens */ - async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise { const rawTokens = []; for (const token of tokens) { const raw = {NFT: {properties: token.properties}}; @@ -1368,10 +1349,10 @@ const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens], - true, `Unable to mint NFT tokens for ${label}`, + true, ); const collection = this.getCollectionObject(collectionId); - return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); + return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); } /** @@ -1379,12 +1360,11 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token - * @param label * @example burnToken(aliceKeyring, 10, 5); * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null``` */ - async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, label?: string): Promise<{ success: boolean; token: number | null; }> { - return await super.burnToken(signer, collectionId, tokenId, label, 1n); + async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number): Promise<{ success: boolean; token: number | null; }> { + return await super.burnToken(signer, collectionId, tokenId, 1n); } /** @@ -1394,12 +1374,11 @@ * @param collectionId ID of collection * @param tokenId ID of token * @param toAddressObj address to approve - * @param label * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, label?: string) { - return super.approveToken(signer, collectionId, tokenId, toAddressObj, label, 1n); + async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) { + return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n); } } @@ -1459,7 +1438,7 @@ * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=100n): Promise { + async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise { return await super.transferToken(signer, collectionId, tokenId, addressObj, amount); } @@ -1474,7 +1453,7 @@ * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=100n): Promise { + async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise { return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount); } @@ -1482,7 +1461,6 @@ * Mint new collection * @param signer keyring of signer * @param collectionOptions Collection options - * @param label * @example * mintCollection(aliceKeyring, { * name: 'New', @@ -1491,20 +1469,18 @@ * }) * @returns object of the created collection */ - async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, label = 'new collection'): Promise { - return await super.mintCollection(signer, collectionOptions, 'RFT', `Unable to mint RFT collection for ${label}`) as UniqueRFTCollection; + async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions): Promise { + return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection; } /** * Mint new token * @param signer keyring of signer * @param data token data - * @param label * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n}); * @returns created token object */ - async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${data.collectionId}`; + async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise { const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, { @@ -1513,24 +1489,23 @@ properties: data.properties, }, }], - true, `Unable to mint RFT token for ${label}`, + true, ); - const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult, label); + const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult); if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens'); if (createdTokens.tokens.length < 1) throw Error('No tokens minted'); return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId); } - async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[], label?: string): Promise { + async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise { throw Error('Not implemented'); - if(typeof label === 'undefined') label = `collection #${collectionId}`; const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}], - true, `Unable to mint RFT tokens for ${label}`, + true, // `Unable to mint RFT tokens for ${label}`, ); const collection = this.getCollectionObject(collectionId); - return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); + return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); } /** @@ -1539,12 +1514,10 @@ * @param collectionId ID of collection * @param owner tokens owner * @param tokens array of tokens with properties and pieces - * @param label * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]); * @returns array of newly created RFT tokens */ - async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise { const rawTokens = []; for (const token of tokens) { const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}}; @@ -1553,10 +1526,10 @@ const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens], - true, `Unable to mint RFT tokens for ${label}`, + true, ); const collection = this.getCollectionObject(collectionId); - return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); + return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); } /** @@ -1564,13 +1537,12 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token - * @param label * @param amount number of pieces to be burnt * @example burnToken(aliceKeyring, 10, 5); * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null``` */ - async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, label?: string, amount=100n): Promise<{ success: boolean; token: number | null; }> { - return await super.burnToken(signer, collectionId, tokenId, label, amount); + async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<{ success: boolean; token: number | null; }> { + return await super.burnToken(signer, collectionId, tokenId, amount); } /** @@ -1580,13 +1552,12 @@ * @param collectionId ID of collection * @param tokenId ID of token * @param toAddressObj address to approve - * @param label * @param amount number of pieces to be approved * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n); * @returns true if the token success, otherwise false */ - async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, label?: string, amount=100n) { - return super.approveToken(signer, collectionId, tokenId, toAddressObj, label, amount); + async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) { + return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount); } /** @@ -1606,20 +1577,18 @@ * @param collectionId ID of collection * @param tokenId ID of token * @param amount new number of pieces - * @param label * @example repartitionToken(aliceKeyring, 10, 5, 12345n); * @returns true if the repartion was success, otherwise false */ - async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise { const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId); const repartitionResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.repartition', [collectionId, tokenId, amount], - true, `Unable to repartition RFT token for ${label}`, + true, ); - if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated', label); - return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed', label); + if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated'); + return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed'); } } @@ -1640,7 +1609,6 @@ * @param signer keyring of signer * @param collectionOptions Collection options * @param decimalPoints number of token decimals - * @param errorLabel * @example * mintCollection(aliceKeyring, { * name: 'New', @@ -1649,7 +1617,7 @@ * }, 18) * @returns newly created fungible collection */ - async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, decimalPoints = 0, errorLabel = 'Unable to mint collection'): Promise { + async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, decimalPoints = 0): Promise { collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions'); collectionOptions.mode = {fungible: decimalPoints}; @@ -1659,9 +1627,9 @@ const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createCollectionEx', [collectionOptions], - true, errorLabel, + true, ); - return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult, errorLabel)); + return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult)); } /** @@ -1670,12 +1638,10 @@ * @param collectionId ID of collection * @param owner address owner of new tokens * @param amount amount of tokens to be meanted - * @param label * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async mintTokens(signer: TSigner, collectionId: number, owner: ICrossAccountId | string, amount: bigint, label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async mintTokens(signer: TSigner, collectionId: number, owner: ICrossAccountId | string, amount: bigint): Promise { const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, { @@ -1683,9 +1649,9 @@ value: amount, }, }], - true, `Unable to mint fungible tokens for ${label}`, + true, // `Unable to mint fungible tokens for ${label}`, ); - return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated', label); + return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated'); } /** @@ -1694,11 +1660,9 @@ * @param collectionId ID of collection * @param owner tokens owner * @param tokens array of tokens with properties and pieces - * @param label * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {value: bigint}[], label?: string): Promise { - if(typeof label === 'undefined') label = `collection #${collectionId}`; + async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {value: bigint}[]): Promise { const rawTokens = []; for (const token of tokens) { const raw = {Fungible: {Value: token.value}}; @@ -1707,9 +1671,9 @@ const creationResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens], - true, `Unable to mint RFT tokens for ${label}`, + true, ); - return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated', label); + return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated'); } /** @@ -1737,12 +1701,12 @@ * Transfer tokens to address * @param signer keyring of signer * @param collectionId ID of collection - * @param toAddressObj address recepient + * @param toAddressObj address recipient * @param amount amount of tokens to be sent * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount: bigint) { + async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) { return await super.transferToken(signer, collectionId, 0, toAddressObj, amount); } @@ -1756,7 +1720,7 @@ * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) { + async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) { return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount); } @@ -1765,12 +1729,11 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param amount amount of tokens to be destroyed - * @param label * @example burnTokens(aliceKeyring, 10, 1000n); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async burnTokens(signer: IKeyringPair, collectionId: number, amount=100n, label?: string): Promise { - return (await super.burnToken(signer, collectionId, 0, label, amount)).success; + async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise { + return (await super.burnToken(signer, collectionId, 0, amount)).success; } /** @@ -1779,12 +1742,11 @@ * @param collectionId ID of collection * @param fromAddressObj address on behalf of which tokens will be burnt * @param amount amount of tokens to be burnt - * @param label * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n); * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=100n, label?: string): Promise { - return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, label, amount); + async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise { + return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, amount); } /** @@ -1803,12 +1765,11 @@ * @param collectionId ID of collection * @param toAddressObj address to be approved * @param amount amount of tokens to be approved - * @param label * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n) * @returns ```true``` if extrinsic success, otherwise ```false``` */ - async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=100n, label?: string) { - return super.approveToken(signer, collectionId, 0, toAddressObj, label, amount); + async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) { + return super.approveToken(signer, collectionId, 0, toAddressObj, amount); } /** @@ -1906,13 +1867,13 @@ /** * Transfer tokens to substrate address * @param signer keyring of signer - * @param address substrate address of a recepient + * @param address substrate address of a recipient * @param amount amount of tokens to be transfered * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n); * @returns ```true``` if extrinsic success, otherwise ```false``` */ async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise { - const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`); + const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/); let transfer = {from: null, to: null, amount: 0n} as any; result.result.events.forEach(({event: {data, method, section}}) => { @@ -2035,60 +1996,68 @@ return await this.helper.collection.getEffectiveLimits(this.collectionId); } - async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount, label?: string) { - return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress, label); + async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) { + return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress); } - async confirmSponsorship(signer: TSigner, label?: string) { - return await this.helper.collection.confirmSponsorship(signer, this.collectionId, label); + async confirmSponsorship(signer: TSigner) { + return await this.helper.collection.confirmSponsorship(signer, this.collectionId); } - async setLimits(signer: TSigner, limits: ICollectionLimits, label?: string) { - return await this.helper.collection.setLimits(signer, this.collectionId, limits, label); + async setLimits(signer: TSigner, limits: ICollectionLimits) { + return await this.helper.collection.setLimits(signer, this.collectionId, limits); } - async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount, label?: string) { - return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress, label); + async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) { + return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress); } - async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) { - return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj, label); + async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) { + return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj); + } + + async enableAllowList(signer: TSigner, value = true/*: 'Normal' | 'AllowList' = 'AllowList'*/) { + return await this.setPermissions(signer, value ? {access: 'AllowList', mintMode: true} : {access: 'Normal'}); + } + + async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) { + return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj); } - async addToAllowList(signer: TSigner, addressObj: ICrossAccountId, label?: string) { - return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj, label); + async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) { + return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj); } - async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) { - return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj, label); + async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) { + return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj); } - async setProperties(signer: TSigner, properties: IProperty[], label?: string) { - return await this.helper.collection.setProperties(signer, this.collectionId, properties, label); + async setProperties(signer: TSigner, properties: IProperty[]) { + return await this.helper.collection.setProperties(signer, this.collectionId, properties); } - async deleteProperties(signer: TSigner, propertyKeys: string[], label?: string) { - return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys, label); + async deleteProperties(signer: TSigner, propertyKeys: string[]) { + return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys); } async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) { return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj); } - async setPermissions(signer: TSigner, permissions: ICollectionPermissions, label?: string) { - return await this.helper.collection.setPermissions(signer, this.collectionId, permissions, label); + async setPermissions(signer: TSigner, permissions: ICollectionPermissions) { + return await this.helper.collection.setPermissions(signer, this.collectionId, permissions); } - async enableNesting(signer: TSigner, permissions: INestingPermissions, label?: string) { - return await this.helper.collection.enableNesting(signer, this.collectionId, permissions, label); + async enableNesting(signer: TSigner, permissions: INestingPermissions) { + return await this.helper.collection.enableNesting(signer, this.collectionId, permissions); } - async disableNesting(signer: TSigner, label?: string) { - return await this.helper.collection.disableNesting(signer, this.collectionId, label); + async disableNesting(signer: TSigner) { + return await this.helper.collection.disableNesting(signer, this.collectionId); } - async burn(signer: TSigner, label?: string) { - return await this.helper.collection.burn(signer, this.collectionId, label); + async burn(signer: TSigner) { + return await this.helper.collection.burn(signer, this.collectionId); } } @@ -2103,7 +2072,7 @@ } async getToken(tokenId: number, blockHashAt?: string) { - return await this.helper.nft.getToken(this.collectionId, tokenId, blockHashAt); + return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt); } async getTokenOwner(tokenId: number, blockHashAt?: string) { @@ -2126,44 +2095,44 @@ return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj); } - async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, label?: string) { - return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj, label); + async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) { + return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj); } async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) { return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj); } - async mintToken(signer: TSigner, owner: ICrossAccountId, properties?: IProperty[], label?: string) { - return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties}, label); + async mintToken(signer: TSigner, owner: ICrossAccountId, properties?: IProperty[]) { + return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties}); } - async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[], label?: string) { - return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens, label); + async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) { + return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens); } - async burnToken(signer: TSigner, tokenId: number, label?: string) { - return await this.helper.nft.burnToken(signer, this.collectionId, tokenId, label); + async burnToken(signer: TSigner, tokenId: number) { + return await this.helper.nft.burnToken(signer, this.collectionId, tokenId); } - async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[], label?: string) { - return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties, label); + async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) { + return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties); } - async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[], label?: string) { - return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys, label); + async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) { + return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys); } - async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[], label?: string) { - return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions, label); + async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) { + return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions); } - async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken, label?: string) { - return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj, label); + async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) { + return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj); } - async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId, label?: string) { - return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj, label); + async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) { + return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj); } } @@ -2189,59 +2158,59 @@ return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId); } - async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=100n) { + async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) { return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount); } - async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=100n) { + async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) { return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount); } - async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=100n, label?: string) { - return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, label, amount); + async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) { + return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount); } async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) { return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj); } - async repartitionToken(signer: TSigner, tokenId: number, amount: bigint, label?: string) { - return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount, label); + async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) { + return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount); } - async mintToken(signer: TSigner, owner: ICrossAccountId, pieces=100n, properties?: IProperty[], label?: string) { - return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties}, label); + async mintToken(signer: TSigner, owner: ICrossAccountId, pieces=100n, properties?: IProperty[]) { + return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties}); } - async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[], label?: string) { - return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens, label); + async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]) { + return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens); } - async burnToken(signer: TSigner, tokenId: number, amount=100n, label?: string) { - return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, label, amount); + async burnToken(signer: TSigner, tokenId: number, amount=1n) { + return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount); } - async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[], label?: string) { - return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties, label); + async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) { + return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties); } - async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[], label?: string) { - return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys, label); + async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) { + return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys); } - async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[], label?: string) { - return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions, label); + async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) { + return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions); } } class UniqueFTCollection extends UniqueCollectionBase { - async mint(signer: TSigner, owner: ICrossAccountId, amount: bigint, label?: string) { - return await this.helper.ft.mintTokens(signer, this.collectionId, owner, amount, label); + async mint(signer: TSigner, owner: ICrossAccountId, amount: bigint) { + return await this.helper.ft.mintTokens(signer, this.collectionId, owner, amount); } - async mintWithOneOwner(signer: TSigner, owner: ICrossAccountId, tokens: {value: bigint}[], label?: string) { - return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, owner, tokens, label); + async mintWithOneOwner(signer: TSigner, owner: ICrossAccountId, tokens: {value: bigint}[]) { + return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, owner, tokens); } async getBalance(addressObj: ICrossAccountId) { @@ -2252,28 +2221,28 @@ return await this.helper.ft.getTop10Owners(this.collectionId); } - async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount: bigint) { + async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) { return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount); } - async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) { + async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) { return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount); } - async burnTokens(signer: TSigner, amount: bigint, label?: string) { - return await this.helper.ft.burnTokens(signer, this.collectionId, amount, label); + async burnTokens(signer: TSigner, amount=1n) { + return await this.helper.ft.burnTokens(signer, this.collectionId, amount); } - async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount: bigint, label?: string) { - return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount, label); + async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) { + return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount); } async getTotalPieces() { return await this.helper.ft.getTotalPieces(this.collectionId); } - async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=100n, label?: string) { - return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount, label); + async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) { + return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount); } async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) { @@ -2297,12 +2266,12 @@ return await this.collection.getTokenNextSponsored(this.tokenId, addressObj); } - async setProperties(signer: TSigner, properties: IProperty[], label?: string) { - return await this.collection.setTokenProperties(signer, this.tokenId, properties, label); + async setProperties(signer: TSigner, properties: IProperty[]) { + return await this.collection.setTokenProperties(signer, this.tokenId, properties); } - async deleteProperties(signer: TSigner, propertyKeys: string[], label?: string) { - return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys, label); + async deleteProperties(signer: TSigner, propertyKeys: string[]) { + return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys); } } @@ -2331,12 +2300,12 @@ return await this.collection.getTokenChildren(this.tokenId, blockHashAt); } - async nest(signer: TSigner, toTokenObj: IToken, label?: string) { - return await this.collection.nestToken(signer, this.tokenId, toTokenObj, label); + async nest(signer: TSigner, toTokenObj: IToken) { + return await this.collection.nestToken(signer, this.tokenId, toTokenObj); } - async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId, label?: string) { - return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj, label); + async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) { + return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj); } async transfer(signer: TSigner, addressObj: ICrossAccountId) { @@ -2347,16 +2316,16 @@ return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj); } - async approve(signer: TSigner, toAddressObj: ICrossAccountId, label?: string) { - return await this.collection.approveToken(signer, this.tokenId, toAddressObj, label); + async approve(signer: TSigner, toAddressObj: ICrossAccountId) { + return await this.collection.approveToken(signer, this.tokenId, toAddressObj); } async isApproved(toAddressObj: ICrossAccountId) { return await this.collection.isTokenApproved(this.tokenId, toAddressObj); } - async burn(signer: TSigner, label?: string) { - return await this.collection.burnToken(signer, this.tokenId, label); + async burn(signer: TSigner) { + return await this.collection.burnToken(signer, this.tokenId); } } @@ -2380,27 +2349,27 @@ return await this.collection.getTokenTotalPieces(this.tokenId); } - async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=100n) { + async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) { return await this.collection.transferToken(signer, this.tokenId, addressObj, amount); } - async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=100n) { + async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) { return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount); } - async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=100n, label?: string) { - return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount, label); + async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) { + return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount); } async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) { return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj); } - async repartition(signer: TSigner, amount: bigint, label?: string) { - return await this.collection.repartitionToken(signer, this.tokenId, amount, label); + async repartition(signer: TSigner, amount: bigint) { + return await this.collection.repartitionToken(signer, this.tokenId, amount); } - async burn(signer: TSigner, amount=100n, label?: string) { - return await this.collection.burnToken(signer, this.tokenId, amount, label); + async burn(signer: TSigner, amount=1n) { + return await this.collection.burnToken(signer, this.tokenId, amount); } } \ No newline at end of file