1234567891011121314151617import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';19import reFungibleTokenAbi from './reFungibleTokenAbi.json';2021import chai from 'chai';22import chaiAsPromised from 'chai-as-promised';23chai.use(chaiAsPromised);24const expect = chai.expect;2526describe('Refungible token: Information getting', () => {27 before(async function() {28 await requirePallets(this, [Pallets.ReFungible]);29 });3031 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {32 const alice = privateKeyWrapper('//Alice');3334 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;3536 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);3738 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;3940 const address = tokenIdToAddress(collectionId, tokenId);41 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});42 const totalSupply = await contract.methods.totalSupply().call();4344 expect(totalSupply).to.equal('200');45 });4647 itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {48 const alice = privateKeyWrapper('//Alice');4950 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;5152 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);5354 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;5556 const address = tokenIdToAddress(collectionId, tokenId);57 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});58 const balance = await contract.methods.balanceOf(caller).call();5960 expect(balance).to.equal('200');61 });6263 itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {64 const alice = privateKeyWrapper('//Alice');6566 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;6768 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);6970 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;7172 const address = tokenIdToAddress(collectionId, tokenId);73 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});74 const decimals = await contract.methods.decimals().call();7576 expect(decimals).to.equal('0');77 });78});798081describe('Check ERC721 token URI for ReFungible', () => {82 before(async function() {83 await requirePallets(this, [Pallets.ReFungible]);84 });8586 itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {87 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);88 const helper = evmCollectionHelpers(web3, owner);89 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();90 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);91 const receiver = createEthAccount(web3);92 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});93 94 const nextTokenId = await contract.methods.nextTokenId().call();95 expect(nextTokenId).to.be.equal('1');96 result = await contract.methods.mint(97 receiver,98 nextTokenId,99 ).send();100101 const events = normalizeEvents(result.events);102 const address = collectionIdToAddress(collectionId);103104 expect(events).to.be.deep.equal([105 {106 address,107 event: 'Transfer',108 args: {109 from: '0x0000000000000000000000000000000000000000',110 to: receiver,111 tokenId: nextTokenId,112 },113 },114 ]);115116 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');117 });118119 itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {120 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);121 const helper = evmCollectionHelpers(web3, owner);122 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();123 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);124 const receiver = createEthAccount(web3);125 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});126 127 const nextTokenId = await contract.methods.nextTokenId().call();128 expect(nextTokenId).to.be.equal('1');129 result = await contract.methods.mint(130 receiver,131 nextTokenId,132 ).send();133 134 135 await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();136 137 const events = normalizeEvents(result.events);138 const address = collectionIdToAddress(collectionId);139140 expect(events).to.be.deep.equal([141 {142 address,143 event: 'Transfer',144 args: {145 from: '0x0000000000000000000000000000000000000000',146 to: receiver,147 tokenId: nextTokenId,148 },149 },150 ]);151152 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');153 });154155 itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {156 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);157 const helper = evmCollectionHelpers(web3, owner);158 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();159 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);160 const receiver = createEthAccount(web3);161 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});162 163 const nextTokenId = await contract.methods.nextTokenId().call();164 expect(nextTokenId).to.be.equal('1');165 result = await contract.methods.mint(166 receiver,167 nextTokenId,168 ).send();169 170 const events = normalizeEvents(result.events);171 const address = collectionIdToAddress(collectionId);172173 expect(events).to.be.deep.equal([174 {175 address,176 event: 'Transfer',177 args: {178 from: '0x0000000000000000000000000000000000000000',179 to: receiver,180 tokenId: nextTokenId,181 },182 },183 ]);184185 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);186 });187188 itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {189 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);190 const helper = evmCollectionHelpers(web3, owner);191 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();192 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);193 const receiver = createEthAccount(web3);194 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});195 196 const nextTokenId = await contract.methods.nextTokenId().call();197 expect(nextTokenId).to.be.equal('1');198 result = await contract.methods.mint(199 receiver,200 nextTokenId,201 ).send();202 203 204 const suffix = '/some/suffix';205 await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();206207 const events = normalizeEvents(result.events);208 const address = collectionIdToAddress(collectionId);209210 expect(events).to.be.deep.equal([211 {212 address,213 event: 'Transfer',214 args: {215 from: '0x0000000000000000000000000000000000000000',216 to: receiver,217 tokenId: nextTokenId,218 },219 },220 ]);221222 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);223 });224});225226describe('Refungible: Plain calls', () => {227 before(async function() {228 await requirePallets(this, [Pallets.ReFungible]);229 });230231 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {232 const alice = privateKeyWrapper('//Alice');233234 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;235236 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);237238 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;239240 const address = tokenIdToAddress(collectionId, tokenId);241242 const spender = createEthAccount(web3);243244 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});245246 {247 const result = await contract.methods.approve(spender, 100).send({from: owner});248 const events = normalizeEvents(result.events);249250 expect(events).to.be.deep.equal([251 {252 address,253 event: 'Approval',254 args: {255 owner,256 spender,257 value: '100',258 },259 },260 ]);261 }262263 {264 const allowance = await contract.methods.allowance(owner, spender).call();265 expect(+allowance).to.equal(100);266 }267 });268269 itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {270 const alice = privateKeyWrapper('//Alice');271272 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;273274 const owner = createEthAccount(web3);275 await transferBalanceToEth(api, alice, owner);276277 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;278279 const spender = createEthAccount(web3);280 await transferBalanceToEth(api, alice, spender);281282 const receiver = createEthAccount(web3);283284 const address = tokenIdToAddress(collectionId, tokenId);285 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});286287 await contract.methods.approve(spender, 100).send();288289 {290 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});291 const events = normalizeEvents(result.events);292 expect(events).to.include.deep.members([293 {294 address,295 event: 'Transfer',296 args: {297 from: owner,298 to: receiver,299 value: '49',300 },301 },302 {303 address,304 event: 'Approval',305 args: {306 owner,307 spender,308 value: '51',309 },310 },311 ]);312 }313314 {315 const balance = await contract.methods.balanceOf(receiver).call();316 expect(+balance).to.equal(49);317 }318319 {320 const balance = await contract.methods.balanceOf(owner).call();321 expect(+balance).to.equal(151);322 }323 });324325 itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {326 const alice = privateKeyWrapper('//Alice');327328 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;329330 const owner = createEthAccount(web3);331 await transferBalanceToEth(api, alice, owner);332333 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;334335 const receiver = createEthAccount(web3);336 await transferBalanceToEth(api, alice, receiver);337338 const address = tokenIdToAddress(collectionId, tokenId);339 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});340341 {342 const result = await contract.methods.transfer(receiver, 50).send({from: owner});343 const events = normalizeEvents(result.events);344 expect(events).to.include.deep.members([345 {346 address,347 event: 'Transfer',348 args: {349 from: owner,350 to: receiver,351 value: '50',352 },353 },354 ]);355 }356357 {358 const balance = await contract.methods.balanceOf(owner).call();359 expect(+balance).to.equal(150);360 }361362 {363 const balance = await contract.methods.balanceOf(receiver).call();364 expect(+balance).to.equal(50);365 }366 });367368 itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {369 const alice = privateKeyWrapper('//Alice');370371 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;372373 const owner = createEthAccount(web3);374 await transferBalanceToEth(api, alice, owner);375376 const receiver = createEthAccount(web3);377 await transferBalanceToEth(api, alice, receiver);378379 const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;380381 const address = tokenIdToAddress(collectionId, tokenId);382 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});383384 await contract.methods.repartition(200).send({from: owner});385 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);386 await contract.methods.transfer(receiver, 110).send({from: owner});387 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);388 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);389 390 await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;391392 await contract.methods.transfer(receiver, 90).send({from: owner});393 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);394 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);395396 await contract.methods.repartition(150).send({from: receiver});397 await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;398 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);399 });400401 itWeb3('Can repartition with increased amount', async ({web3, api, privateKeyWrapper}) => {402 const alice = privateKeyWrapper('//Alice');403404 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;405406 const owner = createEthAccount(web3);407 await transferBalanceToEth(api, alice, owner);408409 const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;410411 const address = tokenIdToAddress(collectionId, tokenId);412 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});413414 const result = await contract.methods.repartition(200).send();415 const events = normalizeEvents(result.events);416417 expect(events).to.deep.equal([418 {419 address,420 event: 'Transfer',421 args: {422 from: '0x0000000000000000000000000000000000000000',423 to: owner,424 value: '100',425 },426 },427 ]);428 });429430 itWeb3('Can repartition with decreased amount', async ({web3, api, privateKeyWrapper}) => {431 const alice = privateKeyWrapper('//Alice');432433 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;434435 const owner = createEthAccount(web3);436 await transferBalanceToEth(api, alice, owner);437438 const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;439440 const address = tokenIdToAddress(collectionId, tokenId);441 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});442443 const result = await contract.methods.repartition(50).send();444 const events = normalizeEvents(result.events);445 expect(events).to.deep.equal([446 {447 address,448 event: 'Transfer',449 args: {450 from: owner,451 to: '0x0000000000000000000000000000000000000000',452 value: '50',453 },454 },455 ]);456 });457458 itWeb3('Receiving Transfer event on burning into full ownership', async ({web3, api, privateKeyWrapper}) => {459 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);460 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);461 const helper = evmCollectionHelpers(web3, caller);462 const result = await helper.methods.createRefungibleCollection('Mint collection', '6', '6').send();463 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);464 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});465466 const tokenId = await contract.methods.nextTokenId().call();467 await contract.methods.mint(caller, tokenId).send();468469 const address = tokenIdToAddress(collectionId, tokenId);470471 const tokenContract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});472 await tokenContract.methods.repartition(2).send();473 await tokenContract.methods.transfer(receiver, 1).send();474475 const events = await recordEvents(contract, async () => 476 await tokenContract.methods.burnFrom(caller, 1).send());477 expect(events).to.deep.equal([478 {479 address: collectionIdAddress,480 event: 'Transfer',481 args: {482 from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',483 to: receiver,484 tokenId,485 },486 },487 ]);488 });489});490491describe('Refungible: Fees', () => {492 before(async function() {493 await requirePallets(this, [Pallets.ReFungible]);494 });495496 itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {497 const alice = privateKeyWrapper('//Alice');498499 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;500501 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);502 const spender = createEthAccount(web3);503504 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;505506 const address = tokenIdToAddress(collectionId, tokenId);507 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});508509 const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));510 expect(cost < BigInt(0.2 * Number(UNIQUE)));511 });512513 itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {514 const alice = privateKeyWrapper('//Alice');515516 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;517518 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);519 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);520521 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;522523 const address = tokenIdToAddress(collectionId, tokenId);524 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});525526 await contract.methods.approve(spender, 100).send({from: owner});527528 const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));529 expect(cost < BigInt(0.2 * Number(UNIQUE)));530 });531532 itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {533 const alice = privateKeyWrapper('//Alice');534535 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;536537 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);538 const receiver = createEthAccount(web3);539540 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;541542 const address = tokenIdToAddress(collectionId, tokenId);543 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});544545 const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));546 expect(cost < BigInt(0.2 * Number(UNIQUE)));547 });548});549550describe('Refungible: Substrate calls', () => {551 before(async function() {552 await requirePallets(this, [Pallets.ReFungible]);553 });554555 itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {556 const alice = privateKeyWrapper('//Alice');557558 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;559560 const receiver = createEthAccount(web3);561562 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;563564 const address = tokenIdToAddress(collectionId, tokenId);565 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);566567 const events = await recordEvents(contract, async () => {568 expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;569 });570571 expect(events).to.be.deep.equal([572 {573 address,574 event: 'Approval',575 args: {576 owner: subToEth(alice.address),577 spender: receiver,578 value: '100',579 },580 },581 ]);582 });583584 itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {585 const alice = privateKeyWrapper('//Alice');586587 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;588 const bob = privateKeyWrapper('//Bob');589590 const receiver = createEthAccount(web3);591592 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;593 expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;594595 const address = tokenIdToAddress(collectionId, tokenId);596 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);597598 const events = await recordEvents(contract, async () => {599 expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver}, 51n)).to.be.true;600 });601602 expect(events).to.be.deep.equal([603 {604 address,605 event: 'Transfer',606 args: {607 from: subToEth(alice.address),608 to: receiver,609 value: '51',610 },611 },612 {613 address,614 event: 'Approval',615 args: {616 owner: subToEth(alice.address),617 spender: subToEth(bob.address),618 value: '49',619 },620 },621 ]);622 });623624 itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {625 const alice = privateKeyWrapper('//Alice');626627 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;628629 const receiver = createEthAccount(web3);630631 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;632633 const address = tokenIdToAddress(collectionId, tokenId);634 const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);635636 const events = await recordEvents(contract, async () => {637 expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver}, 51n)).to.be.true;638 });639640 expect(events).to.be.deep.equal([641 {642 address,643 event: 'Transfer',644 args: {645 from: subToEth(alice.address),646 to: receiver,647 value: '51',648 },649 },650 ]);651 });652});