ERC1155.behavior.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. const { contract } = require('@openzeppelin/test-environment');
  2. const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  3. const { ZERO_ADDRESS } = constants;
  4. const { expect } = require('chai');
  5. const { shouldSupportInterfaces } = require('../../introspection/SupportsInterface.behavior');
  6. const ERC1155ReceiverMock = contract.fromArtifact('ERC1155ReceiverMock');
  7. function shouldBehaveLikeERC1155 ([minter, firstTokenHolder, secondTokenHolder, multiTokenHolder, recipient, proxy]) {
  8. const firstTokenId = new BN(1);
  9. const secondTokenId = new BN(2);
  10. const unknownTokenId = new BN(3);
  11. const firstAmount = new BN(1000);
  12. const secondAmount = new BN(2000);
  13. const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61';
  14. const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81';
  15. describe('like an ERC1155', function () {
  16. describe('balanceOf', function () {
  17. it('reverts when queried about the zero address', async function () {
  18. await expectRevert(
  19. this.token.balanceOf(ZERO_ADDRESS, firstTokenId),
  20. 'ERC1155: balance query for the zero address'
  21. );
  22. });
  23. context('when accounts don\'t own tokens', function () {
  24. it('returns zero for given addresses', async function () {
  25. expect(await this.token.balanceOf(
  26. firstTokenHolder,
  27. firstTokenId
  28. )).to.be.bignumber.equal('0');
  29. expect(await this.token.balanceOf(
  30. secondTokenHolder,
  31. secondTokenId
  32. )).to.be.bignumber.equal('0');
  33. expect(await this.token.balanceOf(
  34. firstTokenHolder,
  35. unknownTokenId
  36. )).to.be.bignumber.equal('0');
  37. });
  38. });
  39. context('when accounts own some tokens', function () {
  40. beforeEach(async function () {
  41. await this.token.mint(firstTokenHolder, firstTokenId, firstAmount, '0x', {
  42. from: minter,
  43. });
  44. await this.token.mint(
  45. secondTokenHolder,
  46. secondTokenId,
  47. secondAmount,
  48. '0x',
  49. {
  50. from: minter,
  51. }
  52. );
  53. });
  54. it('returns the amount of tokens owned by the given addresses', async function () {
  55. expect(await this.token.balanceOf(
  56. firstTokenHolder,
  57. firstTokenId
  58. )).to.be.bignumber.equal(firstAmount);
  59. expect(await this.token.balanceOf(
  60. secondTokenHolder,
  61. secondTokenId
  62. )).to.be.bignumber.equal(secondAmount);
  63. expect(await this.token.balanceOf(
  64. firstTokenHolder,
  65. unknownTokenId
  66. )).to.be.bignumber.equal('0');
  67. });
  68. });
  69. });
  70. describe('balanceOfBatch', function () {
  71. it('reverts when input arrays don\'t match up', async function () {
  72. await expectRevert(
  73. this.token.balanceOfBatch(
  74. [firstTokenHolder, secondTokenHolder, firstTokenHolder, secondTokenHolder],
  75. [firstTokenId, secondTokenId, unknownTokenId]
  76. ),
  77. 'ERC1155: accounts and ids length mismatch'
  78. );
  79. await expectRevert(
  80. this.token.balanceOfBatch(
  81. [firstTokenHolder, secondTokenHolder],
  82. [firstTokenId, secondTokenId, unknownTokenId]
  83. ),
  84. 'ERC1155: accounts and ids length mismatch'
  85. );
  86. });
  87. it('reverts when one of the addresses is the zero address', async function () {
  88. await expectRevert(
  89. this.token.balanceOfBatch(
  90. [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS],
  91. [firstTokenId, secondTokenId, unknownTokenId]
  92. ),
  93. 'ERC1155: batch balance query for the zero address'
  94. );
  95. });
  96. context('when accounts don\'t own tokens', function () {
  97. it('returns zeros for each account', async function () {
  98. const result = await this.token.balanceOfBatch(
  99. [firstTokenHolder, secondTokenHolder, firstTokenHolder],
  100. [firstTokenId, secondTokenId, unknownTokenId]
  101. );
  102. expect(result).to.be.an('array');
  103. expect(result[0]).to.be.a.bignumber.equal('0');
  104. expect(result[1]).to.be.a.bignumber.equal('0');
  105. expect(result[2]).to.be.a.bignumber.equal('0');
  106. });
  107. });
  108. context('when accounts own some tokens', function () {
  109. beforeEach(async function () {
  110. await this.token.mint(firstTokenHolder, firstTokenId, firstAmount, '0x', {
  111. from: minter,
  112. });
  113. await this.token.mint(
  114. secondTokenHolder,
  115. secondTokenId,
  116. secondAmount,
  117. '0x',
  118. {
  119. from: minter,
  120. }
  121. );
  122. });
  123. it('returns amounts owned by each account in order passed', async function () {
  124. const result = await this.token.balanceOfBatch(
  125. [secondTokenHolder, firstTokenHolder, firstTokenHolder],
  126. [secondTokenId, firstTokenId, unknownTokenId]
  127. );
  128. expect(result).to.be.an('array');
  129. expect(result[0]).to.be.a.bignumber.equal(secondAmount);
  130. expect(result[1]).to.be.a.bignumber.equal(firstAmount);
  131. expect(result[2]).to.be.a.bignumber.equal('0');
  132. });
  133. it('returns multiple times the balance of the same address when asked', async function () {
  134. const result = await this.token.balanceOfBatch(
  135. [firstTokenHolder, secondTokenHolder, firstTokenHolder],
  136. [firstTokenId, secondTokenId, firstTokenId]
  137. );
  138. expect(result).to.be.an('array');
  139. expect(result[0]).to.be.a.bignumber.equal(result[2]);
  140. expect(result[0]).to.be.a.bignumber.equal(firstAmount);
  141. expect(result[1]).to.be.a.bignumber.equal(secondAmount);
  142. expect(result[2]).to.be.a.bignumber.equal(firstAmount);
  143. });
  144. });
  145. });
  146. describe('setApprovalForAll', function () {
  147. let logs;
  148. beforeEach(async function () {
  149. ({ logs } = await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }));
  150. });
  151. it('sets approval status which can be queried via isApprovedForAll', async function () {
  152. expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(true);
  153. });
  154. it('emits an ApprovalForAll log', function () {
  155. expectEvent.inLogs(logs, 'ApprovalForAll', { account: multiTokenHolder, operator: proxy, approved: true });
  156. });
  157. it('can unset approval for an operator', async function () {
  158. await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder });
  159. expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false);
  160. });
  161. it('reverts if attempting to approve self as an operator', async function () {
  162. await expectRevert(
  163. this.token.setApprovalForAll(multiTokenHolder, true, { from: multiTokenHolder }),
  164. 'ERC1155: setting approval status for self'
  165. );
  166. });
  167. });
  168. describe('safeTransferFrom', function () {
  169. beforeEach(async function () {
  170. await this.token.mint(multiTokenHolder, firstTokenId, firstAmount, '0x', {
  171. from: minter,
  172. });
  173. await this.token.mint(
  174. multiTokenHolder,
  175. secondTokenId,
  176. secondAmount,
  177. '0x',
  178. {
  179. from: minter,
  180. }
  181. );
  182. });
  183. it('reverts when transferring more than balance', async function () {
  184. await expectRevert(
  185. this.token.safeTransferFrom(
  186. multiTokenHolder,
  187. recipient,
  188. firstTokenId,
  189. firstAmount.addn(1),
  190. '0x',
  191. { from: multiTokenHolder },
  192. ),
  193. 'ERC1155: insufficient balance for transfer'
  194. );
  195. });
  196. it('reverts when transferring to zero address', async function () {
  197. await expectRevert(
  198. this.token.safeTransferFrom(
  199. multiTokenHolder,
  200. ZERO_ADDRESS,
  201. firstTokenId,
  202. firstAmount,
  203. '0x',
  204. { from: multiTokenHolder },
  205. ),
  206. 'ERC1155: transfer to the zero address'
  207. );
  208. });
  209. function transferWasSuccessful ({ operator, from, id, value }) {
  210. it('debits transferred balance from sender', async function () {
  211. const newBalance = await this.token.balanceOf(from, id);
  212. expect(newBalance).to.be.a.bignumber.equal('0');
  213. });
  214. it('credits transferred balance to receiver', async function () {
  215. const newBalance = await this.token.balanceOf(this.toWhom, id);
  216. expect(newBalance).to.be.a.bignumber.equal(value);
  217. });
  218. it('emits a TransferSingle log', function () {
  219. expectEvent.inLogs(this.transferLogs, 'TransferSingle', {
  220. operator,
  221. from,
  222. to: this.toWhom,
  223. id,
  224. value,
  225. });
  226. });
  227. }
  228. context('when called by the multiTokenHolder', async function () {
  229. beforeEach(async function () {
  230. this.toWhom = recipient;
  231. ({ logs: this.transferLogs } =
  232. await this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount, '0x', {
  233. from: multiTokenHolder,
  234. }));
  235. });
  236. transferWasSuccessful.call(this, {
  237. operator: multiTokenHolder,
  238. from: multiTokenHolder,
  239. id: firstTokenId,
  240. value: firstAmount,
  241. });
  242. it('preserves existing balances which are not transferred by multiTokenHolder', async function () {
  243. const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId);
  244. expect(balance1).to.be.a.bignumber.equal(secondAmount);
  245. const balance2 = await this.token.balanceOf(recipient, secondTokenId);
  246. expect(balance2).to.be.a.bignumber.equal('0');
  247. });
  248. });
  249. context('when called by an operator on behalf of the multiTokenHolder', function () {
  250. context('when operator is not approved by multiTokenHolder', function () {
  251. beforeEach(async function () {
  252. await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder });
  253. });
  254. it('reverts', async function () {
  255. await expectRevert(
  256. this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount, '0x', {
  257. from: proxy,
  258. }),
  259. 'ERC1155: caller is not owner nor approved'
  260. );
  261. });
  262. });
  263. context('when operator is approved by multiTokenHolder', function () {
  264. beforeEach(async function () {
  265. this.toWhom = recipient;
  266. await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder });
  267. ({ logs: this.transferLogs } =
  268. await this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount, '0x', {
  269. from: proxy,
  270. }));
  271. });
  272. transferWasSuccessful.call(this, {
  273. operator: proxy,
  274. from: multiTokenHolder,
  275. id: firstTokenId,
  276. value: firstAmount,
  277. });
  278. it('preserves operator\'s balances not involved in the transfer', async function () {
  279. const balance1 = await this.token.balanceOf(proxy, firstTokenId);
  280. expect(balance1).to.be.a.bignumber.equal('0');
  281. const balance2 = await this.token.balanceOf(proxy, secondTokenId);
  282. expect(balance2).to.be.a.bignumber.equal('0');
  283. });
  284. });
  285. });
  286. context('when sending to a valid receiver', function () {
  287. beforeEach(async function () {
  288. this.receiver = await ERC1155ReceiverMock.new(
  289. RECEIVER_SINGLE_MAGIC_VALUE, false,
  290. RECEIVER_BATCH_MAGIC_VALUE, false,
  291. );
  292. });
  293. context('without data', function () {
  294. beforeEach(async function () {
  295. this.toWhom = this.receiver.address;
  296. this.transferReceipt = await this.token.safeTransferFrom(
  297. multiTokenHolder,
  298. this.receiver.address,
  299. firstTokenId,
  300. firstAmount,
  301. '0x',
  302. { from: multiTokenHolder }
  303. );
  304. ({ logs: this.transferLogs } = this.transferReceipt);
  305. });
  306. transferWasSuccessful.call(this, {
  307. operator: multiTokenHolder,
  308. from: multiTokenHolder,
  309. id: firstTokenId,
  310. value: firstAmount,
  311. });
  312. it('calls onERC1155Received', async function () {
  313. await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', {
  314. operator: multiTokenHolder,
  315. from: multiTokenHolder,
  316. id: firstTokenId,
  317. value: firstAmount,
  318. data: null,
  319. });
  320. });
  321. });
  322. context('with data', function () {
  323. const data = '0xf00dd00d';
  324. beforeEach(async function () {
  325. this.toWhom = this.receiver.address;
  326. this.transferReceipt = await this.token.safeTransferFrom(
  327. multiTokenHolder,
  328. this.receiver.address,
  329. firstTokenId,
  330. firstAmount,
  331. data,
  332. { from: multiTokenHolder }
  333. );
  334. ({ logs: this.transferLogs } = this.transferReceipt);
  335. });
  336. transferWasSuccessful.call(this, {
  337. operator: multiTokenHolder,
  338. from: multiTokenHolder,
  339. id: firstTokenId,
  340. value: firstAmount,
  341. });
  342. it('calls onERC1155Received', async function () {
  343. await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', {
  344. operator: multiTokenHolder,
  345. from: multiTokenHolder,
  346. id: firstTokenId,
  347. value: firstAmount,
  348. data,
  349. });
  350. });
  351. });
  352. });
  353. context('to a receiver contract returning unexpected value', function () {
  354. beforeEach(async function () {
  355. this.receiver = await ERC1155ReceiverMock.new(
  356. '0x00c0ffee', false,
  357. RECEIVER_BATCH_MAGIC_VALUE, false,
  358. );
  359. });
  360. it('reverts', async function () {
  361. await expectRevert(
  362. this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', {
  363. from: multiTokenHolder,
  364. }),
  365. 'ERC1155: ERC1155Receiver rejected tokens'
  366. );
  367. });
  368. });
  369. context('to a receiver contract that reverts', function () {
  370. beforeEach(async function () {
  371. this.receiver = await ERC1155ReceiverMock.new(
  372. RECEIVER_SINGLE_MAGIC_VALUE, true,
  373. RECEIVER_BATCH_MAGIC_VALUE, false,
  374. );
  375. });
  376. it('reverts', async function () {
  377. await expectRevert(
  378. this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', {
  379. from: multiTokenHolder,
  380. }),
  381. 'ERC1155ReceiverMock: reverting on receive'
  382. );
  383. });
  384. });
  385. context('to a contract that does not implement the required function', function () {
  386. it('reverts', async function () {
  387. const invalidReceiver = this.token;
  388. await expectRevert.unspecified(
  389. this.token.safeTransferFrom(multiTokenHolder, invalidReceiver.address, firstTokenId, firstAmount, '0x', {
  390. from: multiTokenHolder,
  391. })
  392. );
  393. });
  394. });
  395. });
  396. describe('safeBatchTransferFrom', function () {
  397. beforeEach(async function () {
  398. await this.token.mint(multiTokenHolder, firstTokenId, firstAmount, '0x', {
  399. from: minter,
  400. });
  401. await this.token.mint(
  402. multiTokenHolder,
  403. secondTokenId,
  404. secondAmount,
  405. '0x',
  406. {
  407. from: minter,
  408. }
  409. );
  410. });
  411. it('reverts when transferring amount more than any of balances', async function () {
  412. await expectRevert(
  413. this.token.safeBatchTransferFrom(
  414. multiTokenHolder, recipient,
  415. [firstTokenId, secondTokenId],
  416. [firstAmount, secondAmount.addn(1)],
  417. '0x', { from: multiTokenHolder }
  418. ),
  419. 'ERC1155: insufficient balance for transfer'
  420. );
  421. });
  422. it('reverts when ids array length doesn\'t match amounts array length', async function () {
  423. await expectRevert(
  424. this.token.safeBatchTransferFrom(
  425. multiTokenHolder, recipient,
  426. [firstTokenId],
  427. [firstAmount, secondAmount],
  428. '0x', { from: multiTokenHolder }
  429. ),
  430. 'ERC1155: ids and amounts length mismatch'
  431. );
  432. await expectRevert(
  433. this.token.safeBatchTransferFrom(
  434. multiTokenHolder, recipient,
  435. [firstTokenId, secondTokenId],
  436. [firstAmount],
  437. '0x', { from: multiTokenHolder }
  438. ),
  439. 'ERC1155: ids and amounts length mismatch'
  440. );
  441. });
  442. it('reverts when transferring to zero address', async function () {
  443. await expectRevert(
  444. this.token.safeBatchTransferFrom(
  445. multiTokenHolder, ZERO_ADDRESS,
  446. [firstTokenId, secondTokenId],
  447. [firstAmount, secondAmount],
  448. '0x', { from: multiTokenHolder }
  449. ),
  450. 'ERC1155: transfer to the zero address'
  451. );
  452. });
  453. function batchTransferWasSuccessful ({ operator, from, ids, values }) {
  454. it('debits transferred balances from sender', async function () {
  455. const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(from), ids);
  456. for (const newBalance of newBalances) {
  457. expect(newBalance).to.be.a.bignumber.equal('0');
  458. }
  459. });
  460. it('credits transferred balances to receiver', async function () {
  461. const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(this.toWhom), ids);
  462. for (let i = 0; i < newBalances.length; i++) {
  463. expect(newBalances[i]).to.be.a.bignumber.equal(values[i]);
  464. }
  465. });
  466. it('emits a TransferBatch log', function () {
  467. expectEvent.inLogs(this.transferLogs, 'TransferBatch', {
  468. operator,
  469. from,
  470. to: this.toWhom,
  471. // ids,
  472. // values,
  473. });
  474. });
  475. }
  476. context('when called by the multiTokenHolder', async function () {
  477. beforeEach(async function () {
  478. this.toWhom = recipient;
  479. ({ logs: this.transferLogs } =
  480. await this.token.safeBatchTransferFrom(
  481. multiTokenHolder, recipient,
  482. [firstTokenId, secondTokenId],
  483. [firstAmount, secondAmount],
  484. '0x', { from: multiTokenHolder }
  485. ));
  486. });
  487. batchTransferWasSuccessful.call(this, {
  488. operator: multiTokenHolder,
  489. from: multiTokenHolder,
  490. ids: [firstTokenId, secondTokenId],
  491. values: [firstAmount, secondAmount],
  492. });
  493. });
  494. context('when called by an operator on behalf of the multiTokenHolder', function () {
  495. context('when operator is not approved by multiTokenHolder', function () {
  496. beforeEach(async function () {
  497. await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder });
  498. });
  499. it('reverts', async function () {
  500. await expectRevert(
  501. this.token.safeBatchTransferFrom(
  502. multiTokenHolder, recipient,
  503. [firstTokenId, secondTokenId],
  504. [firstAmount, secondAmount],
  505. '0x', { from: proxy }
  506. ),
  507. 'ERC1155: transfer caller is not owner nor approved'
  508. );
  509. });
  510. });
  511. context('when operator is approved by multiTokenHolder', function () {
  512. beforeEach(async function () {
  513. this.toWhom = recipient;
  514. await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder });
  515. ({ logs: this.transferLogs } =
  516. await this.token.safeBatchTransferFrom(
  517. multiTokenHolder, recipient,
  518. [firstTokenId, secondTokenId],
  519. [firstAmount, secondAmount],
  520. '0x', { from: proxy },
  521. ));
  522. });
  523. batchTransferWasSuccessful.call(this, {
  524. operator: proxy,
  525. from: multiTokenHolder,
  526. ids: [firstTokenId, secondTokenId],
  527. values: [firstAmount, secondAmount],
  528. });
  529. it('preserves operator\'s balances not involved in the transfer', async function () {
  530. const balance1 = await this.token.balanceOf(proxy, firstTokenId);
  531. expect(balance1).to.be.a.bignumber.equal('0');
  532. const balance2 = await this.token.balanceOf(proxy, secondTokenId);
  533. expect(balance2).to.be.a.bignumber.equal('0');
  534. });
  535. });
  536. });
  537. context('when sending to a valid receiver', function () {
  538. beforeEach(async function () {
  539. this.receiver = await ERC1155ReceiverMock.new(
  540. RECEIVER_SINGLE_MAGIC_VALUE, false,
  541. RECEIVER_BATCH_MAGIC_VALUE, false,
  542. );
  543. });
  544. context('without data', function () {
  545. beforeEach(async function () {
  546. this.toWhom = this.receiver.address;
  547. this.transferReceipt = await this.token.safeBatchTransferFrom(
  548. multiTokenHolder, this.receiver.address,
  549. [firstTokenId, secondTokenId],
  550. [firstAmount, secondAmount],
  551. '0x', { from: multiTokenHolder },
  552. );
  553. ({ logs: this.transferLogs } = this.transferReceipt);
  554. });
  555. batchTransferWasSuccessful.call(this, {
  556. operator: multiTokenHolder,
  557. from: multiTokenHolder,
  558. ids: [firstTokenId, secondTokenId],
  559. values: [firstAmount, secondAmount],
  560. });
  561. it('calls onERC1155BatchReceived', async function () {
  562. await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', {
  563. operator: multiTokenHolder,
  564. from: multiTokenHolder,
  565. // ids: [firstTokenId, secondTokenId],
  566. // values: [firstAmount, secondAmount],
  567. data: null,
  568. });
  569. });
  570. });
  571. context('with data', function () {
  572. const data = '0xf00dd00d';
  573. beforeEach(async function () {
  574. this.toWhom = this.receiver.address;
  575. this.transferReceipt = await this.token.safeBatchTransferFrom(
  576. multiTokenHolder, this.receiver.address,
  577. [firstTokenId, secondTokenId],
  578. [firstAmount, secondAmount],
  579. data, { from: multiTokenHolder },
  580. );
  581. ({ logs: this.transferLogs } = this.transferReceipt);
  582. });
  583. batchTransferWasSuccessful.call(this, {
  584. operator: multiTokenHolder,
  585. from: multiTokenHolder,
  586. ids: [firstTokenId, secondTokenId],
  587. values: [firstAmount, secondAmount],
  588. });
  589. it('calls onERC1155Received', async function () {
  590. await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', {
  591. operator: multiTokenHolder,
  592. from: multiTokenHolder,
  593. // ids: [firstTokenId, secondTokenId],
  594. // values: [firstAmount, secondAmount],
  595. data,
  596. });
  597. });
  598. });
  599. });
  600. context('to a receiver contract returning unexpected value', function () {
  601. beforeEach(async function () {
  602. this.receiver = await ERC1155ReceiverMock.new(
  603. RECEIVER_SINGLE_MAGIC_VALUE, false,
  604. RECEIVER_SINGLE_MAGIC_VALUE, false,
  605. );
  606. });
  607. it('reverts', async function () {
  608. await expectRevert(
  609. this.token.safeBatchTransferFrom(
  610. multiTokenHolder, this.receiver.address,
  611. [firstTokenId, secondTokenId],
  612. [firstAmount, secondAmount],
  613. '0x', { from: multiTokenHolder },
  614. ),
  615. 'ERC1155: ERC1155Receiver rejected tokens'
  616. );
  617. });
  618. });
  619. context('to a receiver contract that reverts', function () {
  620. beforeEach(async function () {
  621. this.receiver = await ERC1155ReceiverMock.new(
  622. RECEIVER_SINGLE_MAGIC_VALUE, false,
  623. RECEIVER_BATCH_MAGIC_VALUE, true,
  624. );
  625. });
  626. it('reverts', async function () {
  627. await expectRevert(
  628. this.token.safeBatchTransferFrom(
  629. multiTokenHolder, this.receiver.address,
  630. [firstTokenId, secondTokenId],
  631. [firstAmount, secondAmount],
  632. '0x', { from: multiTokenHolder },
  633. ),
  634. 'ERC1155ReceiverMock: reverting on batch receive'
  635. );
  636. });
  637. });
  638. context('to a receiver contract that reverts only on single transfers', function () {
  639. beforeEach(async function () {
  640. this.receiver = await ERC1155ReceiverMock.new(
  641. RECEIVER_SINGLE_MAGIC_VALUE, true,
  642. RECEIVER_BATCH_MAGIC_VALUE, false,
  643. );
  644. this.toWhom = this.receiver.address;
  645. this.transferReceipt = await this.token.safeBatchTransferFrom(
  646. multiTokenHolder, this.receiver.address,
  647. [firstTokenId, secondTokenId],
  648. [firstAmount, secondAmount],
  649. '0x', { from: multiTokenHolder },
  650. );
  651. ({ logs: this.transferLogs } = this.transferReceipt);
  652. });
  653. batchTransferWasSuccessful.call(this, {
  654. operator: multiTokenHolder,
  655. from: multiTokenHolder,
  656. ids: [firstTokenId, secondTokenId],
  657. values: [firstAmount, secondAmount],
  658. });
  659. it('calls onERC1155BatchReceived', async function () {
  660. await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', {
  661. operator: multiTokenHolder,
  662. from: multiTokenHolder,
  663. // ids: [firstTokenId, secondTokenId],
  664. // values: [firstAmount, secondAmount],
  665. data: null,
  666. });
  667. });
  668. });
  669. context('to a contract that does not implement the required function', function () {
  670. it('reverts', async function () {
  671. const invalidReceiver = this.token;
  672. await expectRevert.unspecified(
  673. this.token.safeBatchTransferFrom(
  674. multiTokenHolder, invalidReceiver.address,
  675. [firstTokenId, secondTokenId],
  676. [firstAmount, secondAmount],
  677. '0x', { from: multiTokenHolder },
  678. )
  679. );
  680. });
  681. });
  682. });
  683. shouldSupportInterfaces(['ERC165', 'ERC1155']);
  684. });
  685. }
  686. module.exports = {
  687. shouldBehaveLikeERC1155,
  688. };