ERC1155.behavior.js 27 KB

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