ERC721Consecutive.test.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const ERC721ConsecutiveMock = artifacts.require('ERC721ConsecutiveMock');
  4. const ERC721ConsecutiveEnumerableMock = artifacts.require('ERC721ConsecutiveEnumerableMock');
  5. const ERC721ConsecutiveNoConstructorMintMock = artifacts.require('ERC721ConsecutiveNoConstructorMintMock');
  6. contract('ERC721Consecutive', function (accounts) {
  7. const [ user1, user2, user3, receiver ] = accounts;
  8. const name = 'Non Fungible Token';
  9. const symbol = 'NFT';
  10. const batches = [
  11. { receiver: user1, amount: 0 },
  12. { receiver: user1, amount: 1 },
  13. { receiver: user1, amount: 2 },
  14. { receiver: user2, amount: 5 },
  15. { receiver: user3, amount: 0 },
  16. { receiver: user1, amount: 7 },
  17. ];
  18. const delegates = [ user1, user3 ];
  19. describe('with valid batches', function () {
  20. beforeEach(async function () {
  21. this.token = await ERC721ConsecutiveMock.new(
  22. name,
  23. symbol,
  24. delegates,
  25. batches.map(({ receiver }) => receiver),
  26. batches.map(({ amount }) => amount),
  27. );
  28. });
  29. describe('minting during construction', function () {
  30. it('events are emitted at construction', async function () {
  31. let first = 0;
  32. for (const batch of batches) {
  33. if (batch.amount > 0) {
  34. await expectEvent.inConstruction(this.token, 'ConsecutiveTransfer', {
  35. fromTokenId: web3.utils.toBN(first),
  36. toTokenId: web3.utils.toBN(first + batch.amount - 1),
  37. fromAddress: constants.ZERO_ADDRESS,
  38. toAddress: batch.receiver,
  39. });
  40. } else {
  41. // expectEvent.notEmitted.inConstruction only looks at event name, and doesn't check the parameters
  42. }
  43. first += batch.amount;
  44. }
  45. });
  46. it('ownership is set', async function () {
  47. const owners = batches.flatMap(({ receiver, amount }) => Array(amount).fill(receiver));
  48. for (const tokenId in owners) {
  49. expect(await this.token.ownerOf(tokenId))
  50. .to.be.equal(owners[tokenId]);
  51. }
  52. });
  53. it('balance & voting power are set', async function () {
  54. for (const account of accounts) {
  55. const balance = batches
  56. .filter(({ receiver }) => receiver === account)
  57. .map(({ amount }) => amount)
  58. .reduce((a, b) => a + b, 0);
  59. expect(await this.token.balanceOf(account))
  60. .to.be.bignumber.equal(web3.utils.toBN(balance));
  61. // If not delegated at construction, check before + do delegation
  62. if (!delegates.includes(account)) {
  63. expect(await this.token.getVotes(account))
  64. .to.be.bignumber.equal(web3.utils.toBN(0));
  65. await this.token.delegate(account, { from: account });
  66. }
  67. // At this point all accounts should have delegated
  68. expect(await this.token.getVotes(account))
  69. .to.be.bignumber.equal(web3.utils.toBN(balance));
  70. }
  71. });
  72. });
  73. describe('minting after construction', function () {
  74. it('consecutive minting is not possible after construction', async function () {
  75. await expectRevert(
  76. this.token.mintConsecutive(user1, 10),
  77. 'ERC721Consecutive: batch minting restricted to constructor',
  78. );
  79. });
  80. it('simple minting is possible after construction', async function () {
  81. const tokenId = batches.reduce((acc, { amount }) => acc + amount, 0);
  82. expect(await this.token.exists(tokenId)).to.be.equal(false);
  83. expectEvent(
  84. await this.token.mint(user1, tokenId),
  85. 'Transfer',
  86. { from: constants.ZERO_ADDRESS, to: user1, tokenId: tokenId.toString() },
  87. );
  88. });
  89. it('cannot mint a token that has been batched minted', async function () {
  90. const tokenId = batches.reduce((acc, { amount }) => acc + amount, 0) - 1;
  91. expect(await this.token.exists(tokenId)).to.be.equal(true);
  92. await expectRevert(
  93. this.token.mint(user1, tokenId),
  94. 'ERC721: token already minted',
  95. );
  96. });
  97. });
  98. describe('ERC721 behavior', function () {
  99. it('core takes over ownership on transfer', async function () {
  100. await this.token.transferFrom(user1, receiver, 1, { from: user1 });
  101. expect(await this.token.ownerOf(1)).to.be.equal(receiver);
  102. });
  103. it('tokens can be burned and re-minted #1', async function () {
  104. expectEvent(
  105. await this.token.burn(1, { from: user1 }),
  106. 'Transfer',
  107. { from: user1, to: constants.ZERO_ADDRESS, tokenId: '1' },
  108. );
  109. await expectRevert(this.token.ownerOf(1), 'ERC721: invalid token ID');
  110. expectEvent(
  111. await this.token.mint(user2, 1),
  112. 'Transfer',
  113. { from: constants.ZERO_ADDRESS, to: user2, tokenId: '1' },
  114. );
  115. expect(await this.token.ownerOf(1)).to.be.equal(user2);
  116. });
  117. it('tokens can be burned and re-minted #2', async function () {
  118. const tokenId = batches.reduce((acc, { amount }) => acc.addn(amount), web3.utils.toBN(0));
  119. expect(await this.token.exists(tokenId)).to.be.equal(false);
  120. await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID');
  121. // mint
  122. await this.token.mint(user1, tokenId);
  123. expect(await this.token.exists(tokenId)).to.be.equal(true);
  124. expect(await this.token.ownerOf(tokenId), user1);
  125. // burn
  126. expectEvent(
  127. await this.token.burn(tokenId, { from: user1 }),
  128. 'Transfer',
  129. { from: user1, to: constants.ZERO_ADDRESS, tokenId },
  130. );
  131. expect(await this.token.exists(tokenId)).to.be.equal(false);
  132. await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID');
  133. // re-mint
  134. expectEvent(
  135. await this.token.mint(user2, tokenId),
  136. 'Transfer',
  137. { from: constants.ZERO_ADDRESS, to: user2, tokenId },
  138. );
  139. expect(await this.token.exists(tokenId)).to.be.equal(true);
  140. expect(await this.token.ownerOf(tokenId), user2);
  141. });
  142. });
  143. });
  144. describe('invalid use', function () {
  145. it('cannot mint a batch larger than 5000', async function () {
  146. await expectRevert(
  147. ERC721ConsecutiveMock.new(
  148. name,
  149. symbol,
  150. [],
  151. [user1],
  152. ['5001'],
  153. ),
  154. 'ERC721Consecutive: batch too large',
  155. );
  156. });
  157. it('cannot use single minting during construction', async function () {
  158. await expectRevert(
  159. ERC721ConsecutiveNoConstructorMintMock.new(
  160. name,
  161. symbol,
  162. ),
  163. 'ERC721Consecutive: can\'t mint during construction',
  164. );
  165. });
  166. it('cannot use single minting during construction', async function () {
  167. await expectRevert(
  168. ERC721ConsecutiveNoConstructorMintMock.new(
  169. name,
  170. symbol,
  171. ),
  172. 'ERC721Consecutive: can\'t mint during construction',
  173. );
  174. });
  175. it('consecutive mint not compatible with enumerability', async function () {
  176. await expectRevert(
  177. ERC721ConsecutiveEnumerableMock.new(
  178. name,
  179. symbol,
  180. batches.map(({ receiver }) => receiver),
  181. batches.map(({ amount }) => amount),
  182. ),
  183. 'ERC721Enumerable: consecutive transfers not supported',
  184. );
  185. });
  186. });
  187. });