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}) => {152 const sender = await helper.eth.createAccountWithBalance(donor, 100n);153154 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);155156 await collection.mint(alice, 200n, {Substrate: alice.address});157 await collection.approveTokens(alice, {Ethereum: sender}, 100n);158159 const address = helper.ethAddress.fromCollectionId(collection.collectionId);160 const contract = helper.ethNativeContract.collection(address, 'ft');161162 const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});163 164 const ownerCross = helper.ethCrossAccount.fromKeyringPair(alice);165 const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});166 const events = result.events;167168 expect(events).to.be.like({169 Transfer: {170 address: helper.ethAddress.fromCollectionId(collection.collectionId),171 event: 'Transfer',172 returnValues: {173 from: helper.address.substrateToEth(alice.address),174 to: '0x0000000000000000000000000000000000000000',175 value: '49',176 },177 },178 Approval: {179 address: helper.ethAddress.fromCollectionId(collection.collectionId),180 returnValues: {181 owner: helper.address.substrateToEth(alice.address),182 spender: sender,183 value: '51',184 },185 event: 'Approval',186 },187 });188189 const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});190 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);191 });192193 itEth('Can perform transferFrom()', async ({helper}) => {194 const owner = await helper.eth.createAccountWithBalance(donor);195 const spender = await helper.eth.createAccountWithBalance(donor);196 const receiver = helper.eth.createAccount();197 const collection = await helper.ft.mintCollection(alice);198 await collection.mint(alice, 200n, {Ethereum: owner});199200 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);201 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);202203 await contract.methods.approve(spender, 100).send();204205 {206 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});207 208 let event = result.events.Transfer;209 expect(event.address).to.be.equal(collectionAddress);210 expect(event.returnValues.from).to.be.equal(owner);211 expect(event.returnValues.to).to.be.equal(receiver);212 expect(event.returnValues.value).to.be.equal('49');213214 event = result.events.Approval;215 expect(event.address).to.be.equal(collectionAddress);216 expect(event.returnValues.owner).to.be.equal(owner);217 expect(event.returnValues.spender).to.be.equal(spender);218 expect(event.returnValues.value).to.be.equal('51');219 }220221 {222 const balance = await contract.methods.balanceOf(receiver).call();223 expect(+balance).to.equal(49);224 }225226 {227 const balance = await contract.methods.balanceOf(owner).call();228 expect(+balance).to.equal(151);229 }230 });231232 itEth('Can perform transfer()', async ({helper}) => {233 const owner = await helper.eth.createAccountWithBalance(donor);234 const receiver = await helper.eth.createAccountWithBalance(donor);235 const collection = await helper.ft.mintCollection(alice);236 await collection.mint(alice, 200n, {Ethereum: owner});237238 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);239 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);240241 {242 const result = await contract.methods.transfer(receiver, 50).send({from: owner});243 244 const event = result.events.Transfer;245 expect(event.address).to.be.equal(collectionAddress);246 expect(event.returnValues.from).to.be.equal(owner);247 expect(event.returnValues.to).to.be.equal(receiver);248 expect(event.returnValues.value).to.be.equal('50');249 }250251 {252 const balance = await contract.methods.balanceOf(owner).call();253 expect(+balance).to.equal(150);254 }255256 {257 const balance = await contract.methods.balanceOf(receiver).call();258 expect(+balance).to.equal(50);259 }260 });261262 itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {263 const sender = await helper.eth.createAccountWithBalance(donor, 100n);264265 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);266267 const receiver = helper.eth.createAccount();268269 await collection.mint(alice, 200n, {Substrate: alice.address});270 await collection.approveTokens(alice, {Ethereum: sender}, 100n);271272 const address = helper.ethAddress.fromCollectionId(collection.collectionId);273 const contract = helper.ethNativeContract.collection(address, 'ft');274275 const from = helper.ethCrossAccount.fromKeyringPair(alice);276 const to = helper.ethCrossAccount.fromAddress(receiver);277278 const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});279 const toBalanceBefore = await collection.getBalance({Ethereum: receiver});280 281 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});282283 expect(result.events).to.be.like({284 Transfer: {285 address,286 event: 'Transfer',287 returnValues: {288 from: helper.address.substrateToEth(alice.address),289 to: receiver,290 value: '51',291 },292 },293 Approval: {294 address,295 event: 'Approval',296 returnValues: {297 owner: helper.address.substrateToEth(alice.address),298 spender: sender,299 value: '49',300 },301 }});302303 const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});304 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);305 const toBalanceAfter = await collection.getBalance({Ethereum: receiver});306 expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);307 });308});309310describe('Fungible: Fees', () => {311 let donor: IKeyringPair;312 let alice: IKeyringPair;313314 before(async function() {315 await usingEthPlaygrounds(async (helper, privateKey) => {316 donor = await privateKey({filename: __filename});317 [alice] = await helper.arrange.createAccounts([20n], donor);318 });319 });320 321 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {322 const owner = await helper.eth.createAccountWithBalance(donor);323 const spender = helper.eth.createAccount();324 const collection = await helper.ft.mintCollection(alice);325 await collection.mint(alice, 200n, {Ethereum: owner});326327 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);328 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);329330 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));331 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));332 });333334 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {335 const owner = await helper.eth.createAccountWithBalance(donor);336 const spender = await helper.eth.createAccountWithBalance(donor);337 const collection = await helper.ft.mintCollection(alice);338 await collection.mint(alice, 200n, {Ethereum: owner});339340 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);341 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);342343 await contract.methods.approve(spender, 100).send({from: owner});344345 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));346 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));347 });348349 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {350 const owner = await helper.eth.createAccountWithBalance(donor);351 const receiver = helper.eth.createAccount();352 const collection = await helper.ft.mintCollection(alice);353 await collection.mint(alice, 200n, {Ethereum: owner});354355 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);356 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);357358 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));359 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));360 });361});362363describe('Fungible: Substrate calls', () => {364 let donor: IKeyringPair;365 let alice: IKeyringPair;366367 before(async function() {368 await usingEthPlaygrounds(async (helper, privateKey) => {369 donor = await privateKey({filename: __filename});370 [alice] = await helper.arrange.createAccounts([20n], donor);371 });372 });373374 itEth('Events emitted for approve()', async ({helper}) => {375 const receiver = helper.eth.createAccount();376 const collection = await helper.ft.mintCollection(alice);377 await collection.mint(alice, 200n);378379 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);380 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');381382 const events: any = [];383 contract.events.allEvents((_: any, event: any) => {384 events.push(event);385 });386 387 await collection.approveTokens(alice, {Ethereum: receiver}, 100n);388 if (events.length == 0) await helper.wait.newBlocks(1);389 const event = events[0];390391 expect(event.event).to.be.equal('Approval');392 expect(event.address).to.be.equal(collectionAddress);393 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));394 expect(event.returnValues.spender).to.be.equal(receiver);395 expect(event.returnValues.value).to.be.equal('100');396 });397398 itEth('Events emitted for transferFrom()', async ({helper}) => {399 const [bob] = await helper.arrange.createAccounts([10n], donor);400 const receiver = helper.eth.createAccount();401 const collection = await helper.ft.mintCollection(alice);402 await collection.mint(alice, 200n);403 await collection.approveTokens(alice, {Substrate: bob.address}, 100n);404405 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);406 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');407408 const events: any = [];409 contract.events.allEvents((_: any, event: any) => {410 events.push(event);411 });412413 await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);414 if (events.length == 0) await helper.wait.newBlocks(1);415 let event = events[0];416417 expect(event.event).to.be.equal('Transfer');418 expect(event.address).to.be.equal(collectionAddress);419 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));420 expect(event.returnValues.to).to.be.equal(receiver);421 expect(event.returnValues.value).to.be.equal('51');422423 event = events[1];424 expect(event.event).to.be.equal('Approval');425 expect(event.address).to.be.equal(collectionAddress);426 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));427 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));428 expect(event.returnValues.value).to.be.equal('49');429 });430431 itEth('Events emitted for transfer()', async ({helper}) => {432 const receiver = helper.eth.createAccount();433 const collection = await helper.ft.mintCollection(alice);434 await collection.mint(alice, 200n);435436 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);437 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');438439 const events: any = [];440 contract.events.allEvents((_: any, event: any) => {441 events.push(event);442 });443 444 await collection.transfer(alice, {Ethereum:receiver}, 51n);445 if (events.length == 0) await helper.wait.newBlocks(1);446 const event = events[0];447448 expect(event.event).to.be.equal('Transfer');449 expect(event.address).to.be.equal(collectionAddress);450 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));451 expect(event.returnValues.to).to.be.equal(receiver);452 expect(event.returnValues.value).to.be.equal('51');453 });454455 itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {456 const sender = await helper.eth.createAccountWithBalance(donor, 100n);457458 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);459460 const receiver = helper.eth.createAccount();461462 await collection.mint(alice, 200n, {Substrate: alice.address});463 await collection.approveTokens(alice, {Ethereum: sender}, 100n);464465 const address = helper.ethAddress.fromCollectionId(collection.collectionId);466 const contract = helper.ethNativeContract.collection(address, 'ft');467468 const from = helper.ethCrossAccount.fromKeyringPair(alice);469 const to = helper.ethCrossAccount.fromAddress(receiver);470 471 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});472473 expect(result.events).to.be.like({474 Transfer: {475 address,476 event: 'Transfer',477 returnValues: {478 from: helper.address.substrateToEth(alice.address),479 to: receiver,480 value: '51',481 },482 },483 Approval: {484 address,485 event: 'Approval',486 returnValues: {487 owner: helper.address.substrateToEth(alice.address),488 spender: sender,489 value: '49',490 },491 }});492 });493});