ERC1155.behavior.js 27 KB

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