1234567891011121314151617import {expect, itEth, usingEthPlaygrounds} from './util';18import {IKeyringPair} from '@polkadot/types/types';1920describe('Fungible: Information getting', () => {21 let donor: IKeyringPair;22 let alice: IKeyringPair;2324 before(async function() {25 await usingEthPlaygrounds(async (helper, privateKey) => {26 donor = await privateKey({filename: __filename});27 [alice] = await helper.arrange.createAccounts([20n], donor);28 });29 });3031 itEth('totalSupply', async ({helper}) => {32 const caller = await helper.eth.createAccountWithBalance(donor);33 const collection = await helper.ft.mintCollection(alice);34 await collection.mint(alice, 200n);3536 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);37 const totalSupply = await contract.methods.totalSupply().call();38 expect(totalSupply).to.equal('200');39 });4041 itEth('balanceOf', async ({helper}) => {42 const caller = await helper.eth.createAccountWithBalance(donor);43 const collection = await helper.ft.mintCollection(alice);44 await collection.mint(alice, 200n, {Ethereum: caller});4546 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);47 const balance = await contract.methods.balanceOf(caller).call();48 expect(balance).to.equal('200');49 });50});5152describe('Fungible: Plain calls', () => {53 let donor: IKeyringPair;54 let alice: IKeyringPair;55 let owner: IKeyringPair;5657 before(async function() {58 await usingEthPlaygrounds(async (helper, privateKey) => {59 donor = await privateKey({filename: __filename});60 [alice, owner] = await helper.arrange.createAccounts([20n, 20n], donor);61 });62 });6364 itEth('Can perform mint()', async ({helper}) => {65 const owner = await helper.eth.createAccountWithBalance(donor);66 const receiver = helper.eth.createAccount();67 const collection = await helper.ft.mintCollection(alice);68 await collection.addAdmin(alice, {Ethereum: owner});6970 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);71 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);7273 const result = await contract.methods.mint(receiver, 100).send();74 75 const event = result.events.Transfer;76 expect(event.address).to.equal(collectionAddress);77 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');78 expect(event.returnValues.to).to.equal(receiver);79 expect(event.returnValues.value).to.equal('100');80 });8182 itEth('Can perform mintBulk()', async ({helper}) => {83 const owner = await helper.eth.createAccountWithBalance(donor);84 const bulkSize = 3;85 const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());86 const collection = await helper.ft.mintCollection(alice);87 await collection.addAdmin(alice, {Ethereum: owner});8889 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);90 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);9192 const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (93 [receivers[i], (i + 1) * 10]94 ))).send();95 const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);96 for (let i = 0; i < bulkSize; i++) {97 const event = events[i];98 expect(event.address).to.equal(collectionAddress);99 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');100 expect(event.returnValues.to).to.equal(receivers[i]);101 expect(event.returnValues.value).to.equal(String(10 * (i + 1)));102 }103 });104105 itEth('Can perform burn()', async ({helper}) => {106 const owner = await helper.eth.createAccountWithBalance(donor);107 const receiver = await helper.eth.createAccountWithBalance(donor);108 const collection = await helper.ft.mintCollection(alice);109 await collection.addAdmin(alice, {Ethereum: owner});110111 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);112 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);113 await contract.methods.mint(receiver, 100).send();114115 const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});116 117 const event = result.events.Transfer;118 expect(event.address).to.equal(collectionAddress);119 expect(event.returnValues.from).to.equal(receiver);120 expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');121 expect(event.returnValues.value).to.equal('49');122123 const balance = await contract.methods.balanceOf(receiver).call();124 expect(balance).to.equal('51');125 });126127 itEth('Can perform approve()', async ({helper}) => {128 const owner = await helper.eth.createAccountWithBalance(donor);129 const spender = helper.eth.createAccount();130 const collection = await helper.ft.mintCollection(alice);131 await collection.mint(alice, 200n, {Ethereum: owner});132133 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);134 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);135136 {137 const result = await contract.methods.approve(spender, 100).send({from: owner});138139 const event = result.events.Approval;140 expect(event.address).to.be.equal(collectionAddress);141 expect(event.returnValues.owner).to.be.equal(owner);142 expect(event.returnValues.spender).to.be.equal(spender);143 expect(event.returnValues.value).to.be.equal('100');144 }145146 {147 const allowance = await contract.methods.allowance(owner, spender).call();148 expect(+allowance).to.equal(100);149 }150 });151152 itEth('Can perform burnFromCross()', async ({helper}) => {153 const sender = await helper.eth.createAccountWithBalance(donor, 100n);154155 const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);156157 await collection.mint(owner, 200n, {Substrate: owner.address});158 await collection.approveTokens(owner, {Ethereum: sender}, 100n);159160 const address = helper.ethAddress.fromCollectionId(collection.collectionId);161 const contract = helper.ethNativeContract.collection(address, 'ft');162163 const fromBalanceBefore = await collection.getBalance({Substrate: owner.address});164 165 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);166 const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});167 const events = result.events;168169 expect(events).to.be.like({170 Transfer: {171 address: helper.ethAddress.fromCollectionId(collection.collectionId),172 event: 'Transfer',173 returnValues: {174 from: helper.address.substrateToEth(owner.address),175 to: '0x0000000000000000000000000000000000000000',176 value: '49',177 },178 },179 Approval: {180 address: helper.ethAddress.fromCollectionId(collection.collectionId),181 returnValues: {182 owner: helper.address.substrateToEth(owner.address),183 spender: sender,184 value: '51',185 },186 event: 'Approval',187 },188 });189190 const fromBalanceAfter = await collection.getBalance({Substrate: owner.address});191 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);192 });193194 itEth('Can perform transferFrom()', async ({helper}) => {195 const owner = await helper.eth.createAccountWithBalance(donor);196 const spender = await helper.eth.createAccountWithBalance(donor);197 const receiver = helper.eth.createAccount();198 const collection = await helper.ft.mintCollection(alice);199 await collection.mint(alice, 200n, {Ethereum: owner});200201 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);202 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);203204 await contract.methods.approve(spender, 100).send();205206 {207 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});208 209 let event = result.events.Transfer;210 expect(event.address).to.be.equal(collectionAddress);211 expect(event.returnValues.from).to.be.equal(owner);212 expect(event.returnValues.to).to.be.equal(receiver);213 expect(event.returnValues.value).to.be.equal('49');214215 event = result.events.Approval;216 expect(event.address).to.be.equal(collectionAddress);217 expect(event.returnValues.owner).to.be.equal(owner);218 expect(event.returnValues.spender).to.be.equal(spender);219 expect(event.returnValues.value).to.be.equal('51');220 }221222 {223 const balance = await contract.methods.balanceOf(receiver).call();224 expect(+balance).to.equal(49);225 }226227 {228 const balance = await contract.methods.balanceOf(owner).call();229 expect(+balance).to.equal(151);230 }231 });232233 itEth('Can perform transferCross()', async ({helper}) => {234 const owner = await helper.eth.createAccountWithBalance(donor);235 const receiver = await helper.eth.createAccountWithBalance(donor);236 const to = helper.ethCrossAccount.fromAddress(receiver);237 const toSubstrate = helper.ethCrossAccount.fromKeyringPair(donor);238 const collection = await helper.ft.mintCollection(alice);239 await collection.mint(alice, 200n, {Ethereum: owner});240241 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);242 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);243244 {245 const result = await contract.methods.transferCross(to, 50).send({from: owner});246 247 const event = result.events.Transfer;248 expect(event.address).to.be.equal(collectionAddress);249 expect(event.returnValues.from).to.be.equal(owner);250 expect(event.returnValues.to).to.be.equal(receiver);251 expect(event.returnValues.value).to.be.equal('50');252 }253254 {255 const balance = await contract.methods.balanceOf(owner).call();256 expect(+balance).to.equal(150);257 }258259 {260 const balance = await contract.methods.balanceOf(receiver).call();261 expect(+balance).to.equal(50);262 }263 264 {265 const result = await contract.methods.transferCross(toSubstrate, 50).send({from: owner});266 267 const event = result.events.Transfer;268 expect(event.address).to.be.equal(collectionAddress);269 expect(event.returnValues.from).to.be.equal(owner);270 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address));271 expect(event.returnValues.value).to.be.equal('50');272 }273274 {275 const balance = await collection.getBalance({Ethereum: owner});276 expect(balance).to.equal(100n);277 }278279 {280 const balance = await collection.getBalance({Substrate: donor.address});281 expect(balance).to.equal(50n);282 }283 284 });285 286 itEth('Can perform transfer()', async ({helper}) => {287 const owner = await helper.eth.createAccountWithBalance(donor);288 const receiver = await helper.eth.createAccountWithBalance(donor);289 const collection = await helper.ft.mintCollection(alice);290 await collection.mint(alice, 200n, {Ethereum: owner});291292 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);293 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);294295 {296 const result = await contract.methods.transfer(receiver, 50).send({from: owner});297 298 const event = result.events.Transfer;299 expect(event.address).to.be.equal(collectionAddress);300 expect(event.returnValues.from).to.be.equal(owner);301 expect(event.returnValues.to).to.be.equal(receiver);302 expect(event.returnValues.value).to.be.equal('50');303 }304305 {306 const balance = await contract.methods.balanceOf(owner).call();307 expect(+balance).to.equal(150);308 }309310 {311 const balance = await contract.methods.balanceOf(receiver).call();312 expect(+balance).to.equal(50);313 }314 });315316 itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {317 const sender = await helper.eth.createAccountWithBalance(donor, 100n);318319 const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);320321 const receiver = helper.eth.createAccount();322323 await collection.mint(owner, 200n, {Substrate: owner.address});324 await collection.approveTokens(owner, {Ethereum: sender}, 100n);325326 const address = helper.ethAddress.fromCollectionId(collection.collectionId);327 const contract = helper.ethNativeContract.collection(address, 'ft');328329 const from = helper.ethCrossAccount.fromKeyringPair(owner);330 const to = helper.ethCrossAccount.fromAddress(receiver);331332 const fromBalanceBefore = await collection.getBalance({Substrate: owner.address});333 const toBalanceBefore = await collection.getBalance({Ethereum: receiver});334 335 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});336337 expect(result.events).to.be.like({338 Transfer: {339 address,340 event: 'Transfer',341 returnValues: {342 from: helper.address.substrateToEth(owner.address),343 to: receiver,344 value: '51',345 },346 },347 Approval: {348 address,349 event: 'Approval',350 returnValues: {351 owner: helper.address.substrateToEth(owner.address),352 spender: sender,353 value: '49',354 },355 }});356357 const fromBalanceAfter = await collection.getBalance({Substrate: owner.address});358 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);359 const toBalanceAfter = await collection.getBalance({Ethereum: receiver});360 expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);361 });362});363364describe('Fungible: Fees', () => {365 let donor: IKeyringPair;366 let alice: IKeyringPair;367368 before(async function() {369 await usingEthPlaygrounds(async (helper, privateKey) => {370 donor = await privateKey({filename: __filename});371 [alice] = await helper.arrange.createAccounts([20n], donor);372 });373 });374 375 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {376 const owner = await helper.eth.createAccountWithBalance(donor);377 const spender = helper.eth.createAccount();378 const collection = await helper.ft.mintCollection(alice);379 await collection.mint(alice, 200n, {Ethereum: owner});380381 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);382 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);383384 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));385 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));386 });387388 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {389 const owner = await helper.eth.createAccountWithBalance(donor);390 const spender = await helper.eth.createAccountWithBalance(donor);391 const collection = await helper.ft.mintCollection(alice);392 await collection.mint(alice, 200n, {Ethereum: owner});393394 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);395 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);396397 await contract.methods.approve(spender, 100).send({from: owner});398399 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));400 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));401 });402403 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {404 const owner = await helper.eth.createAccountWithBalance(donor);405 const receiver = helper.eth.createAccount();406 const collection = await helper.ft.mintCollection(alice);407 await collection.mint(alice, 200n, {Ethereum: owner});408409 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);410 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);411412 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));413 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));414 });415});416417describe('Fungible: Substrate calls', () => {418 let donor: IKeyringPair;419 let alice: IKeyringPair;420 let owner: IKeyringPair;421422 before(async function() {423 await usingEthPlaygrounds(async (helper, privateKey) => {424 donor = await privateKey({filename: __filename});425 [alice, owner] = await helper.arrange.createAccounts([20n, 20n], donor);426 });427 });428429 itEth('Events emitted for approve()', async ({helper}) => {430 const receiver = helper.eth.createAccount();431 const collection = await helper.ft.mintCollection(alice);432 await collection.mint(alice, 200n);433434 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);435 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');436437 const events: any = [];438 contract.events.allEvents((_: any, event: any) => {439 events.push(event);440 });441 442 await collection.approveTokens(alice, {Ethereum: receiver}, 100n);443 if (events.length == 0) await helper.wait.newBlocks(1);444 const event = events[0];445446 expect(event.event).to.be.equal('Approval');447 expect(event.address).to.be.equal(collectionAddress);448 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));449 expect(event.returnValues.spender).to.be.equal(receiver);450 expect(event.returnValues.value).to.be.equal('100');451 });452453 itEth('Events emitted for transferFrom()', async ({helper}) => {454 const [bob] = await helper.arrange.createAccounts([10n], donor);455 const receiver = helper.eth.createAccount();456 const collection = await helper.ft.mintCollection(alice);457 await collection.mint(alice, 200n);458 await collection.approveTokens(alice, {Substrate: bob.address}, 100n);459460 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);461 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');462463 const events: any = [];464 contract.events.allEvents((_: any, event: any) => {465 events.push(event);466 });467468 await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);469 if (events.length == 0) await helper.wait.newBlocks(1);470 let event = events[0];471472 expect(event.event).to.be.equal('Transfer');473 expect(event.address).to.be.equal(collectionAddress);474 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));475 expect(event.returnValues.to).to.be.equal(receiver);476 expect(event.returnValues.value).to.be.equal('51');477478 event = events[1];479 expect(event.event).to.be.equal('Approval');480 expect(event.address).to.be.equal(collectionAddress);481 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));482 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));483 expect(event.returnValues.value).to.be.equal('49');484 });485486 itEth('Events emitted for transfer()', async ({helper}) => {487 const receiver = helper.eth.createAccount();488 const collection = await helper.ft.mintCollection(alice);489 await collection.mint(alice, 200n);490491 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);492 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');493494 const events: any = [];495 contract.events.allEvents((_: any, event: any) => {496 events.push(event);497 });498 499 await collection.transfer(alice, {Ethereum:receiver}, 51n);500 if (events.length == 0) await helper.wait.newBlocks(1);501 const event = events[0];502503 expect(event.event).to.be.equal('Transfer');504 expect(event.address).to.be.equal(collectionAddress);505 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));506 expect(event.returnValues.to).to.be.equal(receiver);507 expect(event.returnValues.value).to.be.equal('51');508 });509510 itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {511 const sender = await helper.eth.createAccountWithBalance(donor, 100n);512513 const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);514515 const receiver = helper.eth.createAccount();516517 await collection.mint(owner, 200n, {Substrate: owner.address});518 await collection.approveTokens(owner, {Ethereum: sender}, 100n);519520 const address = helper.ethAddress.fromCollectionId(collection.collectionId);521 const contract = helper.ethNativeContract.collection(address, 'ft');522523 const from = helper.ethCrossAccount.fromKeyringPair(owner);524 const to = helper.ethCrossAccount.fromAddress(receiver);525 526 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});527528 expect(result.events).to.be.like({529 Transfer: {530 address,531 event: 'Transfer',532 returnValues: {533 from: helper.address.substrateToEth(owner.address),534 to: receiver,535 value: '51',536 },537 },538 Approval: {539 address,540 event: 'Approval',541 returnValues: {542 owner: helper.address.substrateToEth(owner.address),543 spender: sender,544 value: '49',545 },546 }});547 });548});