ERC1155.behavior.js 27 KB

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