git.delta.rocks / unique-network / refs/commits / ed1eea85386f

difftreelog

tests(eth): NFT, RFT, FT tests refactored for playgrounds

Fahrrader2022-09-27parent: #edc6ac8.patch.diff
in: master

6 files changed

modifiedtests/package.jsondiffbeforeafterboth
87 "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",87 "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
88 "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts",88 "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts",
89 "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.test.ts",89 "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.test.ts",
90 "testEthNFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/nonFungible.test.ts",
90 "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",91 "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",
92 "testEthRFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/reFungible.test.ts ./**/eth/reFungibleToken.test.ts",
91 "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",93 "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",
94 "testEthFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/fungible.test.ts",
92 "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",95 "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",
93 "testPromotion": "mocha --timeout 9999999 -r ts-node/register ./**/app-promotion.test.ts",96 "testPromotion": "mocha --timeout 9999999 -r ts-node/register ./**/app-promotion.test.ts",
94 "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",97 "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {approveExpectSuccess, createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';17import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';18import {IKeyringPair} from '@polkadot/types/types';
19import fungibleAbi from './fungibleAbi.json';
20import {expect} from 'chai';
21import {submitTransactionAsync} from '../substrate/substrate-api';
2219
23describe('Fungible: Information getting', () => {20describe('Fungible: Information getting', () => {
24 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {21 let donor: IKeyringPair;
22 let alice: IKeyringPair;
23
25 const collection = await createCollectionExpectSuccess({24 before(async function() {
25 await usingEthPlaygrounds(async (helper, privateKey) => {
26 name: 'token name',26 donor = privateKey('//Alice');
27 mode: {type: 'Fungible', decimalPoints: 0},27 [alice] = await helper.arrange.createAccounts([20n], donor);
28 });28 });
29 const alice = privateKeyWrapper('//Alice');29 });
3030
31 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);31 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);
3235
33 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});36 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);
34
35 const address = collectionIdToAddress(collection);
36 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});
37 const totalSupply = await contract.methods.totalSupply().call();37 const totalSupply = await contract.methods.totalSupply().call();
38
39 expect(totalSupply).to.equal('200');38 expect(totalSupply).to.equal('200');
40 });39 });
4140
42 itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {41 itEth('balanceOf', async ({helper}) => {
43 const collection = await createCollectionExpectSuccess({42 const caller = await helper.eth.createAccountWithBalance(donor);
44 name: 'token name',43 const collection = await helper.ft.mintCollection(alice);
45 mode: {type: 'Fungible', decimalPoints: 0},44 await collection.mint(alice, 200n, {Ethereum: caller});
46 });
47 const alice = privateKeyWrapper('//Alice');
4845
49 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);46 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller);
50
51 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});
52
53 const address = collectionIdToAddress(collection);
54 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});
55 const balance = await contract.methods.balanceOf(caller).call();47 const balance = await contract.methods.balanceOf(caller).call();
56
57 expect(balance).to.equal('200');48 expect(balance).to.equal('200');
58 });49 });
59});50});
6051
61describe('Fungible: Plain calls', () => {52describe('Fungible: Plain calls', () => {
62 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {53 let donor: IKeyringPair;
54 let alice: IKeyringPair;
55
56 before(async function() {
57 await usingEthPlaygrounds(async (helper, privateKey) => {
63 const alice = privateKeyWrapper('//Alice');58 donor = privateKey('//Alice');
64 const collection = await createCollection(api, alice, {59 [alice] = await helper.arrange.createAccounts([20n], donor);
65 name: 'token name',
66 mode: {type: 'Fungible', decimalPoints: 0},
67 });60 });
61 });
6862
69 const receiver = createEthAccount(web3);63 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});
7068
71 const collectionIdAddress = collectionIdToAddress(collection.collectionId);69 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
72 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);70 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
73 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
74 await submitTransactionAsync(alice, changeAdminTx);
7571
76 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});72 const result = await contract.methods.mint(receiver, 100).send();
77 const result = await collectionContract.methods.mint(receiver, 100).send();
78 const events = normalizeEvents(result.events);
79 73
80 expect(events).to.be.deep.equal([74 const event = result.events.Transfer;
81 {
82 address: collectionIdAddress,75 expect(event.address).to.equal(collectionAddress);
83 event: 'Transfer',76 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
84 args: {
85 from: '0x0000000000000000000000000000000000000000',
86 to: receiver,77 expect(event.returnValues.to).to.equal(receiver);
87 value: '100',78 expect(event.returnValues.value).to.equal('100');
88 },
89 },
90 ]);
91 });79 });
9280
93 itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {81 itEth('Can perform mintBulk()', async ({helper}) => {
94 const alice = privateKeyWrapper('//Alice');82 const owner = await helper.eth.createAccountWithBalance(donor);
95 const collection = await createCollection(api, alice, {83 const bulkSize = 3;
96 name: 'token name',84 const receivers = [...new Array(bulkSize)].map(() => helper.eth.createAccount());
97 mode: {type: 'Fungible', decimalPoints: 0},85 const collection = await helper.ft.mintCollection(alice);
98 });86 await collection.addAdmin(alice, {Ethereum: owner});
9987
100 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);88 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
101 const receiver1 = createEthAccount(web3);89 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
102 const receiver2 = createEthAccount(web3);
103 const receiver3 = createEthAccount(web3);
10490
105 const collectionIdAddress = collectionIdToAddress(collection.collectionId);91 const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => (
106 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
107 await submitTransactionAsync(alice, changeAdminTx);
108
109 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
110 const result = await collectionContract.methods.mintBulk([
111 [receiver1, 10],92 [receivers[i], (i + 1) * 10]
112 [receiver2, 20],
113 [receiver3, 30],
114 ]).send();93 ))).send();
115 const events = normalizeEvents(result.events);94 const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.value - b.returnValues.value);
116
117 expect(events).to.be.deep.contain({
118 address:collectionIdAddress,
119 event: 'Transfer',
120 args: {
121 from: '0x0000000000000000000000000000000000000000',
122 to: receiver1,95 for (let i = 0; i < bulkSize; i++) {
123 value: '10',
124 },96 const event = events[i];
125 });
126 97 expect(event.address).to.equal(collectionAddress);
127 expect(events).to.be.deep.contain({
128 address:collectionIdAddress,98 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
129 event: 'Transfer',
130 args: {
131 from: '0x0000000000000000000000000000000000000000',
132 to: receiver2,
133 value: '20',
134 },
135 });
136 99 expect(event.returnValues.to).to.equal(receivers[i]);
137 expect(events).to.be.deep.contain({
138 address:collectionIdAddress,100 expect(event.returnValues.value).to.equal(String(10 * (i + 1)));
139 event: 'Transfer',
140 args: {
141 from: '0x0000000000000000000000000000000000000000',
142 to: receiver3,
143 value: '30',
144 },101 }
145 });
146 });102 });
147103
148 itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {104 itEth('Can perform burn()', async ({helper}) => {
149 const alice = privateKeyWrapper('//Alice');105 const owner = await helper.eth.createAccountWithBalance(donor);
150 const collection = await createCollection(api, alice, {106 const receiver = await helper.eth.createAccountWithBalance(donor);
151 name: 'token name',107 const collection = await helper.ft.mintCollection(alice);
152 mode: {type: 'Fungible', decimalPoints: 0},108 await collection.addAdmin(alice, {Ethereum: owner});
153 });
154109
155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);110 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
156 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});111 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
157 await submitTransactionAsync(alice, changeAdminTx);112 await contract.methods.mint(receiver, 100).send();
158 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
159113
160 const collectionIdAddress = collectionIdToAddress(collection.collectionId);114 const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver});
161 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
162 await collectionContract.methods.mint(receiver, 100).send();
163
164 const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});
165 115
166 const events = normalizeEvents(result.events);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');
167121
168 expect(events).to.be.deep.equal([122 const balance = await contract.methods.balanceOf(receiver).call();
169 {
170 address: collectionIdAddress,
171 event: 'Transfer',
172 args: {
173 from: receiver,
174 to: '0x0000000000000000000000000000000000000000',
175 value: '49',
176 },
177 },
178 ]);
179
180 const balance = await collectionContract.methods.balanceOf(receiver).call();
181 expect(balance).to.equal('51');123 expect(balance).to.equal('51');
182 });124 });
183125
184 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {126 itEth('Can perform approve()', async ({helper}) => {
185 const collection = await createCollectionExpectSuccess({127 const owner = await helper.eth.createAccountWithBalance(donor);
186 name: 'token name',128 const spender = helper.eth.createAccount();
187 mode: {type: 'Fungible', decimalPoints: 0},129 const collection = await helper.ft.mintCollection(alice);
188 });
189 const alice = privateKeyWrapper('//Alice');130 await collection.mint(alice, 200n, {Ethereum: owner});
190131
191 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);132 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
133 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
192134
193 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
194
195 const spender = createEthAccount(web3);
196
197 const address = collectionIdToAddress(collection);
198 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
199
200 {135 {
201 const result = await contract.methods.approve(spender, 100).send({from: owner});136 const result = await contract.methods.approve(spender, 100).send({from: owner});
202 const events = normalizeEvents(result.events);
203137
204 expect(events).to.be.deep.equal([138 const event = result.events.Approval;
205 {
206 address,139 expect(event.address).to.be.equal(collectionAddress);
207 event: 'Approval',140 expect(event.returnValues.owner).to.be.equal(owner);
208 args: {
209 owner,
210 spender,141 expect(event.returnValues.spender).to.be.equal(spender);
211 value: '100',142 expect(event.returnValues.value).to.be.equal('100');
212 },
213 },
214 ]);
215 }143 }
216144
217 {145 {
220 }148 }
221 });149 });
222150
223 itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {151 itEth('Can perform transferFrom()', async ({helper}) => {
224 const collection = await createCollectionExpectSuccess({152 const owner = await helper.eth.createAccountWithBalance(donor);
225 name: 'token name',153 const spender = await helper.eth.createAccountWithBalance(donor);
226 mode: {type: 'Fungible', decimalPoints: 0},154 const receiver = helper.eth.createAccount();
227 });155 const collection = await helper.ft.mintCollection(alice);
228 const alice = privateKeyWrapper('//Alice');156 await collection.mint(alice, 200n, {Ethereum: owner});
229157
230 const owner = createEthAccount(web3);158 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
231 await transferBalanceToEth(api, alice, owner);159 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
232160
233 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
234
235 const spender = createEthAccount(web3);
236 await transferBalanceToEth(api, alice, spender);
237
238 const receiver = createEthAccount(web3);
239
240 const address = collectionIdToAddress(collection);
241 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
242
243 await contract.methods.approve(spender, 100).send();161 await contract.methods.approve(spender, 100).send();
244162
245 {163 {
246 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});164 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
247 const events = normalizeEvents(result.events);165
166 let event = result.events.Transfer;
248 expect(events).to.be.deep.equal([167 expect(event.address).to.be.equal(collectionAddress);
249 {168 expect(event.returnValues.from).to.be.equal(owner);
250 address,
251 event: 'Transfer',
252 args: {
253 from: owner,
254 to: receiver,169 expect(event.returnValues.to).to.be.equal(receiver);
255 value: '49',170 expect(event.returnValues.value).to.be.equal('49');
256 },171
257 },172 event = result.events.Approval;
258 {173 expect(event.address).to.be.equal(collectionAddress);
259 address,
260 event: 'Approval',174 expect(event.returnValues.owner).to.be.equal(owner);
261 args: {
262 owner,
263 spender,175 expect(event.returnValues.spender).to.be.equal(spender);
264 value: '51',176 expect(event.returnValues.value).to.be.equal('51');
265 },
266 },
267 ]);
268 }177 }
269178
270 {179 {
278 }187 }
279 });188 });
280189
281 itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {190 itEth('Can perform transfer()', async ({helper}) => {
282 const collection = await createCollectionExpectSuccess({191 const owner = await helper.eth.createAccountWithBalance(donor);
283 name: 'token name',192 const receiver = await helper.eth.createAccountWithBalance(donor);
284 mode: {type: 'Fungible', decimalPoints: 0},193 const collection = await helper.ft.mintCollection(alice);
285 });
286 const alice = privateKeyWrapper('//Alice');194 await collection.mint(alice, 200n, {Ethereum: owner});
287195
288 const owner = createEthAccount(web3);196 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
289 await transferBalanceToEth(api, alice, owner);197 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
290198
291 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
292
293 const receiver = createEthAccount(web3);
294 await transferBalanceToEth(api, alice, receiver);
295
296 const address = collectionIdToAddress(collection);
297 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
298
299 {199 {
300 const result = await contract.methods.transfer(receiver, 50).send({from: owner});200 const result = await contract.methods.transfer(receiver, 50).send({from: owner});
301 const events = normalizeEvents(result.events);201
202 const event = result.events.Transfer;
302 expect(events).to.be.deep.equal([203 expect(event.address).to.be.equal(collectionAddress);
303 {204 expect(event.returnValues.from).to.be.equal(owner);
304 address,
305 event: 'Transfer',
306 args: {
307 from: owner,
308 to: receiver,205 expect(event.returnValues.to).to.be.equal(receiver);
309 value: '50',206 expect(event.returnValues.value).to.be.equal('50');
310 },
311 },
312 ]);
313 }207 }
314208
315 {209 {
325});219});
326220
327describe('Fungible: Fees', () => {221describe('Fungible: Fees', () => {
328 itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {222 let donor: IKeyringPair;
223 let alice: IKeyringPair;
224
225 before(async function() {
226 await usingEthPlaygrounds(async (helper, privateKey) => {
329 const collection = await createCollectionExpectSuccess({227 donor = privateKey('//Alice');
330 mode: {type: 'Fungible', decimalPoints: 0},228 [alice] = await helper.arrange.createAccounts([20n], donor);
331 });229 });
332 const alice = privateKeyWrapper('//Alice');230 });
231
232 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
233 const owner = await helper.eth.createAccountWithBalance(donor);
234 const spender = helper.eth.createAccount();
235 const collection = await helper.ft.mintCollection(alice);
236 await collection.mint(alice, 200n, {Ethereum: owner});
333237
334 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);238 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
335 const spender = createEthAccount(web3);239 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
336240
337 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});241 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
338
339 const address = collectionIdToAddress(collection);
340 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
341
342 const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));
343 expect(cost < BigInt(0.2 * Number(UNIQUE)));242 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
344 });243 });
345244
346 itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {245 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
347 const collection = await createCollectionExpectSuccess({246 const owner = await helper.eth.createAccountWithBalance(donor);
348 mode: {type: 'Fungible', decimalPoints: 0},247 const spender = await helper.eth.createAccountWithBalance(donor);
349 });248 const collection = await helper.ft.mintCollection(alice);
350 const alice = privateKeyWrapper('//Alice');249 await collection.mint(alice, 200n, {Ethereum: owner});
351250
352 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);251 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
353 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);252 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
354253
355 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
356
357 const address = collectionIdToAddress(collection);
358 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
359
360 await contract.methods.approve(spender, 100).send({from: owner});254 await contract.methods.approve(spender, 100).send({from: owner});
361255
362 const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));256 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
363 expect(cost < BigInt(0.2 * Number(UNIQUE)));257 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
364 });258 });
365259
366 itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {260 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
367 const collection = await createCollectionExpectSuccess({261 const owner = await helper.eth.createAccountWithBalance(donor);
368 mode: {type: 'Fungible', decimalPoints: 0},262 const receiver = helper.eth.createAccount();
369 });263 const collection = await helper.ft.mintCollection(alice);
370 const alice = privateKeyWrapper('//Alice');264 await collection.mint(alice, 200n, {Ethereum: owner});
371265
372 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);266 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
373 const receiver = createEthAccount(web3);267 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
374268
375 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});269 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
376
377 const address = collectionIdToAddress(collection);
378 const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
379
380 const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
381 expect(cost < BigInt(0.2 * Number(UNIQUE)));270 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
382 });271 });
383});272});
384273
385describe('Fungible: Substrate calls', () => {274describe('Fungible: Substrate calls', () => {
386 itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {275 let donor: IKeyringPair;
276 let alice: IKeyringPair;
277
278 before(async function() {
279 await usingEthPlaygrounds(async (helper, privateKey) => {
387 const collection = await createCollectionExpectSuccess({280 donor = privateKey('//Alice');
388 mode: {type: 'Fungible', decimalPoints: 0},281 [alice] = await helper.arrange.createAccounts([20n], donor);
389 });282 });
390 const alice = privateKeyWrapper('//Alice');283 });
391284
392 const receiver = createEthAccount(web3);285 itEth('Events emitted for approve()', async ({helper}) => {
286 const receiver = helper.eth.createAccount();
287 const collection = await helper.ft.mintCollection(alice);
288 await collection.mint(alice, 200n);
393289
394 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});290 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
291 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
395292
396 const address = collectionIdToAddress(collection);293 const events: any = [];
397 const contract = new web3.eth.Contract(fungibleAbi as any, address);294 contract.events.allEvents((_: any, event: any) => {
398
399 const events = await recordEvents(contract, async () => {
400 await approveExpectSuccess(collection, 0, alice, {Ethereum: receiver}, 100);295 events.push(event);
401 });296 });
297 await collection.approveTokens(alice, {Ethereum: receiver}, 100n);
402298
403 expect(events).to.be.deep.equal([299 const event = events[0];
404 {
405 address,
406 event: 'Approval',300 expect(event.event).to.be.equal('Approval');
407 args: {301 expect(event.address).to.be.equal(collectionAddress);
408 owner: subToEth(alice.address),302 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
409 spender: receiver,303 expect(event.returnValues.spender).to.be.equal(receiver);
410 value: '100',304 expect(event.returnValues.value).to.be.equal('100');
411 },
412 },
413 ]);
414 });305 });
415306
416 itWeb3('Events emitted for transferFrom()', async ({web3, privateKeyWrapper}) => {307 itEth('Events emitted for transferFrom()', async ({helper}) => {
417 const collection = await createCollectionExpectSuccess({308 const [bob] = await helper.arrange.createAccounts([10n], donor);
418 mode: {type: 'Fungible', decimalPoints: 0},309 const receiver = helper.eth.createAccount();
419 });310 const collection = await helper.ft.mintCollection(alice);
420 const alice = privateKeyWrapper('//Alice');311 await collection.mint(alice, 200n);
421 const bob = privateKeyWrapper('//Bob');312 await collection.approveTokens(alice, {Substrate: bob.address}, 100n);
422313
423 const receiver = createEthAccount(web3);314 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
315 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
424316
425 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});317 const events: any = [];
426 await approveExpectSuccess(collection, 0, alice, bob.address, 100);
427
428 const address = collectionIdToAddress(collection);
429 const contract = new web3.eth.Contract(fungibleAbi as any, address);318 contract.events.allEvents((_: any, event: any) => {
430
431 const events = await recordEvents(contract, async () => {
432 await transferFromExpectSuccess(collection, 0, bob, alice, {Ethereum: receiver}, 51, 'Fungible');319 events.push(event);
433 });320 });
321 await collection.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n);
434322
435 expect(events).to.be.deep.equal([323 let event = events[0];
436 {
437 address,
438 event: 'Transfer',324 expect(event.event).to.be.equal('Transfer');
439 args: {325 expect(event.address).to.be.equal(collectionAddress);
440 from: subToEth(alice.address),
441 to: receiver,
442 value: '51',326 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
443 },
444 },
445 {
446 address,
447 event: 'Approval',
448 args: {
449 owner: subToEth(alice.address),
450 spender: subToEth(bob.address),327 expect(event.returnValues.to).to.be.equal(receiver);
451 value: '49',328 expect(event.returnValues.value).to.be.equal('51');
452 },
453 },
454 ]);
455 });
456329
457 itWeb3('Events emitted for transfer()', async ({web3, privateKeyWrapper}) => {330 event = events[1];
458 const collection = await createCollectionExpectSuccess({331 expect(event.event).to.be.equal('Approval');
332 expect(event.address).to.be.equal(collectionAddress);
459 mode: {type: 'Fungible', decimalPoints: 0},333 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
460 });334 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
461 const alice = privateKeyWrapper('//Alice');335 expect(event.returnValues.value).to.be.equal('49');
462
463 const receiver = createEthAccount(web3);336 });
464337
465 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n});338 itEth('Events emitted for transfer()', async ({helper}) => {
339 const receiver = helper.eth.createAccount();
340 const collection = await helper.ft.mintCollection(alice);
341 await collection.mint(alice, 200n);
466342
467 const address = collectionIdToAddress(collection);343 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
468 const contract = new web3.eth.Contract(fungibleAbi as any, address);344 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft');
469345
470 const events = await recordEvents(contract, async () => {346 const events: any = [];
347 contract.events.allEvents((_: any, event: any) => {
471 await transferExpectSuccess(collection, 0, alice, {Ethereum:receiver}, 51, 'Fungible');348 events.push(event);
472 });349 });
350 await collection.transfer(alice, {Ethereum:receiver}, 51n);
473351
474 expect(events).to.be.deep.equal([352 const event = events[0];
475 {
476 address,
477 event: 'Transfer',353 expect(event.event).to.be.equal('Transfer');
478 args: {354 expect(event.address).to.be.equal(collectionAddress);
479 from: subToEth(alice.address),355 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
480 to: receiver,356 expect(event.returnValues.to).to.be.equal(receiver);
481 value: '51',357 expect(event.returnValues.value).to.be.equal('51');
482 },
483 },
484 ]);
485 });358 });
486});359});
487360
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';17import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';
18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';18import {IKeyringPair} from '@polkadot/types/types';
19import nonFungibleAbi from './nonFungibleAbi.json';19import {Contract} from 'web3-eth-contract';
20import {expect} from 'chai';
21import {submitTransactionAsync} from '../substrate/substrate-api';
2220
23describe('NFT: Information getting', () => {21describe('NFT: Information getting', () => {
24 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {22 let donor: IKeyringPair;
23 let alice: IKeyringPair;
24
25 before(async function() {
26 await usingEthPlaygrounds(async (helper, privateKey) => {
25 const collection = await createCollectionExpectSuccess({27 donor = privateKey('//Alice');
26 mode: {type: 'NFT'},28 [alice] = await helper.arrange.createAccounts([10n], donor);
27 });29 });
28 const alice = privateKeyWrapper('//Alice');30 });
31
32 itEth('totalSupply', async ({helper}) => {
29 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);33 const collection = await helper.nft.mintCollection(alice, {});
34 await collection.mintToken(alice);
3035
31 await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});36 const caller = await helper.eth.createAccountWithBalance(donor);
3237
33 const address = collectionIdToAddress(collection);38 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
34 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
35 const totalSupply = await contract.methods.totalSupply().call();39 const totalSupply = await contract.methods.totalSupply().call();
3640
37 expect(totalSupply).to.equal('1');41 expect(totalSupply).to.equal('1');
38 });42 });
3943
40 itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {44 itEth('balanceOf', async ({helper}) => {
41 const collection = await createCollectionExpectSuccess({45 const collection = await helper.nft.mintCollection(alice, {});
42 mode: {type: 'NFT'},
43 });
44 const alice = privateKeyWrapper('//Alice');46 const caller = await helper.eth.createAccountWithBalance(donor);
4547
46 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);48 await collection.mintToken(alice, {Ethereum: caller});
47 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum:caller});
48 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});49 await collection.mintToken(alice, {Ethereum: caller});
49 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});50 await collection.mintToken(alice, {Ethereum: caller});
5051
51 const address = collectionIdToAddress(collection);52 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
52 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
53 const balance = await contract.methods.balanceOf(caller).call();53 const balance = await contract.methods.balanceOf(caller).call();
5454
55 expect(balance).to.equal('3');55 expect(balance).to.equal('3');
56 });56 });
5757
58 itWeb3('ownerOf', async ({api, web3, privateKeyWrapper}) => {58 itEth('ownerOf', async ({helper}) => {
59 const collection = await createCollectionExpectSuccess({59 const collection = await helper.nft.mintCollection(alice, {});
60 mode: {type: 'NFT'},
61 });
62 const alice = privateKeyWrapper('//Alice');60 const caller = await helper.eth.createAccountWithBalance(donor);
6361
64 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);62 const token = await collection.mintToken(alice, {Ethereum: caller});
65 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
6663
67 const address = collectionIdToAddress(collection);64 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
68 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
69 const owner = await contract.methods.ownerOf(tokenId).call();
7065
66 const owner = await contract.methods.ownerOf(token.tokenId).call();
67
71 expect(owner).to.equal(caller);68 expect(owner).to.equal(caller);
72 });69 });
73});70});
7471
75describe('Check ERC721 token URI for NFT', () => {72describe('Check ERC721 token URI for NFT', () => {
76 itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {73 let donor: IKeyringPair;
74
75 before(async function() {
76 await usingEthPlaygrounds(async (_helper, privateKey) => {
77 donor = privateKey('//Alice');
78 });
79 });
80
81 async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
77 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);82 const owner = await helper.eth.createAccountWithBalance(donor);
83 const receiver = helper.eth.createAccount();
84
78 const helper = evmCollectionHelpers(web3, owner);85 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
79 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();86 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();
80 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);87 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
81 const receiver = createEthAccount(web3);88 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
82 const contract = evmCollection(web3, owner, collectionIdAddress);
83 89
84 const nextTokenId = await contract.methods.nextTokenId().call();90 const nextTokenId = await contract.methods.nextTokenId().call();
85 expect(nextTokenId).to.be.equal('1');91 expect(nextTokenId).to.be.equal('1');
88 nextTokenId,94 nextTokenId,
89 ).send();95 ).send();
9096
91 const events = normalizeEvents(result.events);97 if (propertyKey && propertyValue) {
92 const address = collectionIdToAddress(collectionId);98 // Set URL or suffix
99 await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
100 }
93101
94 expect(events).to.be.deep.equal([102 const event = result.events.Transfer;
103 expect(event.address).to.be.equal(collectionAddress);
95 {104 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
96 address,
97 event: 'Transfer',
98 args: {
99 from: '0x0000000000000000000000000000000000000000',
100 to: receiver,105 expect(event.returnValues.to).to.be.equal(receiver);
101 tokenId: nextTokenId,106 expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
102 },
103 },
104 ]);
105107
108 return {contract, nextTokenId};
109 }
110
111 itEth('Empty tokenURI', async ({helper}) => {
112 const {contract, nextTokenId} = await setup(helper, '');
106 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');113 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
107 });114 });
108115
109 itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {116 itEth('TokenURI from url', async ({helper}) => {
110 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);117 const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');
111 const helper = evmCollectionHelpers(web3, owner);
112 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
113 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
114 const receiver = createEthAccount(web3);
115 const contract = evmCollection(web3, owner, collectionIdAddress);
116
117 const nextTokenId = await contract.methods.nextTokenId().call();
118 expect(nextTokenId).to.be.equal('1');
119 result = await contract.methods.mint(
120 receiver,
121 nextTokenId,
122 ).send();
123
124 // Set URL
125 await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
126
127 const events = normalizeEvents(result.events);
128 const address = collectionIdToAddress(collectionId);
129
130 expect(events).to.be.deep.equal([
131 {
132 address,
133 event: 'Transfer',
134 args: {
135 from: '0x0000000000000000000000000000000000000000',
136 to: receiver,
137 tokenId: nextTokenId,
138 },
139 },
140 ]);
141
142 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');118 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
143 });119 });
144120
145 itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {121 itEth('TokenURI from baseURI + tokenId', async ({helper}) => {
146 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);122 const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
147 const helper = evmCollectionHelpers(web3, owner);
148 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
149 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
150 const receiver = createEthAccount(web3);
151 const contract = evmCollection(web3, owner, collectionIdAddress);
152
153 const nextTokenId = await contract.methods.nextTokenId().call();
154 expect(nextTokenId).to.be.equal('1');
155 result = await contract.methods.mint(
156 receiver,
157 nextTokenId,
158 ).send();
159
160 const events = normalizeEvents(result.events);
161 const address = collectionIdToAddress(collectionId);
162
163 expect(events).to.be.deep.equal([
164 {
165 address,
166 event: 'Transfer',
167 args: {
168 from: '0x0000000000000000000000000000000000000000',
169 to: receiver,
170 tokenId: nextTokenId,
171 },
172 },
173 ]);
174
175 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);123 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
176 });124 });
177125
178 itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {126 itEth('TokenURI from baseURI + suffix', async ({helper}) => {
179 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
180 const helper = evmCollectionHelpers(web3, owner);
181 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
182 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
183 const receiver = createEthAccount(web3);
184 const contract = evmCollection(web3, owner, collectionIdAddress);
185
186 const nextTokenId = await contract.methods.nextTokenId().call();
187 expect(nextTokenId).to.be.equal('1');
188 result = await contract.methods.mint(
189 receiver,
190 nextTokenId,
191 ).send();
192
193 // Set suffix
194 const suffix = '/some/suffix';127 const suffix = '/some/suffix';
195 await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();128 const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);
196
197 const events = normalizeEvents(result.events);
198 const address = collectionIdToAddress(collectionId);
199
200 expect(events).to.be.deep.equal([
201 {
202 address,
203 event: 'Transfer',
204 args: {
205 from: '0x0000000000000000000000000000000000000000',
206 to: receiver,
207 tokenId: nextTokenId,
208 },
209 },
210 ]);
211
212 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);129 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
213 });130 });
214});131});
215132
216describe('NFT: Plain calls', () => {133describe('NFT: Plain calls', () => {
217 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {134 let donor: IKeyringPair;
135 let alice: IKeyringPair;
136
137 before(async function() {
138 await usingEthPlaygrounds(async (helper, privateKey) => {
218 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);139 donor = privateKey('//Alice');
219 const helper = evmCollectionHelpers(web3, owner);140 [alice] = await helper.arrange.createAccounts([10n], donor);
220 let result = await helper.methods.createNonfungibleCollection('Mint collection', '6', '6').send();141 });
142 });
143
144 itEth('Can perform mint()', async ({helper}) => {
221 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);145 const owner = await helper.eth.createAccountWithBalance(donor);
222 const receiver = createEthAccount(web3);146 const receiver = helper.eth.createAccount();
147
223 const contract = evmCollection(web3, owner, collectionIdAddress);148 const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Minty', '6', '6');
149 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
224 const nextTokenId = await contract.methods.nextTokenId().call();150 const nextTokenId = await contract.methods.nextTokenId().call();
225151
226 expect(nextTokenId).to.be.equal('1');152 expect(nextTokenId).to.be.equal('1');
227 result = await contract.methods.mintWithTokenURI(153 const result = await contract.methods.mintWithTokenURI(
228 receiver,154 receiver,
229 nextTokenId,155 nextTokenId,
230 'Test URI',156 'Test URI',
231 ).send();157 ).send();
232158
233 const events = normalizeEvents(result.events);159 const event = result.events.Transfer;
160 expect(event.address).to.be.equal(collectionAddress);
234 const address = collectionIdToAddress(collectionId);161 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
162 expect(event.returnValues.to).to.be.equal(receiver);
163 expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
235164
236 expect(events).to.be.deep.equal([
237 {
238 address,
239 event: 'Transfer',
240 args: {
241 from: '0x0000000000000000000000000000000000000000',
242 to: receiver,
243 tokenId: nextTokenId,
244 },
245 },
246 ]);
247
248 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');165 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
249166
250 // TODO: this wont work right now, need release 919000 first167 // TODO: this wont work right now, need release 919000 first
254 });171 });
255172
256 //TODO: CORE-302 add eth methods173 //TODO: CORE-302 add eth methods
257 itWeb3.skip('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {174 /* todo:playgrounds skipped test!
175 itWeb3.skip('Can perform mintBulk()', async ({helper}) => {
258 const collection = await createCollectionExpectSuccess({176 const collection = await createCollectionExpectSuccess({
259 mode: {type: 'NFT'},177 mode: {type: 'NFT'},
260 });178 });
316 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');234 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
317 }235 }
318 });236 });
237 */
319238
320 itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {239 itEth('Can perform burn()', async ({helper}) => {
321 const collection = await createCollectionExpectSuccess({240 const caller = await helper.eth.createAccountWithBalance(donor);
322 mode: {type: 'NFT'},
323 });
324 const alice = privateKeyWrapper('//Alice');
325241
326 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);242 const collection = await helper.nft.mintCollection(alice, {});
243 const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});
327244
328 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});245 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
246 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
329247
330 const address = collectionIdToAddress(collection);
331 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
332
333 {248 {
334 const result = await contract.methods.burn(tokenId).send({from: owner});249 const result = await contract.methods.burn(tokenId).send({from: caller});
335 const events = normalizeEvents(result.events);250
336251 const event = result.events.Transfer;
337 expect(events).to.be.deep.equal([252 expect(event.address).to.be.equal(collectionAddress);
338 {253 expect(event.returnValues.from).to.be.equal(caller);
339 address,
340 event: 'Transfer',
341 args: {
342 from: owner,
343 to: '0x0000000000000000000000000000000000000000',254 expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
344 tokenId: tokenId.toString(),255 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
345 },
346 },
347 ]);
348 }256 }
349 });257 });
350258
351 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {259 itEth('Can perform approve()', async ({helper}) => {
352 const collection = await createCollectionExpectSuccess({260 const owner = await helper.eth.createAccountWithBalance(donor);
353 mode: {type: 'NFT'},
354 });
355 const alice = privateKeyWrapper('//Alice');261 const spender = helper.eth.createAccount();
356262
357 const owner = createEthAccount(web3);263 const collection = await helper.nft.mintCollection(alice, {});
358 await transferBalanceToEth(api, alice, owner);264 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
359265
360 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});266 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
267 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
361268
362 const spender = createEthAccount(web3);
363
364 const address = collectionIdToAddress(collection);
365 const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
366
367 {269 {
368 const result = await contract.methods.approve(spender, tokenId).send({from: owner, ...GAS_ARGS});270 const result = await contract.methods.approve(spender, tokenId).send({from: owner});
369 const events = normalizeEvents(result.events);
370271
371 expect(events).to.be.deep.equal([272 const event = result.events.Approval;
372 {
373 address,273 expect(event.address).to.be.equal(collectionAddress);
374 event: 'Approval',274 expect(event.returnValues.owner).to.be.equal(owner);
375 args: {
376 owner,
377 approved: spender,275 expect(event.returnValues.approved).to.be.equal(spender);
378 tokenId: tokenId.toString(),276 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
379 },
380 },
381 ]);
382 }277 }
383 });278 });
384279
385 itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {280 itEth('Can perform transferFrom()', async ({helper}) => {
386 const collection = await createCollectionExpectSuccess({281 const owner = await helper.eth.createAccountWithBalance(donor);
387 mode: {type: 'NFT'},282 const spender = await helper.eth.createAccountWithBalance(donor);
388 });
389 const alice = privateKeyWrapper('//Alice');283 const receiver = helper.eth.createAccount();
390284
391 const owner = createEthAccount(web3);285 const collection = await helper.nft.mintCollection(alice, {});
392 await transferBalanceToEth(api, alice, owner);286 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
393287
394 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});288 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
289 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
395290
396 const spender = createEthAccount(web3);
397 await transferBalanceToEth(api, alice, spender);
398
399 const receiver = createEthAccount(web3);
400
401 const address = collectionIdToAddress(collection);
402 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
403
404 await contract.methods.approve(spender, tokenId).send({from: owner});291 await contract.methods.approve(spender, tokenId).send({from: owner});
405292
406 {293 {
407 const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});294 const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});
295
408 const events = normalizeEvents(result.events);296 const event = result.events.Transfer;
409 expect(events).to.be.deep.equal([297 expect(event.address).to.be.equal(collectionAddress);
410 {298 expect(event.returnValues.from).to.be.equal(owner);
411 address,
412 event: 'Transfer',
413 args: {
414 from: owner,
415 to: receiver,299 expect(event.returnValues.to).to.be.equal(receiver);
416 tokenId: tokenId.toString(),300 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
417 },
418 },
419 ]);
420 }301 }
421302
422 {303 {
430 }311 }
431 });312 });
432313
433 itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {314 itEth('Can perform transfer()', async ({helper}) => {
434 const collection = await createCollectionExpectSuccess({315 const collection = await helper.nft.mintCollection(alice, {});
435 mode: {type: 'NFT'},316 const owner = await helper.eth.createAccountWithBalance(donor);
436 });
437 const alice = privateKeyWrapper('//Alice');317 const receiver = helper.eth.createAccount();
438318
439 const owner = createEthAccount(web3);319 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
440 await transferBalanceToEth(api, alice, owner);
441320
442 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});321 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
322 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
443323
444 const receiver = createEthAccount(web3);
445 await transferBalanceToEth(api, alice, receiver);
446
447 const address = collectionIdToAddress(collection);
448 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
449
450 {324 {
451 const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});325 const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});
326
452 const events = normalizeEvents(result.events);327 const event = result.events.Transfer;
453 expect(events).to.be.deep.equal([328 expect(event.address).to.be.equal(collectionAddress);
454 {329 expect(event.returnValues.from).to.be.equal(owner);
455 address,
456 event: 'Transfer',
457 args: {
458 from: owner,
459 to: receiver,330 expect(event.returnValues.to).to.be.equal(receiver);
460 tokenId: tokenId.toString(),331 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
461 },
462 },
463 ]);
464 }332 }
465333
466 {334 {
476});344});
477345
478describe('NFT: Fees', () => {346describe('NFT: Fees', () => {
479 itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {347 let donor: IKeyringPair;
348 let alice: IKeyringPair;
349
350 before(async function() {
351 await usingEthPlaygrounds(async (helper, privateKey) => {
480 const collection = await createCollectionExpectSuccess({352 donor = privateKey('//Alice');
481 mode: {type: 'NFT'},353 [alice] = await helper.arrange.createAccounts([10n], donor);
482 });354 });
483 const alice = privateKeyWrapper('//Alice');355 });
356
357 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
358 const owner = await helper.eth.createAccountWithBalance(donor);
359 const spender = helper.eth.createAccount();
484360
485 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);361 const collection = await helper.nft.mintCollection(alice, {});
486 const spender = createEthAccount(web3);362 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
487363
488 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});364 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
489365
490 const address = collectionIdToAddress(collection);366 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
491 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
492
493 const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));
494 expect(cost < BigInt(0.2 * Number(UNIQUE)));367 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
495 });368 });
496369
497 itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {370 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
498 const collection = await createCollectionExpectSuccess({371 const owner = await helper.eth.createAccountWithBalance(donor);
499 mode: {type: 'NFT'},
500 });
501 const alice = privateKeyWrapper('//Alice');372 const spender = await helper.eth.createAccountWithBalance(donor);
502373
503 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);374 const collection = await helper.nft.mintCollection(alice, {});
504 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);375 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
505376
506 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});377 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
507378
508 const address = collectionIdToAddress(collection);
509 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
510
511 await contract.methods.approve(spender, tokenId).send({from: owner});379 await contract.methods.approve(spender, tokenId).send({from: owner});
512380
513 const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));381 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));
514 expect(cost < BigInt(0.2 * Number(UNIQUE)));382 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
515 });383 });
516384
517 itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {385 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
518 const collection = await createCollectionExpectSuccess({386 const owner = await helper.eth.createAccountWithBalance(donor);
519 mode: {type: 'NFT'},
520 });
521 const alice = privateKeyWrapper('//Alice');387 const receiver = helper.eth.createAccount();
522388
523 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);389 const collection = await helper.nft.mintCollection(alice, {});
524 const receiver = createEthAccount(web3);390 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});
525391
526 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});392 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);
527393
528 const address = collectionIdToAddress(collection);394 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
529 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
530
531 const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));
532 expect(cost < BigInt(0.2 * Number(UNIQUE)));395 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
533 });396 });
534});397});
535398
536describe('NFT: Substrate calls', () => {399describe('NFT: Substrate calls', () => {
537 itWeb3('Events emitted for mint()', async ({web3, privateKeyWrapper}) => {400 let donor: IKeyringPair;
538 const collection = await createCollectionExpectSuccess({
539 mode: {type: 'NFT'},
540 });
541 const alice = privateKeyWrapper('//Alice');401 let alice: IKeyringPair;
542402
543 const address = collectionIdToAddress(collection);403 before(async function() {
544 const contract = new web3.eth.Contract(nonFungibleAbi as any, address);404 await usingEthPlaygrounds(async (helper, privateKey) => {
545
546 let tokenId: number;
547 const events = await recordEvents(contract, async () => {405 donor = privateKey('//Alice');
548 tokenId = await createItemExpectSuccess(alice, collection, 'NFT');406 [alice] = await helper.arrange.createAccounts([20n], donor);
549 });407 });
550
551 expect(events).to.be.deep.equal([
552 {
553 address,
554 event: 'Transfer',
555 args: {
556 from: '0x0000000000000000000000000000000000000000',
557 to: subToEth(alice.address),
558 tokenId: tokenId!.toString(),
559 },
560 },
561 ]);
562 });408 });
563409
564 itWeb3('Events emitted for burn()', async ({web3, privateKeyWrapper}) => {410 itEth('Events emitted for mint()', async ({helper}) => {
565 const collection = await createCollectionExpectSuccess({411 const collection = await helper.nft.mintCollection(alice, {});
566 mode: {type: 'NFT'},412 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
567 });
568 const alice = privateKeyWrapper('//Alice');413 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
569414
570 const address = collectionIdToAddress(collection);415 const events: any = [];
571 const contract = new web3.eth.Contract(nonFungibleAbi as any, address);416 contract.events.allEvents((_: any, event: any) => {
572
573 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');
574 const events = await recordEvents(contract, async () => {
575 await burnItemExpectSuccess(alice, collection, tokenId);417 events.push(event);
576 });418 });
419 const {tokenId} = await collection.mintToken(alice);
577420
578 expect(events).to.be.deep.equal([421 const event = events[0];
579 {
580 address,
581 event: 'Transfer',422 expect(event.event).to.be.equal('Transfer');
582 args: {423 expect(event.address).to.be.equal(collectionAddress);
583 from: subToEth(alice.address),
584 to: '0x0000000000000000000000000000000000000000',424 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
585 tokenId: tokenId.toString(),425 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(alice.address));
586 },
587 },
588 ]);426 expect(event.returnValues.tokenId).to.be.equal(tokenId.toString());
589 });427 });
590428
591 itWeb3('Events emitted for approve()', async ({web3, privateKeyWrapper}) => {429 itEth('Events emitted for burn()', async ({helper}) => {
592 const collection = await createCollectionExpectSuccess({430 const collection = await helper.nft.mintCollection(alice, {});
593 mode: {type: 'NFT'},431 const token = await collection.mintToken(alice);
432
433 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
434 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
435
436 const events: any = [];
437 contract.events.allEvents((_: any, event: any) => {
438 events.push(event);
594 });439 });
595 const alice = privateKeyWrapper('//Alice');
596440
597 const receiver = createEthAccount(web3);441 await token.burn(alice);
598442
599 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');443 const event = events[0];
444 expect(event.event).to.be.equal('Transfer');
445 expect(event.address).to.be.equal(collectionAddress);
446 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
447 expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
448 expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
449 });
600450
601 const address = collectionIdToAddress(collection);451 itEth('Events emitted for approve()', async ({helper}) => {
602 const contract = new web3.eth.Contract(nonFungibleAbi as any, address);452 const receiver = helper.eth.createAccount();
603453
604 const events = await recordEvents(contract, async () => {454 const collection = await helper.nft.mintCollection(alice, {});
605 await approveExpectSuccess(collection, tokenId, alice, {Ethereum: receiver}, 1);455 const token = await collection.mintToken(alice);
606 });
607456
608 expect(events).to.be.deep.equal([457 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
609 {458 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
610 address,
611 event: 'Approval',
612 args: {
613 owner: subToEth(alice.address),
614 approved: receiver,459
615 tokenId: tokenId.toString(),460 const events: any = [];
616 },
617 },
618 ]);
619 });461 contract.events.allEvents((_: any, event: any) => {
620
621 itWeb3('Events emitted for transferFrom()', async ({web3, privateKeyWrapper}) => {
622 const collection = await createCollectionExpectSuccess({462 events.push(event);
623 mode: {type: 'NFT'},
624 });463 });
625 const alice = privateKeyWrapper('//Alice');
626 const bob = privateKeyWrapper('//Bob');
627464
628 const receiver = createEthAccount(web3);465 await token.approve(alice, {Ethereum: receiver});
629466
630 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');467 const event = events[0];
468 expect(event.event).to.be.equal('Approval');
631 await approveExpectSuccess(collection, tokenId, alice, bob.address, 1);469 expect(event.address).to.be.equal(collectionAddress);
470 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
471 expect(event.returnValues.approved).to.be.equal(receiver);
472 expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());
473 });
632474
633 const address = collectionIdToAddress(collection);475 itEth('Events emitted for transferFrom()', async ({helper}) => {
476 const [bob] = await helper.arrange.createAccounts([10n], donor);
634 const contract = new web3.eth.Contract(nonFungibleAbi as any, address);477 const receiver = helper.eth.createAccount();
635478
636 const events = await recordEvents(contract, async () => {479 const collection = await helper.nft.mintCollection(alice, {});
480 const token = await collection.mintToken(alice);
481 await token.approve(alice, {Substrate: bob.address});
482
637 await transferFromExpectSuccess(collection, tokenId, bob, alice, {Ethereum: receiver}, 1, 'NFT');483 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
484 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
485
486 const events: any = [];
487 contract.events.allEvents((_: any, event: any) => {
488 events.push(event);
638 });489 });
639490
640 expect(events).to.be.deep.equal([491 await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver});
641 {
642 address,
643 event: 'Transfer',492
644 args: {493 const event = events[0];
645 from: subToEth(alice.address),494 expect(event.address).to.be.equal(collectionAddress);
495 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
646 to: receiver,496 expect(event.returnValues.to).to.be.equal(receiver);
647 tokenId: tokenId.toString(),497 expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
648 },
649 },
650 ]);
651 });498 });
652499
653 itWeb3('Events emitted for transfer()', async ({web3, privateKeyWrapper}) => {500 itEth('Events emitted for transfer()', async ({helper}) => {
654 const collection = await createCollectionExpectSuccess({501 const receiver = helper.eth.createAccount();
655 mode: {type: 'NFT'},
656 });
657 const alice = privateKeyWrapper('//Alice');
658502
659 const receiver = createEthAccount(web3);503 const collection = await helper.nft.mintCollection(alice, {});
504 const token = await collection.mintToken(alice);
660505
661 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');506 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
662
663 const address = collectionIdToAddress(collection);507 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');
664 const contract = new web3.eth.Contract(nonFungibleAbi as any, address);508
665509 const events: any = [];
666 const events = await recordEvents(contract, async () => {510 contract.events.allEvents((_: any, event: any) => {
667 await transferExpectSuccess(collection, tokenId, alice, {Ethereum: receiver}, 1, 'NFT');511 events.push(event);
668 });512 });
669513
670 expect(events).to.be.deep.equal([514 await token.transfer(alice, {Ethereum: receiver});
671 {515
672 address,516 const event = events[0];
673 event: 'Transfer',517 expect(event.address).to.be.equal(collectionAddress);
674 args: {518 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
675 from: subToEth(alice.address),
676 to: receiver,519 expect(event.returnValues.to).to.be.equal(receiver);
677 tokenId: tokenId.toString(),520 expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
678 },
679 },
680 ]);
681 });521 });
682});522});
683523
684describe('Common metadata', () => {524describe('Common metadata', () => {
685 itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {525 let donor: IKeyringPair;
526 let alice: IKeyringPair;
527
528 before(async function() {
686 const collection = await createCollectionExpectSuccess({529 await usingEthPlaygrounds(async (helper, privateKey) => {
687 name: 'token name',530 donor = privateKey('//Alice');
688 mode: {type: 'NFT'},531 [alice] = await helper.arrange.createAccounts([20n], donor);
689 });532 });
690 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);533 });
691534
692 const address = collectionIdToAddress(collection);535 itEth('Returns collection name', async ({helper}) => {
693 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});536 const caller = await helper.eth.createAccountWithBalance(donor);
694 const name = await contract.methods.name().call();537 const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
695538
696 expect(name).to.equal('token name');539 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
540 const name = await contract.methods.name().call();
541 expect(name).to.equal('oh River');
697 });542 });
698543
699 itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {544 itEth('Returns symbol name', async ({helper}) => {
700 const collection = await createCollectionExpectSuccess({545 const caller = await helper.eth.createAccountWithBalance(donor);
701 tokenPrefix: 'TOK',
702 mode: {type: 'NFT'},
703 });
704 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);546 const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});
705547
706 const address = collectionIdToAddress(collection);548 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);
707 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
708 const symbol = await contract.methods.symbol().call();549 const symbol = await contract.methods.symbol().call();
709
710 expect(symbol).to.equal('TOK');550 expect(symbol).to.equal('CHANGE');
711 });551 });
712});552});
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {createCollectionExpectSuccess, UNIQUE, requirePallets, Pallets} from '../util/helpers';17import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, tokenIdToAddress, uniqueRefungibleToken} from './util/helpers';18import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
19import {expect} from 'chai';19import {IKeyringPair} from '@polkadot/types/types';
2020
21describe('Refungible: Information getting', () => {21describe('Refungible: Information getting', () => {
22 let donor: IKeyringPair;
23
22 before(async function() {24 before(async function() {
23 await requirePallets(this, [Pallets.ReFungible]);25 await usingEthPlaygrounds(async (helper, privateKey) => {
26 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
27
28 donor = privateKey('//Alice');
29 });
24 });30 });
2531
26 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {32 itEth('totalSupply', async ({helper}) => {
27 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);33 const caller = await helper.eth.createAccountWithBalance(donor);
28 const helper = evmCollectionHelpers(web3, caller);
29 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();34 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TotalSupply', '6', '6');
30 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);35 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
31 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
32 const nextTokenId = await contract.methods.nextTokenId().call();36 const nextTokenId = await contract.methods.nextTokenId().call();
33 await contract.methods.mint(caller, nextTokenId).send();37 await contract.methods.mint(caller, nextTokenId).send();
34 const totalSupply = await contract.methods.totalSupply().call();38 const totalSupply = await contract.methods.totalSupply().call();
35 expect(totalSupply).to.equal('1');39 expect(totalSupply).to.equal('1');
36 });40 });
3741
38 itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {42 itEth('balanceOf', async ({helper}) => {
39 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const caller = await helper.eth.createAccountWithBalance(donor);
40 const helper = evmCollectionHelpers(web3, caller);
41 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();44 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'BalanceOf', '6', '6');
42 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);45 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
43 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
4446
45 {47 {
46 const nextTokenId = await contract.methods.nextTokenId().call();48 const nextTokenId = await contract.methods.nextTokenId().call();
56 }58 }
5759
58 const balance = await contract.methods.balanceOf(caller).call();60 const balance = await contract.methods.balanceOf(caller).call();
59
60 expect(balance).to.equal('3');61 expect(balance).to.equal('3');
61 });62 });
6263
63 itWeb3('ownerOf', async ({api, web3, privateKeyWrapper}) => {64 itEth('ownerOf', async ({helper}) => {
64 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);65 const caller = await helper.eth.createAccountWithBalance(donor);
65 const helper = evmCollectionHelpers(web3, caller);
66 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();66 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'OwnerOf', '6', '6');
67 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);67 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
68 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
6968
70 const tokenId = await contract.methods.nextTokenId().call();69 const tokenId = await contract.methods.nextTokenId().call();
71 await contract.methods.mint(caller, tokenId).send();70 await contract.methods.mint(caller, tokenId).send();
7271
73 const owner = await contract.methods.ownerOf(tokenId).call();72 const owner = await contract.methods.ownerOf(tokenId).call();
74
75 expect(owner).to.equal(caller);73 expect(owner).to.equal(caller);
76 });74 });
7775
78 itWeb3('ownerOf after burn', async ({api, web3, privateKeyWrapper}) => {76 itEth('ownerOf after burn', async ({helper}) => {
79 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);77 const caller = await helper.eth.createAccountWithBalance(donor);
80 const receiver = createEthAccount(web3);78 const receiver = helper.eth.createAccount();
81 const helper = evmCollectionHelpers(web3, caller);79 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'OwnerOf-AfterBurn', '6', '6');
82 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
83 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);80 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
84 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
8581
86 const tokenId = await contract.methods.nextTokenId().call();82 const tokenId = await contract.methods.nextTokenId().call();
87 await contract.methods.mint(caller, tokenId).send();83 await contract.methods.mint(caller, tokenId).send();
84 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
8885
89 const tokenAddress = tokenIdToAddress(collectionId, tokenId);
90 const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
91
92 await tokenContract.methods.repartition(2).send();86 await tokenContract.methods.repartition(2).send();
93 await tokenContract.methods.transfer(receiver, 1).send();87 await tokenContract.methods.transfer(receiver, 1).send();
9488
95 await tokenContract.methods.burnFrom(caller, 1).send();89 await tokenContract.methods.burnFrom(caller, 1).send();
9690
97 const owner = await contract.methods.ownerOf(tokenId).call();91 const owner = await contract.methods.ownerOf(tokenId).call();
98
99 expect(owner).to.equal(receiver);92 expect(owner).to.equal(receiver);
100 });93 });
10194
102 itWeb3('ownerOf for partial ownership', async ({api, web3, privateKeyWrapper}) => {95 itEth('ownerOf for partial ownership', async ({helper}) => {
103 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);96 const caller = await helper.eth.createAccountWithBalance(donor);
104 const receiver = createEthAccount(web3);97 const receiver = helper.eth.createAccount();
105 const helper = evmCollectionHelpers(web3, caller);98 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Partial-OwnerOf', '6', '6');
106 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
107 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);99 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
108 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
109100
110 const tokenId = await contract.methods.nextTokenId().call();101 const tokenId = await contract.methods.nextTokenId().call();
111 await contract.methods.mint(caller, tokenId).send();102 await contract.methods.mint(caller, tokenId).send();
103 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
112104
113 const tokenAddress = tokenIdToAddress(collectionId, tokenId);
114 const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
115
116 await tokenContract.methods.repartition(2).send();105 await tokenContract.methods.repartition(2).send();
117 await tokenContract.methods.transfer(receiver, 1).send();106 await tokenContract.methods.transfer(receiver, 1).send();
118107
119 const owner = await contract.methods.ownerOf(tokenId).call();108 const owner = await contract.methods.ownerOf(tokenId).call();
120
121 expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');109 expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
122 });110 });
123});111});
124112
125describe('Refungible: Plain calls', () => {113describe('Refungible: Plain calls', () => {
114 let donor: IKeyringPair;
115
126 before(async function() {116 before(async function() {
127 await requirePallets(this, [Pallets.ReFungible]);117 await usingEthPlaygrounds(async (helper, privateKey) => {
118 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
119
120 donor = privateKey('//Alice');
121 });
128 });122 });
129123
130 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {124 itEth('Can perform mint()', async ({helper}) => {
131 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);125 const owner = await helper.eth.createAccountWithBalance(donor);
132 const helper = evmCollectionHelpers(web3, owner);126 const receiver = helper.eth.createAccount();
133 let result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();127 const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Minty', '6', '6');
134 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);128 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
135 const receiver = createEthAccount(web3);
136 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});129
137 const nextTokenId = await contract.methods.nextTokenId().call();130 const nextTokenId = await contract.methods.nextTokenId().call();
138
139 expect(nextTokenId).to.be.equal('1');131 expect(nextTokenId).to.be.equal('1');
140 result = await contract.methods.mintWithTokenURI(132 const result = await contract.methods.mintWithTokenURI(
141 receiver,133 receiver,
142 nextTokenId,134 nextTokenId,
143 'Test URI',135 'Test URI',
144 ).send();136 ).send();
145137
146 const events = normalizeEvents(result.events);138 const event = result.events.Transfer;
139 expect(event.address).to.equal(collectionAddress);
140 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
141 expect(event.returnValues.to).to.equal(receiver);
142 expect(event.returnValues.tokenId).to.equal(nextTokenId);
147143
148 expect(events).to.include.deep.members([
149 {
150 address: collectionIdAddress,
151 event: 'Transfer',
152 args: {
153 from: '0x0000000000000000000000000000000000000000',
154 to: receiver,
155 tokenId: nextTokenId,
156 },
157 },
158 ]);
159
160 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');144 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
161 });145 });
162146
163 itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {147 itEth('Can perform mintBulk()', async ({helper}) => {
164 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);148 const owner = await helper.eth.createAccountWithBalance(donor);
165 const helper = evmCollectionHelpers(web3, caller);149 const receiver = helper.eth.createAccount();
166 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();150 const {collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'MintBulky', '6', '6');
167 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);151 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
168 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
169152
170 const receiver = createEthAccount(web3);
171
172 {153 {
173 const nextTokenId = await contract.methods.nextTokenId().call();154 const nextTokenId = await contract.methods.nextTokenId().call();
174 expect(nextTokenId).to.be.equal('1');155 expect(nextTokenId).to.be.equal('1');
180 [+nextTokenId + 2, 'Test URI 2'],161 [+nextTokenId + 2, 'Test URI 2'],
181 ],162 ],
182 ).send();163 ).send();
183 const events = normalizeEvents(result.events);
184164
185 expect(events).to.include.deep.members([165 const events = result.events.Transfer;
186 {
187 address: collectionIdAddress,
188 event: 'Transfer',
189 args: {166 for (let i = 0; i < 2; i++) {
190 from: '0x0000000000000000000000000000000000000000',
191 to: receiver,
192 tokenId: nextTokenId,
193 },
194 },
195 {
196 address: collectionIdAddress,167 const event = events[i];
197 event: 'Transfer',
198 args: {
199 from: '0x0000000000000000000000000000000000000000',168 expect(event.address).to.equal(collectionAddress);
200 to: receiver,
201 tokenId: String(+nextTokenId + 1),
202 },169 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
203 },
204 {
205 address: collectionIdAddress,
206 event: 'Transfer',
207 args: {
208 from: '0x0000000000000000000000000000000000000000',
209 to: receiver,170 expect(event.returnValues.to).to.equal(receiver);
210 tokenId: String(+nextTokenId + 2),171 expect(event.returnValues.tokenId).to.equal(String(+nextTokenId + i));
211 },172 }
212 },
213 ]);
214173
215 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');174 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
216 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');175 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
217 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');176 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
218 }177 }
219 });178 });
220179
221 itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {180 itEth('Can perform burn()', async ({helper}) => {
222 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);181 const caller = await helper.eth.createAccountWithBalance(donor);
223 const helper = evmCollectionHelpers(web3, caller);
224 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();182 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Burny', '6', '6');
225 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);183 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
226 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
227184
228 const tokenId = await contract.methods.nextTokenId().call();185 const tokenId = await contract.methods.nextTokenId().call();
229 await contract.methods.mint(caller, tokenId).send();186 await contract.methods.mint(caller, tokenId).send();
230 {187 {
231 const result = await contract.methods.burn(tokenId).send();188 const result = await contract.methods.burn(tokenId).send();
232 const events = normalizeEvents(result.events);189 const event = result.events.Transfer;
233 expect(events).to.include.deep.members([190 expect(event.address).to.equal(collectionAddress);
234 {191 expect(event.returnValues.from).to.equal(caller);
235 address: collectionIdAddress,
236 event: 'Transfer',
237 args: {
238 from: caller,
239 to: '0x0000000000000000000000000000000000000000',192 expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');
240 tokenId: tokenId.toString(),193 expect(event.returnValues.tokenId).to.equal(tokenId.toString());
241 },
242 },
243 ]);
244 }194 }
245 });195 });
246196
247 itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {197 itEth('Can perform transferFrom()', async ({helper}) => {
248 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);198 const caller = await helper.eth.createAccountWithBalance(donor);
249 const helper = evmCollectionHelpers(web3, caller);199 const receiver = helper.eth.createAccount();
250 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();200 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'TransferFromy', '6', '6');
251 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);201 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
252 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
253202
254 const receiver = createEthAccount(web3);
255
256 const tokenId = await contract.methods.nextTokenId().call();203 const tokenId = await contract.methods.nextTokenId().call();
204 const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
257 await contract.methods.mint(caller, tokenId).send();205 await contract.methods.mint(caller, tokenId).send();
258206
259 const address = tokenIdToAddress(collectionId, tokenId);207 const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
260 const tokenContract = uniqueRefungibleToken(web3, address, caller);
261 await tokenContract.methods.repartition(15).send();208 await tokenContract.methods.repartition(15).send();
262209
263 {210 {
264 const erc20Events = await recordEvents(tokenContract, async () => {211 const tokenEvents: any = [];
265 const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
266 const events = normalizeEvents(result.events);212 tokenContract.events.allEvents((_: any, event: any) => {
267 expect(events).to.include.deep.members([
268 {
269 address: collectionIdAddress,
270 event: 'Transfer',
271 args: {
272 from: caller,213 tokenEvents.push(event);
273 to: receiver,
274 tokenId: tokenId.toString(),
275 },
276 },
277 ]);
278 });214 });
215 const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();
279216
280 expect(erc20Events).to.include.deep.members([217 let event = result.events.Transfer;
218 expect(event.address).to.equal(collectionAddress);
281 {219 expect(event.returnValues.from).to.equal(caller);
282 address,220 expect(event.returnValues.to).to.equal(receiver);
283 event: 'Transfer',221 expect(event.returnValues.tokenId).to.equal(tokenId.toString());
222
284 args: {223 event = tokenEvents[0];
285 from: caller,224 expect(event.address).to.equal(tokenAddress);
225 expect(event.returnValues.from).to.equal(caller);
286 to: receiver,226 expect(event.returnValues.to).to.equal(receiver);
287 value: '15',227 expect(event.returnValues.value).to.equal('15');
288 },
289 },
290 ]);
291 }228 }
292229
293 {230 {
301 }238 }
302 });239 });
303240
304 itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {241 itEth('Can perform transfer()', async ({helper}) => {
305 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);242 const caller = await helper.eth.createAccountWithBalance(donor);
306 const helper = evmCollectionHelpers(web3, caller);243 const receiver = helper.eth.createAccount();
307 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();244 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry', '6', '6');
308 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);245 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
309 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
310246
311 const receiver = createEthAccount(web3);
312
313 const tokenId = await contract.methods.nextTokenId().call();247 const tokenId = await contract.methods.nextTokenId().call();
314 await contract.methods.mint(caller, tokenId).send();248 await contract.methods.mint(caller, tokenId).send();
315249
316 {250 {
317 const result = await contract.methods.transfer(receiver, tokenId).send();251 const result = await contract.methods.transfer(receiver, tokenId).send();
318 const events = normalizeEvents(result.events);252
253 const event = result.events.Transfer;
319 expect(events).to.include.deep.members([254 expect(event.address).to.equal(collectionAddress);
320 {255 expect(event.returnValues.from).to.equal(caller);
321 address: collectionIdAddress,
322 event: 'Transfer',
323 args: {
324 from: caller,
325 to: receiver,256 expect(event.returnValues.to).to.equal(receiver);
326 tokenId: tokenId.toString(),257 expect(event.returnValues.tokenId).to.equal(tokenId.toString());
327 },
328 },
329 ]);
330 }258 }
331259
332 {260 {
340 }268 }
341 });269 });
342270
343 itWeb3('transfer event on transfer from partial ownership to full ownership', async ({api, web3, privateKeyWrapper}) => {271 itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
344 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);272 const caller = await helper.eth.createAccountWithBalance(donor);
345 const receiver = createEthAccount(web3);273 const receiver = helper.eth.createAccount();
346 const helper = evmCollectionHelpers(web3, caller);274 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry-Partial-to-Full', '6', '6');
347 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
348 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);275 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
349 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
350276
351 const tokenId = await contract.methods.nextTokenId().call();277 const tokenId = await contract.methods.nextTokenId().call();
352 await contract.methods.mint(caller, tokenId).send();278 await contract.methods.mint(caller, tokenId).send();
353279
354 const tokenAddress = tokenIdToAddress(collectionId, tokenId);280 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
355 const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
356281
357 await tokenContract.methods.repartition(2).send();282 await tokenContract.methods.repartition(2).send();
358 await tokenContract.methods.transfer(receiver, 1).send();283 await tokenContract.methods.transfer(receiver, 1).send();
359284
360 const events = await recordEvents(contract, async () =>285 const events: any = [];
286 contract.events.allEvents((_: any, event: any) => {
361 await tokenContract.methods.transfer(receiver, 1).send());287 events.push(event);
362 expect(events).to.deep.equal([288 });
289 await tokenContract.methods.transfer(receiver, 1).send();
290
363 {291 const event = events[0];
364 address: collectionIdAddress,
365 event: 'Transfer',292 expect(event.address).to.equal(collectionAddress);
366 args: {293 expect(event.returnValues.from).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
367 from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
368 to: receiver,294 expect(event.returnValues.to).to.equal(receiver);
369 tokenId: tokenId.toString(),295 expect(event.returnValues.tokenId).to.equal(tokenId.toString());
370 },
371 },
372 ]);
373 });296 });
374297
375 itWeb3('transfer event on transfer from full ownership to partial ownership', async ({api, web3, privateKeyWrapper}) => {298 itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => {
376 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);299 const caller = await helper.eth.createAccountWithBalance(donor);
377 const receiver = createEthAccount(web3);300 const receiver = helper.eth.createAccount();
378 const helper = evmCollectionHelpers(web3, caller);301 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Transferry-Full-to-Partial', '6', '6');
379 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
380 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);302 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
381 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
382303
383 const tokenId = await contract.methods.nextTokenId().call();304 const tokenId = await contract.methods.nextTokenId().call();
384 await contract.methods.mint(caller, tokenId).send();305 await contract.methods.mint(caller, tokenId).send();
385306
386 const tokenAddress = tokenIdToAddress(collectionId, tokenId);307 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);
387 const tokenContract = uniqueRefungibleToken(web3, tokenAddress, caller);
388308
389 await tokenContract.methods.repartition(2).send();309 await tokenContract.methods.repartition(2).send();
390310
391 const events = await recordEvents(contract, async () =>311 const events: any = [];
312 contract.events.allEvents((_: any, event: any) => {
392 await tokenContract.methods.transfer(receiver, 1).send());313 events.push(event);
314 });
315 await tokenContract.methods.transfer(receiver, 1).send();
393316
394 expect(events).to.deep.equal([317 const event = events[0];
395 {
396 address: collectionIdAddress,318 expect(event.address).to.equal(collectionAddress);
397 event: 'Transfer',319 expect(event.returnValues.from).to.equal(caller);
398 args: {
399 from: caller,
400 to: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',320 expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
401 tokenId: tokenId.toString(),321 expect(event.returnValues.tokenId).to.equal(tokenId.toString());
402 },
403 },
404 ]);
405 });322 });
406});323});
407324
408describe('RFT: Fees', () => {325describe('RFT: Fees', () => {
326 let donor: IKeyringPair;
327
409 before(async function() {328 before(async function() {
410 await requirePallets(this, [Pallets.ReFungible]);329 await usingEthPlaygrounds(async (helper, privateKey) => {
330 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
331
332 donor = privateKey('//Alice');
333 });
411 });334 });
412335
413 itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {336 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
414 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);337 const caller = await helper.eth.createAccountWithBalance(donor);
415 const helper = evmCollectionHelpers(web3, caller);338 const receiver = helper.eth.createAccount();
416 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();339 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Feeful-Transfer-From', '6', '6');
417 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);340 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
418 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
419341
420 const receiver = createEthAccount(web3);
421
422 const tokenId = await contract.methods.nextTokenId().call();342 const tokenId = await contract.methods.nextTokenId().call();
423 await contract.methods.mint(caller, tokenId).send();343 await contract.methods.mint(caller, tokenId).send();
424344
425 const cost = await recordEthFee(api, caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());345 const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());
426 expect(cost < BigInt(0.2 * Number(UNIQUE)));346 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
427 expect(cost > 0n);347 expect(cost > 0n);
428 });348 });
429349
430 itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {350 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
431 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);351 const caller = await helper.eth.createAccountWithBalance(donor);
432 const helper = evmCollectionHelpers(web3, caller);352 const receiver = helper.eth.createAccount();
433 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();353 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Feeful-Transfer', '6', '6');
434 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);354 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
435 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
436355
437 const receiver = createEthAccount(web3);
438
439 const tokenId = await contract.methods.nextTokenId().call();356 const tokenId = await contract.methods.nextTokenId().call();
440 await contract.methods.mint(caller, tokenId).send();357 await contract.methods.mint(caller, tokenId).send();
441358
442 const cost = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, tokenId).send());359 const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());
443 expect(cost < BigInt(0.2 * Number(UNIQUE)));360 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
444 expect(cost > 0n);361 expect(cost > 0n);
445 });362 });
446});363});
447364
448describe('Common metadata', () => {365describe('Common metadata', () => {
366 let donor: IKeyringPair;
367 let alice: IKeyringPair;
368
449 before(async function() {369 before(async function() {
450 await requirePallets(this, [Pallets.ReFungible]);370 await usingEthPlaygrounds(async (helper, privateKey) => {
451 });371 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
452372
453 itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {373 donor = privateKey('//Alice');
454 const collection = await createCollectionExpectSuccess({374 [alice] = await helper.arrange.createAccounts([20n], donor);
455 name: 'token name',
456 mode: {type: 'ReFungible'},
457 });375 });
458 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);376 });
459377
460 const address = collectionIdToAddress(collection);378 itEth('Returns collection name', async ({helper}) => {
379 const caller = helper.eth.createAccount();
461 const contract = evmCollection(web3, caller, address, {type: 'ReFungible'});380 const collection = await helper.rft.mintCollection(alice, {name: 'Leviathan', tokenPrefix: '11'});
381
382 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);
462 const name = await contract.methods.name().call();383 const name = await contract.methods.name().call();
463
464 expect(name).to.equal('token name');384 expect(name).to.equal('Leviathan');
465 });385 });
466386
467 itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {387 itEth('Returns symbol name', async ({helper}) => {
468 const collection = await createCollectionExpectSuccess({388 const caller = await helper.eth.createAccountWithBalance(donor);
469 tokenPrefix: 'TOK',
470 mode: {type: 'ReFungible'},
471 });
472 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);389 const {collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Leviathan', '', '12');
473
474 const address = collectionIdToAddress(collection);
475 const contract = evmCollection(web3, caller, address, {type: 'ReFungible'});390 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
476 const symbol = await contract.methods.symbol().call();391 const symbol = await contract.methods.symbol().call();
477
478 expect(symbol).to.equal('TOK');392 expect(symbol).to.equal('12');
479 });393 });
480});394});
481395
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';17import {Pallets, requirePalletsOrSkip} from '../util/playgrounds';
18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRFTCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';18import {EthUniqueHelper, expect, itEth, usingEthPlaygrounds} from './util/playgrounds';
19import {IKeyringPair} from '@polkadot/types/types';
20import {Contract} from 'web3-eth-contract';
1921
20import chai from 'chai';
21import chaiAsPromised from 'chai-as-promised';
22chai.use(chaiAsPromised);
23const expect = chai.expect;
24
25describe('Refungible token: Information getting', () => {22describe('Refungible token: Information getting', () => {
23 let donor: IKeyringPair;
24 let alice: IKeyringPair;
25
26 before(async function() {26 before(async function() {
27 await requirePallets(this, [Pallets.ReFungible]);27 await usingEthPlaygrounds(async (helper, privateKey) => {
28 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
29
30 donor = privateKey('//Alice');
31 [alice] = await helper.arrange.createAccounts([20n], donor);
32 });
28 });33 });
2934
30 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {35 itEth('totalSupply', async ({helper}) => {
31 const alice = privateKeyWrapper('//Alice');36 const caller = await helper.eth.createAccountWithBalance(donor);
37 const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
38 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
3239
33 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;40 const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
34
35 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
36
37 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
38
39 const address = tokenIdToAddress(collectionId, tokenId);
40 const contract = uniqueRefungibleToken(web3, address, caller);
41 const totalSupply = await contract.methods.totalSupply().call();41 const totalSupply = await contract.methods.totalSupply().call();
42
43 expect(totalSupply).to.equal('200');42 expect(totalSupply).to.equal('200');
44 });43 });
4544
46 itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {45 itEth('balanceOf', async ({helper}) => {
47 const alice = privateKeyWrapper('//Alice');46 const caller = await helper.eth.createAccountWithBalance(donor);
47 const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
48 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
4849
49 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;50 const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
50
51 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
52
53 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
54
55 const address = tokenIdToAddress(collectionId, tokenId);
56 const contract = uniqueRefungibleToken(web3, address, caller);
57 const balance = await contract.methods.balanceOf(caller).call();51 const balance = await contract.methods.balanceOf(caller).call();
58
59 expect(balance).to.equal('200');52 expect(balance).to.equal('200');
60 });53 });
6154
62 itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {55 itEth('decimals', async ({helper}) => {
63 const alice = privateKeyWrapper('//Alice');56 const caller = await helper.eth.createAccountWithBalance(donor);
57 const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'});
58 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller});
6459
65 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;60 const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller);
66
67 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
68
69 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
70
71 const address = tokenIdToAddress(collectionId, tokenId);
72 const contract = uniqueRefungibleToken(web3, address, caller);
73 const decimals = await contract.methods.decimals().call();61 const decimals = await contract.methods.decimals().call();
74
75 expect(decimals).to.equal('0');62 expect(decimals).to.equal('0');
76 });63 });
77});64});
7865
79// FIXME: Need erc721 for ReFubgible.66// FIXME: Need erc721 for ReFubgible.
80describe('Check ERC721 token URI for ReFungible', () => {67describe('Check ERC721 token URI for ReFungible', () => {
68 let donor: IKeyringPair;
69
81 before(async function() {70 before(async function() {
82 await requirePallets(this, [Pallets.ReFungible]);71 await usingEthPlaygrounds(async (helper, privateKey) => {
72 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
73
74 donor = privateKey('//Alice');
75 });
83 });76 });
8477
85 itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {78 async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {
86 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
87 const helper = evmCollectionHelpers(web3, owner);79 const owner = await helper.eth.createAccountWithBalance(donor);
88 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();
89 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);80 const receiver = helper.eth.createAccount();
90 const receiver = createEthAccount(web3);
91 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
9281
82 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
83 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();
84 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
85 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
86
93 const nextTokenId = await contract.methods.nextTokenId().call();87 const nextTokenId = await contract.methods.nextTokenId().call();
94 expect(nextTokenId).to.be.equal('1');88 expect(nextTokenId).to.be.equal('1');
95 result = await contract.methods.mint(89 result = await contract.methods.mint(
96 receiver,90 receiver,
97 nextTokenId,91 nextTokenId,
98 ).send();92 ).send();
9993
100 const events = normalizeEvents(result.events);94 if (propertyKey && propertyValue) {
101 const address = collectionIdToAddress(collectionId);95 // Set URL or suffix
96 await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();
97 }
10298
103 expect(events).to.be.deep.equal([99 const event = result.events.Transfer;
100 expect(event.address).to.be.equal(collectionAddress);
104 {101 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
105 address,
106 event: 'Transfer',
107 args: {
108 from: '0x0000000000000000000000000000000000000000',
109 to: receiver,102 expect(event.returnValues.to).to.be.equal(receiver);
110 tokenId: nextTokenId,103 expect(event.returnValues.tokenId).to.be.equal(nextTokenId);
111 },
112 },
113 ]);
114104
105 return {contract, nextTokenId};
106 }
107
108 itEth('Empty tokenURI', async ({helper}) => {
109 const {contract, nextTokenId} = await setup(helper, '');
115 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');110 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');
116 });111 });
117112
118 itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {113 itEth('TokenURI from url', async ({helper}) => {
119 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);114 const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');
120 const helper = evmCollectionHelpers(web3, owner);
121 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
122 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
123 const receiver = createEthAccount(web3);
124 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
125
126 const nextTokenId = await contract.methods.nextTokenId().call();
127 expect(nextTokenId).to.be.equal('1');
128 result = await contract.methods.mint(
129 receiver,
130 nextTokenId,
131 ).send();
132
133 // Set URL
134 await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();
135
136 const events = normalizeEvents(result.events);
137 const address = collectionIdToAddress(collectionId);
138
139 expect(events).to.be.deep.equal([
140 {
141 address,
142 event: 'Transfer',
143 args: {
144 from: '0x0000000000000000000000000000000000000000',
145 to: receiver,
146 tokenId: nextTokenId,
147 },
148 },
149 ]);
150
151 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');115 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');
152 });116 });
153117
154 itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {118 itEth('TokenURI from baseURI + tokenId', async ({helper}) => {
155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);119 const {contract, nextTokenId} = await setup(helper, 'BaseURI_');
156 const helper = evmCollectionHelpers(web3, owner);
157 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
158 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
159 const receiver = createEthAccount(web3);
160 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
161
162 const nextTokenId = await contract.methods.nextTokenId().call();
163 expect(nextTokenId).to.be.equal('1');
164 result = await contract.methods.mint(
165 receiver,
166 nextTokenId,
167 ).send();
168
169 const events = normalizeEvents(result.events);
170 const address = collectionIdToAddress(collectionId);
171
172 expect(events).to.be.deep.equal([
173 {
174 address,
175 event: 'Transfer',
176 args: {
177 from: '0x0000000000000000000000000000000000000000',
178 to: receiver,
179 tokenId: nextTokenId,
180 },
181 },
182 ]);
183
184 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);120 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);
185 });121 });
186122
187 itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {123 itEth('TokenURI from baseURI + suffix', async ({helper}) => {
188 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
189 const helper = evmCollectionHelpers(web3, owner);
190 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();
191 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
192 const receiver = createEthAccount(web3);
193 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});
194
195 const nextTokenId = await contract.methods.nextTokenId().call();
196 expect(nextTokenId).to.be.equal('1');
197 result = await contract.methods.mint(
198 receiver,
199 nextTokenId,
200 ).send();
201
202 // Set suffix
203 const suffix = '/some/suffix';124 const suffix = '/some/suffix';
204 await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();125 const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);
205
206 const events = normalizeEvents(result.events);
207 const address = collectionIdToAddress(collectionId);
208
209 expect(events).to.be.deep.equal([
210 {
211 address,
212 event: 'Transfer',
213 args: {
214 from: '0x0000000000000000000000000000000000000000',
215 to: receiver,
216 tokenId: nextTokenId,
217 },
218 },
219 ]);
220
221 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);126 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);
222 });127 });
223});128});
224129
225describe('Refungible: Plain calls', () => {130describe('Refungible: Plain calls', () => {
131 let donor: IKeyringPair;
132 let alice: IKeyringPair;
133
226 before(async function() {134 before(async function() {
227 await requirePallets(this, [Pallets.ReFungible]);135 await usingEthPlaygrounds(async (helper, privateKey) => {
136 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
137
138 donor = privateKey('//Alice');
139 [alice] = await helper.arrange.createAccounts([50n], donor);
140 });
228 });141 });
229142
230 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {143 itEth('Can perform approve()', async ({helper}) => {
231 const alice = privateKeyWrapper('//Alice');144 const owner = await helper.eth.createAccountWithBalance(donor);
145 const spender = helper.eth.createAccount();
146 const collection = await helper.rft.mintCollection(alice);
147 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
232148
233 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;149 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
150 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
234151
235 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
236
237 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
238
239 const address = tokenIdToAddress(collectionId, tokenId);
240
241 const spender = createEthAccount(web3);
242
243 const contract = uniqueRefungibleToken(web3, address, owner);
244
245 {152 {
246 const result = await contract.methods.approve(spender, 100).send({from: owner});153 const result = await contract.methods.approve(spender, 100).send({from: owner});
247 const events = normalizeEvents(result.events);154 const event = result.events.Approval;
248
249 expect(events).to.be.deep.equal([155 expect(event.address).to.be.equal(tokenAddress);
250 {156 expect(event.returnValues.owner).to.be.equal(owner);
251 address,
252 event: 'Approval',
253 args: {
254 owner,
255 spender,157 expect(event.returnValues.spender).to.be.equal(spender);
256 value: '100',158 expect(event.returnValues.value).to.be.equal('100');
257 },
258 },
259 ]);
260 }159 }
261160
262 {161 {
265 }164 }
266 });165 });
267166
268 itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {167 itEth('Can perform transferFrom()', async ({helper}) => {
269 const alice = privateKeyWrapper('//Alice');168 const owner = await helper.eth.createAccountWithBalance(donor);
169 const spender = await helper.eth.createAccountWithBalance(donor);
170 const receiver = helper.eth.createAccount();
171 const collection = await helper.rft.mintCollection(alice);
172 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
270173
271 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;174 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
175 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
272176
273 const owner = createEthAccount(web3);
274 await transferBalanceToEth(api, alice, owner);
275
276 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
277
278 const spender = createEthAccount(web3);
279 await transferBalanceToEth(api, alice, spender);
280
281 const receiver = createEthAccount(web3);
282
283 const address = tokenIdToAddress(collectionId, tokenId);
284 const contract = uniqueRefungibleToken(web3, address, owner);
285
286 await contract.methods.approve(spender, 100).send();177 await contract.methods.approve(spender, 100).send();
287178
288 {179 {
289 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});180 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
290 const events = normalizeEvents(result.events);181 let event = result.events.Transfer;
291 expect(events).to.include.deep.members([182 expect(event.address).to.be.equal(tokenAddress);
292 {183 expect(event.returnValues.from).to.be.equal(owner);
293 address,
294 event: 'Transfer',
295 args: {
296 from: owner,
297 to: receiver,184 expect(event.returnValues.to).to.be.equal(receiver);
298 value: '49',185 expect(event.returnValues.value).to.be.equal('49');
299 },186
300 },187 event = result.events.Approval;
301 {188 expect(event.address).to.be.equal(tokenAddress);
302 address,
303 event: 'Approval',189 expect(event.returnValues.owner).to.be.equal(owner);
304 args: {
305 owner,
306 spender,190 expect(event.returnValues.spender).to.be.equal(spender);
307 value: '51',191 expect(event.returnValues.value).to.be.equal('51');
308 },
309 },
310 ]);
311 }192 }
312193
313 {194 {
321 }202 }
322 });203 });
323204
324 itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {205 itEth('Can perform transfer()', async ({helper}) => {
325 const alice = privateKeyWrapper('//Alice');206 const owner = await helper.eth.createAccountWithBalance(donor);
207 const receiver = helper.eth.createAccount();
208 const collection = await helper.rft.mintCollection(alice);
209 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
326210
327 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;211 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
212 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
328213
329 const owner = createEthAccount(web3);
330 await transferBalanceToEth(api, alice, owner);
331
332 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
333
334 const receiver = createEthAccount(web3);
335 await transferBalanceToEth(api, alice, receiver);
336
337 const address = tokenIdToAddress(collectionId, tokenId);
338 const contract = uniqueRefungibleToken(web3, address, owner);
339
340 {214 {
341 const result = await contract.methods.transfer(receiver, 50).send({from: owner});215 const result = await contract.methods.transfer(receiver, 50).send({from: owner});
342 const events = normalizeEvents(result.events);216 const event = result.events.Transfer;
343 expect(events).to.include.deep.members([217 expect(event.address).to.be.equal(tokenAddress);
344 {218 expect(event.returnValues.from).to.be.equal(owner);
345 address,
346 event: 'Transfer',
347 args: {
348 from: owner,
349 to: receiver,219 expect(event.returnValues.to).to.be.equal(receiver);
350 value: '50',220 expect(event.returnValues.value).to.be.equal('50');
351 },
352 },
353 ]);
354 }221 }
355222
356 {223 {
364 }231 }
365 });232 });
366233
367 itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {234 itEth('Can perform repartition()', async ({helper}) => {
368 const alice = privateKeyWrapper('//Alice');235 const owner = await helper.eth.createAccountWithBalance(donor);
236 const receiver = await helper.eth.createAccountWithBalance(donor);
237 const collection = await helper.rft.mintCollection(alice);
238 const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
369239
370 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;240 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
241 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
371242
372 const owner = createEthAccount(web3);
373 await transferBalanceToEth(api, alice, owner);
374
375 const receiver = createEthAccount(web3);
376 await transferBalanceToEth(api, alice, receiver);
377
378 const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
379
380 const address = tokenIdToAddress(collectionId, tokenId);
381 const contract = uniqueRefungibleToken(web3, address, owner);
382
383 await contract.methods.repartition(200).send({from: owner});243 await contract.methods.repartition(200).send({from: owner});
384 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);244 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);
385 await contract.methods.transfer(receiver, 110).send({from: owner});245 await contract.methods.transfer(receiver, 110).send({from: owner});
386 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);246 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);
387 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);247 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);
388248
389 await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;249 await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected; // Transaction is reverted
390250
391 await contract.methods.transfer(receiver, 90).send({from: owner});251 await contract.methods.transfer(receiver, 90).send({from: owner});
392 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);252 expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);
393 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);253 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);
394254
395 await contract.methods.repartition(150).send({from: receiver});255 await contract.methods.repartition(150).send({from: receiver});
396 await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;256 await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected; // Transaction is reverted
397 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);257 expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);
398 });258 });
399259
400 itWeb3('Can repartition with increased amount', async ({web3, api, privateKeyWrapper}) => {260 itEth('Can repartition with increased amount', async ({helper}) => {
401 const alice = privateKeyWrapper('//Alice');261 const owner = await helper.eth.createAccountWithBalance(donor);
262 const collection = await helper.rft.mintCollection(alice);
263 const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
402264
403 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;265 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
266 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
404267
405 const owner = createEthAccount(web3);
406 await transferBalanceToEth(api, alice, owner);
407
408 const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
409
410 const address = tokenIdToAddress(collectionId, tokenId);
411 const contract = uniqueRefungibleToken(web3, address, owner);
412
413 const result = await contract.methods.repartition(200).send();268 const result = await contract.methods.repartition(200).send();
414 const events = normalizeEvents(result.events);
415269
416 expect(events).to.deep.equal([270 const event = result.events.Transfer;
271 expect(event.address).to.be.equal(tokenAddress);
417 {272 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
418 address,
419 event: 'Transfer',
420 args: {
421 from: '0x0000000000000000000000000000000000000000',
422 to: owner,273 expect(event.returnValues.to).to.be.equal(owner);
423 value: '100',274 expect(event.returnValues.value).to.be.equal('100');
424 },
425 },
426 ]);
427 });275 });
428276
429 itWeb3('Can repartition with decreased amount', async ({web3, api, privateKeyWrapper}) => {277 itEth('Can repartition with decreased amount', async ({helper}) => {
430 const alice = privateKeyWrapper('//Alice');278 const owner = await helper.eth.createAccountWithBalance(donor);
279 const collection = await helper.rft.mintCollection(alice);
280 const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
431281
432 const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;282 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
283 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
433284
434 const owner = createEthAccount(web3);
435 await transferBalanceToEth(api, alice, owner);
436
437 const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
438
439 const address = tokenIdToAddress(collectionId, tokenId);
440 const contract = uniqueRefungibleToken(web3, address, owner);
441
442 const result = await contract.methods.repartition(50).send();285 const result = await contract.methods.repartition(50).send();
443 const events = normalizeEvents(result.events);286 const event = result.events.Transfer;
444 expect(events).to.deep.equal([287 expect(event.address).to.be.equal(tokenAddress);
445 {288 expect(event.returnValues.from).to.be.equal(owner);
446 address,
447 event: 'Transfer',
448 args: {
449 from: owner,
450 to: '0x0000000000000000000000000000000000000000',289 expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');
451 value: '50',290 expect(event.returnValues.value).to.be.equal('50');
452 },
453 },
454 ]);
455 });291 });
456292
457 itWeb3('Receiving Transfer event on burning into full ownership', async ({web3, api, privateKeyWrapper}) => {293 itEth('Receiving Transfer event on burning into full ownership', async ({helper}) => {
458 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);294 const caller = await helper.eth.createAccountWithBalance(donor);
459 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);295 const receiver = await helper.eth.createAccountWithBalance(donor);
460 const helper = evmCollectionHelpers(web3, caller);296 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(caller, 'Devastation', '6', '6');
461 const result = await helper.methods.createRFTCollection('Mint collection', '6', '6').send();
462 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);297 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
463 const contract = evmCollection(web3, caller, collectionIdAddress, {type: 'ReFungible'});
464298
465 const tokenId = await contract.methods.nextTokenId().call();299 const tokenId = await contract.methods.nextTokenId().call();
466 await contract.methods.mint(caller, tokenId).send();300 await contract.methods.mint(caller, tokenId).send();
301 const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
302 const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);
467303
468 const address = tokenIdToAddress(collectionId, tokenId);
469
470 const tokenContract = uniqueRefungibleToken(web3, address, caller);
471 await tokenContract.methods.repartition(2).send();304 await tokenContract.methods.repartition(2).send();
472 await tokenContract.methods.transfer(receiver, 1).send();305 await tokenContract.methods.transfer(receiver, 1).send();
473306
474 const events = await recordEvents(contract, async () =>307 const events: any = [];
308 contract.events.allEvents((_: any, event: any) => {
475 await tokenContract.methods.burnFrom(caller, 1).send());309 events.push(event);
476 expect(events).to.deep.equal([310 });
311 await tokenContract.methods.burnFrom(caller, 1).send();
312
477 {313 const event = events[0];
478 address: collectionIdAddress,
479 event: 'Transfer',314 expect(event.address).to.be.equal(collectionAddress);
480 args: {315 expect(event.returnValues.from).to.be.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');
481 from: '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF',
482 to: receiver,316 expect(event.returnValues.to).to.be.equal(receiver);
483 tokenId,317 expect(event.returnValues.tokenId).to.be.equal(tokenId);
484 },
485 },
486 ]);
487 });318 });
488});319});
489320
490describe('Refungible: Fees', () => {321describe('Refungible: Fees', () => {
322 let donor: IKeyringPair;
323 let alice: IKeyringPair;
324
491 before(async function() {325 before(async function() {
492 await requirePallets(this, [Pallets.ReFungible]);326 await usingEthPlaygrounds(async (helper, privateKey) => {
327 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
328
329 donor = privateKey('//Alice');
330 [alice] = await helper.arrange.createAccounts([50n], donor);
331 });
493 });332 });
494333
495 itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {334 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {
496 const alice = privateKeyWrapper('//Alice');335 const owner = await helper.eth.createAccountWithBalance(donor);
336 const spender = helper.eth.createAccount();
337 const collection = await helper.rft.mintCollection(alice);
338 const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner});
497339
498 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;340 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
341 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
499342
500 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);343 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner}));
501 const spender = createEthAccount(web3);
502
503 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
504
505 const address = tokenIdToAddress(collectionId, tokenId);
506 const contract = uniqueRefungibleToken(web3, address, owner);
507
508 const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));
509 expect(cost < BigInt(0.2 * Number(UNIQUE)));344 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
510 });345 });
511346
512 itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {347 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {
513 const alice = privateKeyWrapper('//Alice');348 const owner = await helper.eth.createAccountWithBalance(donor);
349 const spender = await helper.eth.createAccountWithBalance(donor);
350 const collection = await helper.rft.mintCollection(alice);
351 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
514352
515 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;353 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
354 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
516355
517 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
518 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
519
520 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
521
522 const address = tokenIdToAddress(collectionId, tokenId);
523 const contract = uniqueRefungibleToken(web3, address, owner);
524
525 await contract.methods.approve(spender, 100).send({from: owner});356 await contract.methods.approve(spender, 100).send({from: owner});
526357
527 const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));358 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
528 expect(cost < BigInt(0.2 * Number(UNIQUE)));359 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
529 });360 });
530361
531 itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {362 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {
532 const alice = privateKeyWrapper('//Alice');363 const owner = await helper.eth.createAccountWithBalance(donor);
364 const receiver = helper.eth.createAccount();
365 const collection = await helper.rft.mintCollection(alice);
366 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
533367
534 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;368 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
369 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
535370
536 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);371 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
537 const receiver = createEthAccount(web3);
538
539 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
540
541 const address = tokenIdToAddress(collectionId, tokenId);
542 const contract = uniqueRefungibleToken(web3, address, owner);
543
544 const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
545 expect(cost < BigInt(0.2 * Number(UNIQUE)));372 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
546 });373 });
547});374});
548375
549describe('Refungible: Substrate calls', () => {376describe('Refungible: Substrate calls', () => {
377 let donor: IKeyringPair;
378 let alice: IKeyringPair;
379
550 before(async function() {380 before(async function() {
551 await requirePallets(this, [Pallets.ReFungible]);381 await usingEthPlaygrounds(async (helper, privateKey) => {
382 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
383
384 donor = privateKey('//Alice');
385 [alice] = await helper.arrange.createAccounts([50n], donor);
386 });
552 });387 });
553388
554 itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {389 itEth('Events emitted for approve()', async ({helper}) => {
555 const alice = privateKeyWrapper('//Alice');390 const receiver = helper.eth.createAccount();
391 const collection = await helper.rft.mintCollection(alice);
392 const token = await collection.mintToken(alice, 200n);
556393
557 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;394 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
395 const contract = helper.ethNativeContract.rftToken(tokenAddress);
558396
559 const receiver = createEthAccount(web3);397 const events: any = [];
560
561 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
562
563 const address = tokenIdToAddress(collectionId, tokenId);398 contract.events.allEvents((_: any, event: any) => {
564 const contract = uniqueRefungibleToken(web3, address);
565
566 const events = await recordEvents(contract, async () => {
567 expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;399 events.push(event);
568 });400 });
401 expect(await token.approve(alice, {Ethereum: receiver}, 100n)).to.be.true;
569402
570 expect(events).to.be.deep.equal([403 const event = events[0];
571 {
572 address,
573 event: 'Approval',404 expect(event.event).to.be.equal('Approval');
574 args: {405 expect(event.address).to.be.equal(tokenAddress);
575 owner: subToEth(alice.address),406 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
576 spender: receiver,407 expect(event.returnValues.spender).to.be.equal(receiver);
577 value: '100',408 expect(event.returnValues.value).to.be.equal('100');
578 },
579 },
580 ]);
581 });409 });
582410
583 itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {411 itEth('Events emitted for transferFrom()', async ({helper}) => {
584 const alice = privateKeyWrapper('//Alice');412 const [bob] = await helper.arrange.createAccounts([10n], donor);
413 const receiver = helper.eth.createAccount();
414 const collection = await helper.rft.mintCollection(alice);
415 const token = await collection.mintToken(alice, 200n);
416 await token.approve(alice, {Substrate: bob.address}, 100n);
585417
586 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;418 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
587 const bob = privateKeyWrapper('//Bob');419 const contract = helper.ethNativeContract.rftToken(tokenAddress);
588420
589 const receiver = createEthAccount(web3);421 const events: any = [];
422 contract.events.allEvents((_: any, event: any) => {
423 events.push(event);
424 });
590425
591 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;426 expect(await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}, 51n)).to.be.true;
592 expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;
593427
594 const address = tokenIdToAddress(collectionId, tokenId);428 let event = events[0];
429 expect(event.event).to.be.equal('Transfer');
430 expect(event.address).to.be.equal(tokenAddress);
595 const contract = uniqueRefungibleToken(web3, address);431 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
432 expect(event.returnValues.to).to.be.equal(receiver);
433 expect(event.returnValues.value).to.be.equal('51');
596434
597 const events = await recordEvents(contract, async () => {435 event = events[1];
598 expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver}, 51n)).to.be.true;436 expect(event.event).to.be.equal('Approval');
599 });
600
601 expect(events).to.be.deep.equal([437 expect(event.address).to.be.equal(tokenAddress);
602 {438 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));
603 address,
604 event: 'Transfer',
605 args: {
606 from: subToEth(alice.address),
607 to: receiver,
608 value: '51',
609 },
610 },
611 {
612 address,
613 event: 'Approval',
614 args: {
615 owner: subToEth(alice.address),
616 spender: subToEth(bob.address),439 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(bob.address));
617 value: '49',440 expect(event.returnValues.value).to.be.equal('49');
618 },
619 },
620 ]);
621 });441 });
622442
623 itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {443 itEth('Events emitted for transfer()', async ({helper}) => {
624 const alice = privateKeyWrapper('//Alice');444 const receiver = helper.eth.createAccount();
445 const collection = await helper.rft.mintCollection(alice);
446 const token = await collection.mintToken(alice, 200n);
625447
626 const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;448 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);
449 const contract = helper.ethNativeContract.rftToken(tokenAddress);
627450
628 const receiver = createEthAccount(web3);451 const events: any = [];
629
630 const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
631
632 const address = tokenIdToAddress(collectionId, tokenId);452 contract.events.allEvents((_: any, event: any) => {
633 const contract = uniqueRefungibleToken(web3, address);
634
635 const events = await recordEvents(contract, async () => {
636 expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver}, 51n)).to.be.true;453 events.push(event);
637 });454 });
638455
639 expect(events).to.be.deep.equal([456 expect(await token.transfer(alice, {Ethereum: receiver}, 51n)).to.be.true;
640 {457
641 address,458 const event = events[0];
642 event: 'Transfer',459 expect(event.event).to.be.equal('Transfer');
643 args: {460 expect(event.address).to.be.equal(tokenAddress);
644 from: subToEth(alice.address),461 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));
645 to: receiver,462 expect(event.returnValues.to).to.be.equal(receiver);
646 value: '51',463 expect(event.returnValues.value).to.be.equal('51');
647 },
648 },
649 ]);
650 });464 });
651});465});
652466
653describe('ERC 1633 implementation', () => {467describe('ERC 1633 implementation', () => {
468 let donor: IKeyringPair;
469
654 before(async function() {470 before(async function() {
655 await requirePallets(this, [Pallets.ReFungible]);471 await usingEthPlaygrounds(async (helper, privateKey) => {
656 });472 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
657473
658 itWeb3('Default parent token address and id', async ({api, web3, privateKeyWrapper}) => {474 donor = privateKey('//Alice');
475 });
659 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);476 });
660477
661 const {collectionIdAddress, collectionId} = await createRFTCollection(api, web3, owner);478 itEth('Default parent token address and id', async ({helper}) => {
662 const refungibleContract = uniqueRefungible(web3, collectionIdAddress, owner);
663 const refungibleTokenId = await refungibleContract.methods.nextTokenId().call();479 const owner = await helper.eth.createAccountWithBalance(donor);
664 await refungibleContract.methods.mint(owner, refungibleTokenId).send();
665480
666 const rftTokenAddress = tokenIdToAddress(collectionId, refungibleTokenId);481 const {collectionId, collectionAddress} = await helper.eth.createRefungibleCollection(owner, 'Sands', '', 'GRAIN');
667 const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);482 const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
483
484 const tokenId = await collectionContract.methods.nextTokenId().call();
485 await collectionContract.methods.mint(owner, tokenId).send();
486 const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);
487 const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);
668488
669 const tokenAddress = await refungibleTokenContract.methods.parentToken().call();489 expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress);
670 const tokenId = await refungibleTokenContract.methods.parentTokenId().call();490 expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId);
671 expect(tokenAddress).to.be.equal(collectionIdAddress);
672 expect(tokenId).to.be.equal(refungibleTokenId);
673 });491 });
674});492});
675493
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
116 return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});116 return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
117 }117 }
118
119 collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract {
120 return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller);
121 }
118122
119 rftTokenByAddress(address: string, caller?: string): Contract {123 rftToken(address: string, caller?: string): Contract {
120 const web3 = this.helper.getWeb3();124 const web3 = this.helper.getWeb3();
121 return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});125 return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
122 }126 }
123127
124 rftToken(collectionId: number, tokenId: number, caller?: string): Contract {128 rftTokenById(collectionId: number, tokenId: number, caller?: string): Contract {
125 return this.rftTokenByAddress(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller);129 return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller);
126 }130 }
127}131}
128132
171 return {collectionId, collectionAddress};175 return {collectionId, collectionAddress};
172 }176 }
177
178 async createRefungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {
179 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
180
181 const result = await collectionHelper.methods.createRFTCollection(name, description, tokenPrefix).send();
182
183 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
184 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
185
186 return {collectionId, collectionAddress};
187 }
173188
174 async deployCollectorContract(signer: string): Promise<Contract> {189 async deployCollectorContract(signer: string): Promise<Contract> {
175 return await this.helper.ethContract.deployByCode(signer, 'Collector', `190 return await this.helper.ethContract.deployByCode(signer, 'Collector', `
216 `);231 `);
217 }232 }
233
234 async recordCallFee(user: string, call: () => Promise<any>): Promise<bigint> {
235 const before = await this.helper.balance.getEthereum(user);
236 await call();
237 // In dev mode, the transaction might not finish processing in time
238 await this.helper.wait.newBlocks(1);
239 const after = await this.helper.balance.getEthereum(user);
240
241 return before - after;
242 }
218} 243}
219 244
220class EthAddressGroup extends EthGroupBase {245class EthAddressGroup extends EthGroupBase {