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;5556 before(async function() {57 await usingEthPlaygrounds(async (helper, privateKey) => {58 donor = await privateKey({filename: __filename});59 [alice] = await helper.arrange.createAccounts([20n], donor);60 });61 });6263 itEth('Can perform mint()', async ({helper}) => {64 const owner = await helper.eth.createAccountWithBalance(donor);65 const receiver = helper.eth.createAccount();66 const collection = await helper.ft.mintCollection(alice);67 await collection.addAdmin(alice, {Ethereum: owner});6869 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);70 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);7172 const result = await contract.methods.mint(receiver, 100).send();73 74 const event = result.events.Transfer;75 expect(event.address).to.equal(collectionAddress);76 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');77 expect(event.returnValues.to).to.equal(receiver);78 expect(event.returnValues.value).to.equal('100');79 });8081 itEth('Can perform mintBulk()', async ({helper}) => {82 const owner = await helper.eth.createAccountWithBalance(donor);83 const bulkSize = 3;84 const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());85 const collection = await helper.ft.mintCollection(alice);86 await collection.addAdmin(alice, {Ethereum: owner});8788 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);89 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);9091 const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (92 [receivers[i], (i + 1) * 10]93 ))).send();94 const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);95 for (let i = 0; i < bulkSize; i++) {96 const event = events[i];97 expect(event.address).to.equal(collectionAddress);98 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');99 expect(event.returnValues.to).to.equal(receivers[i]);100 expect(event.returnValues.value).to.equal(String(10 * (i + 1)));101 }102 });103104 itEth('Can perform burn()', async ({helper}) => {105 const owner = await helper.eth.createAccountWithBalance(donor);106 const receiver = await helper.eth.createAccountWithBalance(donor);107 const collection = await helper.ft.mintCollection(alice);108 await collection.addAdmin(alice, {Ethereum: owner});109110 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);111 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);112 await contract.methods.mint(receiver, 100).send();113114 const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});115 116 const event = result.events.Transfer;117 expect(event.address).to.equal(collectionAddress);118 expect(event.returnValues.from).to.equal(receiver);119 expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');120 expect(event.returnValues.value).to.equal('49');121122 const balance = await contract.methods.balanceOf(receiver).call();123 expect(balance).to.equal('51');124 });125126 itEth('Can perform approve()', async ({helper}) => {127 const owner = await helper.eth.createAccountWithBalance(donor);128 const spender = helper.eth.createAccount();129 const collection = await helper.ft.mintCollection(alice);130 await collection.mint(alice, 200n, {Ethereum: owner});131132 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);133 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);134135 {136 const result = await contract.methods.approve(spender, 100).send({from: owner});137138 const event = result.events.Approval;139 expect(event.address).to.be.equal(collectionAddress);140 expect(event.returnValues.owner).to.be.equal(owner);141 expect(event.returnValues.spender).to.be.equal(spender);142 expect(event.returnValues.value).to.be.equal('100');143 }144145 {146 const allowance = await contract.methods.allowance(owner, spender).call();147 expect(+allowance).to.equal(100);148 }149 });150151 itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {152 const alice = await privateKey('//Alice');153 const sender = await helper.eth.createAccountWithBalance(alice, 100n);154155 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);156157 await collection.mint(alice, 200n, {Substrate: alice.address});158 await collection.approveTokens(alice, {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: alice.address});164 165 const ownerCross = helper.ethCrossAccount.fromKeyringPair(alice);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(alice.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(alice.address),183 spender: sender,184 value: '51',185 },186 event: 'Approval',187 },188 });189190 const fromBalanceAfter = await collection.getBalance({Substrate: alice.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 transfer()', async ({helper}) => {234 const owner = await helper.eth.createAccountWithBalance(donor);235 const receiver = await helper.eth.createAccountWithBalance(donor);236 const collection = await helper.ft.mintCollection(alice);237 await collection.mint(alice, 200n, {Ethereum: owner});238239 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);240 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);241242 {243 const result = await contract.methods.transfer(receiver, 50).send({from: owner});244 245 const event = result.events.Transfer;246 expect(event.address).to.be.equal(collectionAddress);247 expect(event.returnValues.from).to.be.equal(owner);248 expect(event.returnValues.to).to.be.equal(receiver);249 expect(event.returnValues.value).to.be.equal('50');250 }251252 {253 const balance = await contract.methods.balanceOf(owner).call();254 expect(+balance).to.equal(150);255 }256257 {258 const balance = await contract.methods.balanceOf(receiver).call();259 expect(+balance).to.equal(50);260 }261 });262263 itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {264 const alice = await privateKey('//Alice');265 const sender = await helper.eth.createAccountWithBalance(alice, 100n);266267 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);268269 const receiver = helper.eth.createAccount();270271 await collection.mint(alice, 200n, {Substrate: alice.address});272 await collection.approveTokens(alice, {Ethereum: sender}, 100n);273274 const address = helper.ethAddress.fromCollectionId(collection.collectionId);275 const contract = helper.ethNativeContract.collection(address, 'ft');276277 const from = helper.ethCrossAccount.fromKeyringPair(alice);278 const to = helper.ethCrossAccount.fromAddress(receiver);279280 const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});281 const toBalanceBefore = await collection.getBalance({Ethereum: receiver});282 283 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});284285 expect(result.events).to.be.like({286 Transfer: {287 address,288 event: 'Transfer',289 returnValues: {290 from: helper.address.substrateToEth(alice.address),291 to: receiver,292 value: '51',293 },294 },295 Approval: {296 address,297 event: 'Approval',298 returnValues: {299 owner: helper.address.substrateToEth(alice.address),300 spender: sender,301 value: '49',302 },303 }});304305 const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});306 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);307 const toBalanceAfter = await collection.getBalance({Ethereum: receiver});308 expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);309 });310});311312describe('Fungible: Fees', () => {313 let donor: IKeyringPair;314 let alice: IKeyringPair;315316 before(async function() {317 await usingEthPlaygrounds(async (helper, privateKey) => {318 donor = await privateKey({filename: __filename});319 [alice] = await helper.arrange.createAccounts([20n], donor);320 });321 });322 323 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {324 const owner = await helper.eth.createAccountWithBalance(donor);325 const spender = helper.eth.createAccount();326 const collection = await helper.ft.mintCollection(alice);327 await collection.mint(alice, 200n, {Ethereum: owner});328329 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);330 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);331332 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));333 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));334 });335336 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {337 const owner = await helper.eth.createAccountWithBalance(donor);338 const spender = await helper.eth.createAccountWithBalance(donor);339 const collection = await helper.ft.mintCollection(alice);340 await collection.mint(alice, 200n, {Ethereum: owner});341342 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);343 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);344345 await contract.methods.approve(spender, 100).send({from: owner});346347 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));348 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));349 });350351 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {352 const owner = await helper.eth.createAccountWithBalance(donor);353 const receiver = helper.eth.createAccount();354 const collection = await helper.ft.mintCollection(alice);355 await collection.mint(alice, 200n, {Ethereum: owner});356357 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);358 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);359360 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));361 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));362 });363});364365describe('Fungible: Substrate calls', () => {366 let donor: IKeyringPair;367 let alice: IKeyringPair;368369 before(async function() {370 await usingEthPlaygrounds(async (helper, privateKey) => {371 donor = await privateKey({filename: __filename});372 [alice] = await helper.arrange.createAccounts([20n], donor);373 });374 });375376 itEth('Events emitted for approve()', async ({helper}) => {377 const receiver = helper.eth.createAccount();378 const collection = await helper.ft.mintCollection(alice);379 await collection.mint(alice, 200n);380381 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);382 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');383384 const events: any = [];385 contract.events.allEvents((_: any, event: any) => {386 events.push(event);387 });388 389 await collection.approveTokens(alice, {Ethereum: receiver}, 100n);390 if (events.length == 0) await helper.wait.newBlocks(1);391 const event = events[0];392393 expect(event.event).to.be.equal('Approval');394 expect(event.address).to.be.equal(collectionAddress);395 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));396 expect(event.returnValues.spender).to.be.equal(receiver);397 expect(event.returnValues.value).to.be.equal('100');398 });399400 itEth('Events emitted for transferFrom()', async ({helper}) => {401 const [bob] = await helper.arrange.createAccounts([10n], donor);402 const receiver = helper.eth.createAccount();403 const collection = await helper.ft.mintCollection(alice);404 await collection.mint(alice, 200n);405 await collection.approveTokens(alice, {Substrate: bob.address}, 100n);406407 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);408 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');409410 const events: any = [];411 contract.events.allEvents((_: any, event: any) => {412 events.push(event);413 });414415 await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);416 if (events.length == 0) await helper.wait.newBlocks(1);417 let event = events[0];418419 expect(event.event).to.be.equal('Transfer');420 expect(event.address).to.be.equal(collectionAddress);421 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));422 expect(event.returnValues.to).to.be.equal(receiver);423 expect(event.returnValues.value).to.be.equal('51');424425 event = events[1];426 expect(event.event).to.be.equal('Approval');427 expect(event.address).to.be.equal(collectionAddress);428 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));429 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));430 expect(event.returnValues.value).to.be.equal('49');431 });432433 itEth('Events emitted for transfer()', async ({helper}) => {434 const receiver = helper.eth.createAccount();435 const collection = await helper.ft.mintCollection(alice);436 await collection.mint(alice, 200n);437438 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);439 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');440441 const events: any = [];442 contract.events.allEvents((_: any, event: any) => {443 events.push(event);444 });445 446 await collection.transfer(alice, {Ethereum:receiver}, 51n);447 if (events.length == 0) await helper.wait.newBlocks(1);448 const event = events[0];449450 expect(event.event).to.be.equal('Transfer');451 expect(event.address).to.be.equal(collectionAddress);452 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));453 expect(event.returnValues.to).to.be.equal(receiver);454 expect(event.returnValues.value).to.be.equal('51');455 });456457 itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {458 const alice = await privateKey('//Alice');459 const sender = await helper.eth.createAccountWithBalance(alice, 100n);460461 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);462463 const receiver = helper.eth.createAccount();464465 await collection.mint(alice, 200n, {Substrate: alice.address});466 await collection.approveTokens(alice, {Ethereum: sender}, 100n);467468 const address = helper.ethAddress.fromCollectionId(collection.collectionId);469 const contract = helper.ethNativeContract.collection(address, 'ft');470471 const from = helper.ethCrossAccount.fromKeyringPair(alice);472 const to = helper.ethCrossAccount.fromAddress(receiver);473 474 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});475476 expect(result.events).to.be.like({477 Transfer: {478 address,479 event: 'Transfer',480 returnValues: {481 from: helper.address.substrateToEth(alice.address),482 to: receiver,483 value: '51',484 },485 },486 Approval: {487 address,488 event: 'Approval',489 returnValues: {490 owner: helper.address.substrateToEth(alice.address),491 spender: sender,492 value: '49',493 },494 }});495 });496});