Governor.test.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const ethSigUtil = require('eth-sig-util');
  4. const Wallet = require('ethereumjs-wallet').default;
  5. const { fromRpcSig } = require('ethereumjs-util');
  6. const Enums = require('../helpers/enums');
  7. const { EIP712Domain } = require('../helpers/eip712');
  8. const { GovernorHelper } = require('../helpers/governance');
  9. const {
  10. shouldSupportInterfaces,
  11. } = require('../utils/introspection/SupportsInterface.behavior');
  12. const Token = artifacts.require('ERC20VotesMock');
  13. const Governor = artifacts.require('GovernorMock');
  14. const CallReceiver = artifacts.require('CallReceiverMock');
  15. const ERC721Mock = artifacts.require('ERC721Mock');
  16. const ERC1155Mock = artifacts.require('ERC1155Mock');
  17. contract('Governor', function (accounts) {
  18. const [ owner, proposer, voter1, voter2, voter3, voter4 ] = accounts;
  19. const empty = web3.utils.toChecksumAddress(web3.utils.randomHex(20));
  20. const name = 'OZ-Governor';
  21. const version = '1';
  22. const tokenName = 'MockToken';
  23. const tokenSymbol = 'MTKN';
  24. const tokenSupply = web3.utils.toWei('100');
  25. const votingDelay = new BN(4);
  26. const votingPeriod = new BN(16);
  27. const value = web3.utils.toWei('1');
  28. beforeEach(async function () {
  29. this.chainId = await web3.eth.getChainId();
  30. this.token = await Token.new(tokenName, tokenSymbol);
  31. this.mock = await Governor.new(name, this.token.address, votingDelay, votingPeriod, 10);
  32. this.receiver = await CallReceiver.new();
  33. this.helper = new GovernorHelper(this.mock);
  34. await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value });
  35. await this.token.mint(owner, tokenSupply);
  36. await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner });
  37. await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner });
  38. await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner });
  39. await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner });
  40. this.proposal = this.helper.setProposal([
  41. {
  42. target: this.receiver.address,
  43. data: this.receiver.contract.methods.mockFunction().encodeABI(),
  44. value,
  45. },
  46. ], '<proposal description>');
  47. });
  48. shouldSupportInterfaces([
  49. 'ERC165',
  50. 'ERC1155Receiver',
  51. 'Governor',
  52. 'GovernorWithParams',
  53. ]);
  54. it('deployment check', async function () {
  55. expect(await this.mock.name()).to.be.equal(name);
  56. expect(await this.mock.token()).to.be.equal(this.token.address);
  57. expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay);
  58. expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod);
  59. expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
  60. expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=for,abstain');
  61. });
  62. it('nominal workflow', async function () {
  63. // Before
  64. expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false);
  65. expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false);
  66. expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false);
  67. expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(value);
  68. expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0');
  69. // Run proposal
  70. const txPropose = await this.helper.propose({ from: proposer });
  71. expectEvent(
  72. txPropose,
  73. 'ProposalCreated',
  74. {
  75. proposalId: this.proposal.id,
  76. proposer,
  77. targets: this.proposal.targets,
  78. // values: this.proposal.values,
  79. signatures: this.proposal.signatures,
  80. calldatas: this.proposal.data,
  81. startBlock: new BN(txPropose.receipt.blockNumber).add(votingDelay),
  82. endBlock: new BN(txPropose.receipt.blockNumber).add(votingDelay).add(votingPeriod),
  83. description: this.proposal.description,
  84. },
  85. );
  86. await this.helper.waitForSnapshot();
  87. expectEvent(
  88. await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }),
  89. 'VoteCast',
  90. {
  91. voter: voter1,
  92. support: Enums.VoteType.For,
  93. reason: 'This is nice',
  94. weight: web3.utils.toWei('10'),
  95. },
  96. );
  97. expectEvent(
  98. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }),
  99. 'VoteCast',
  100. {
  101. voter: voter2,
  102. support: Enums.VoteType.For,
  103. weight: web3.utils.toWei('7'),
  104. },
  105. );
  106. expectEvent(
  107. await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }),
  108. 'VoteCast',
  109. {
  110. voter: voter3,
  111. support: Enums.VoteType.Against,
  112. weight: web3.utils.toWei('5'),
  113. },
  114. );
  115. expectEvent(
  116. await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }),
  117. 'VoteCast',
  118. {
  119. voter: voter4,
  120. support: Enums.VoteType.Abstain,
  121. weight: web3.utils.toWei('2'),
  122. },
  123. );
  124. await this.helper.waitForDeadline();
  125. const txExecute = await this.helper.execute();
  126. expectEvent(
  127. txExecute,
  128. 'ProposalExecuted',
  129. { proposalId: this.proposal.id },
  130. );
  131. await expectEvent.inTransaction(
  132. txExecute.tx,
  133. this.receiver,
  134. 'MockFunctionCalled',
  135. );
  136. // After
  137. expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false);
  138. expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true);
  139. expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true);
  140. expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0');
  141. expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value);
  142. });
  143. it('vote with signature', async function () {
  144. const voterBySig = Wallet.generate();
  145. const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString());
  146. const signature = async (message) => {
  147. return fromRpcSig(ethSigUtil.signTypedMessage(
  148. voterBySig.getPrivateKey(),
  149. {
  150. data: {
  151. types: {
  152. EIP712Domain,
  153. Ballot: [
  154. { name: 'proposalId', type: 'uint256' },
  155. { name: 'support', type: 'uint8' },
  156. ],
  157. },
  158. domain: { name, version, chainId: this.chainId, verifyingContract: this.mock.address },
  159. primaryType: 'Ballot',
  160. message,
  161. },
  162. },
  163. ));
  164. };
  165. await this.token.delegate(voterBySigAddress, { from: voter1 });
  166. // Run proposal
  167. await this.helper.propose();
  168. await this.helper.waitForSnapshot();
  169. expectEvent(
  170. await this.helper.vote({ support: Enums.VoteType.For, signature }),
  171. 'VoteCast',
  172. { voter: voterBySigAddress, support: Enums.VoteType.For },
  173. );
  174. await this.helper.waitForDeadline();
  175. await this.helper.execute();
  176. // After
  177. expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false);
  178. expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false);
  179. expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false);
  180. expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true);
  181. });
  182. it('send ethers', async function () {
  183. this.proposal = this.helper.setProposal([
  184. {
  185. target: empty,
  186. value,
  187. },
  188. ], '<proposal description>');
  189. // Before
  190. expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(value);
  191. expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal('0');
  192. // Run proposal
  193. await this.helper.propose();
  194. await this.helper.waitForSnapshot();
  195. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  196. await this.helper.waitForDeadline();
  197. await this.helper.execute();
  198. // After
  199. expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0');
  200. expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal(value);
  201. });
  202. describe('should revert', function () {
  203. describe('on propose', function () {
  204. it('if proposal already exists', async function () {
  205. await this.helper.propose();
  206. await expectRevert(this.helper.propose(), 'Governor: proposal already exists');
  207. });
  208. });
  209. describe('on vote', function () {
  210. it('if proposal does not exist', async function () {
  211. await expectRevert(
  212. this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }),
  213. 'Governor: unknown proposal id',
  214. );
  215. });
  216. it('if voting has not started', async function () {
  217. await this.helper.propose();
  218. await expectRevert(
  219. this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }),
  220. 'Governor: vote not currently active',
  221. );
  222. });
  223. it('if support value is invalid', async function () {
  224. await this.helper.propose();
  225. await this.helper.waitForSnapshot();
  226. await expectRevert(
  227. this.helper.vote({ support: new BN('255') }),
  228. 'GovernorVotingSimple: invalid value for enum VoteType',
  229. );
  230. });
  231. it('if vote was already casted', async function () {
  232. await this.helper.propose();
  233. await this.helper.waitForSnapshot();
  234. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  235. await expectRevert(
  236. this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }),
  237. 'GovernorVotingSimple: vote already cast',
  238. );
  239. });
  240. it('if voting is over', async function () {
  241. await this.helper.propose();
  242. await this.helper.waitForDeadline();
  243. await expectRevert(
  244. this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }),
  245. 'Governor: vote not currently active',
  246. );
  247. });
  248. });
  249. describe('on execute', function () {
  250. it('if proposal does not exist', async function () {
  251. await expectRevert(this.helper.execute(), 'Governor: unknown proposal id');
  252. });
  253. it('if quorum is not reached', async function () {
  254. await this.helper.propose();
  255. await this.helper.waitForSnapshot();
  256. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter3 });
  257. await expectRevert(this.helper.execute(), 'Governor: proposal not successful');
  258. });
  259. it('if score not reached', async function () {
  260. await this.helper.propose();
  261. await this.helper.waitForSnapshot();
  262. await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter1 });
  263. await expectRevert(this.helper.execute(), 'Governor: proposal not successful');
  264. });
  265. it('if voting is not over', async function () {
  266. await this.helper.propose();
  267. await this.helper.waitForSnapshot();
  268. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  269. await expectRevert(this.helper.execute(), 'Governor: proposal not successful');
  270. });
  271. it('if receiver revert without reason', async function () {
  272. this.proposal = this.helper.setProposal([
  273. {
  274. target: this.receiver.address,
  275. data: this.receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI(),
  276. },
  277. ], '<proposal description>');
  278. await this.helper.propose();
  279. await this.helper.waitForSnapshot();
  280. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  281. await this.helper.waitForDeadline();
  282. await expectRevert(this.helper.execute(), 'Governor: call reverted without message');
  283. });
  284. it('if receiver revert with reason', async function () {
  285. this.proposal = this.helper.setProposal([
  286. {
  287. target: this.receiver.address,
  288. data: this.receiver.contract.methods.mockFunctionRevertsReason().encodeABI(),
  289. },
  290. ], '<proposal description>');
  291. await this.helper.propose();
  292. await this.helper.waitForSnapshot();
  293. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  294. await this.helper.waitForDeadline();
  295. await expectRevert(this.helper.execute(), 'CallReceiverMock: reverting');
  296. });
  297. it('if proposal was already executed', async function () {
  298. await this.helper.propose();
  299. await this.helper.waitForSnapshot();
  300. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  301. await this.helper.waitForDeadline();
  302. await this.helper.execute();
  303. await expectRevert(this.helper.execute(), 'Governor: proposal not successful');
  304. });
  305. });
  306. });
  307. describe('state', function () {
  308. it('Unset', async function () {
  309. await expectRevert(this.mock.state(this.proposal.id), 'Governor: unknown proposal id');
  310. });
  311. it('Pending & Active', async function () {
  312. await this.helper.propose();
  313. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Pending);
  314. await this.helper.waitForSnapshot();
  315. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Pending);
  316. await this.helper.waitForSnapshot(+1);
  317. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active);
  318. });
  319. it('Defeated', async function () {
  320. await this.helper.propose();
  321. await this.helper.waitForDeadline();
  322. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active);
  323. await this.helper.waitForDeadline(+1);
  324. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Defeated);
  325. });
  326. it('Succeeded', async function () {
  327. await this.helper.propose();
  328. await this.helper.waitForSnapshot();
  329. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  330. await this.helper.waitForDeadline();
  331. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active);
  332. await this.helper.waitForDeadline(+1);
  333. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded);
  334. });
  335. it('Executed', async function () {
  336. await this.helper.propose();
  337. await this.helper.waitForSnapshot();
  338. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  339. await this.helper.waitForDeadline();
  340. await this.helper.execute();
  341. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Executed);
  342. });
  343. });
  344. describe('cancel', function () {
  345. it('before proposal', async function () {
  346. await expectRevert(this.helper.cancel(), 'Governor: unknown proposal id');
  347. });
  348. it('after proposal', async function () {
  349. await this.helper.propose();
  350. await this.helper.cancel();
  351. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
  352. await this.helper.waitForSnapshot();
  353. await expectRevert(
  354. this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }),
  355. 'Governor: vote not currently active',
  356. );
  357. });
  358. it('after vote', async function () {
  359. await this.helper.propose();
  360. await this.helper.waitForSnapshot();
  361. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  362. await this.helper.cancel();
  363. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
  364. await this.helper.waitForDeadline();
  365. await expectRevert(this.helper.execute(), 'Governor: proposal not successful');
  366. });
  367. it('after deadline', async function () {
  368. await this.helper.propose();
  369. await this.helper.waitForSnapshot();
  370. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  371. await this.helper.waitForDeadline();
  372. await this.helper.cancel();
  373. expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
  374. await expectRevert(this.helper.execute(), 'Governor: proposal not successful');
  375. });
  376. it('after execution', async function () {
  377. await this.helper.propose();
  378. await this.helper.waitForSnapshot();
  379. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  380. await this.helper.waitForDeadline();
  381. await this.helper.execute();
  382. await expectRevert(this.helper.cancel(), 'Governor: proposal not active');
  383. });
  384. });
  385. describe('proposal length', function () {
  386. it('empty', async function () {
  387. this.helper.setProposal([ ], '<proposal description>');
  388. await expectRevert(this.helper.propose(), 'Governor: empty proposal');
  389. });
  390. it('mismatch #1', async function () {
  391. this.helper.setProposal({
  392. targets: [ ],
  393. values: [ web3.utils.toWei('0') ],
  394. data: [ this.receiver.contract.methods.mockFunction().encodeABI() ],
  395. }, '<proposal description>');
  396. await expectRevert(this.helper.propose(), 'Governor: invalid proposal length');
  397. });
  398. it('mismatch #2', async function () {
  399. this.helper.setProposal({
  400. targets: [ this.receiver.address ],
  401. values: [ ],
  402. data: [ this.receiver.contract.methods.mockFunction().encodeABI() ],
  403. }, '<proposal description>');
  404. await expectRevert(this.helper.propose(), 'Governor: invalid proposal length');
  405. });
  406. it('mismatch #3', async function () {
  407. this.helper.setProposal({
  408. targets: [ this.receiver.address ],
  409. values: [ web3.utils.toWei('0') ],
  410. data: [ ],
  411. }, '<proposal description>');
  412. await expectRevert(this.helper.propose(), 'Governor: invalid proposal length');
  413. });
  414. });
  415. describe('onlyGovernance updates', function () {
  416. it('setVotingDelay is protected', async function () {
  417. await expectRevert(this.mock.setVotingDelay('0'), 'Governor: onlyGovernance');
  418. });
  419. it('setVotingPeriod is protected', async function () {
  420. await expectRevert(this.mock.setVotingPeriod('32'), 'Governor: onlyGovernance');
  421. });
  422. it('setProposalThreshold is protected', async function () {
  423. await expectRevert(this.mock.setProposalThreshold('1000000000000000000'), 'Governor: onlyGovernance');
  424. });
  425. it('can setVotingDelay through governance', async function () {
  426. this.helper.setProposal([
  427. {
  428. target: this.mock.address,
  429. data: this.mock.contract.methods.setVotingDelay('0').encodeABI(),
  430. },
  431. ], '<proposal description>');
  432. await this.helper.propose();
  433. await this.helper.waitForSnapshot();
  434. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  435. await this.helper.waitForDeadline();
  436. expectEvent(
  437. await this.helper.execute(),
  438. 'VotingDelaySet',
  439. { oldVotingDelay: '4', newVotingDelay: '0' },
  440. );
  441. expect(await this.mock.votingDelay()).to.be.bignumber.equal('0');
  442. });
  443. it('can setVotingPeriod through governance', async function () {
  444. this.helper.setProposal([
  445. {
  446. target: this.mock.address,
  447. data: this.mock.contract.methods.setVotingPeriod('32').encodeABI(),
  448. },
  449. ], '<proposal description>');
  450. await this.helper.propose();
  451. await this.helper.waitForSnapshot();
  452. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  453. await this.helper.waitForDeadline();
  454. expectEvent(
  455. await this.helper.execute(),
  456. 'VotingPeriodSet',
  457. { oldVotingPeriod: '16', newVotingPeriod: '32' },
  458. );
  459. expect(await this.mock.votingPeriod()).to.be.bignumber.equal('32');
  460. });
  461. it('cannot setVotingPeriod to 0 through governance', async function () {
  462. this.helper.setProposal([
  463. {
  464. target: this.mock.address,
  465. data: this.mock.contract.methods.setVotingPeriod('0').encodeABI(),
  466. },
  467. ], '<proposal description>');
  468. await this.helper.propose();
  469. await this.helper.waitForSnapshot();
  470. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  471. await this.helper.waitForDeadline();
  472. await expectRevert(this.helper.execute(), 'GovernorSettings: voting period too low');
  473. });
  474. it('can setProposalThreshold to 0 through governance', async function () {
  475. this.helper.setProposal([
  476. {
  477. target: this.mock.address,
  478. data: this.mock.contract.methods.setProposalThreshold('1000000000000000000').encodeABI(),
  479. },
  480. ], '<proposal description>');
  481. await this.helper.propose();
  482. await this.helper.waitForSnapshot();
  483. await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 });
  484. await this.helper.waitForDeadline();
  485. expectEvent(
  486. await this.helper.execute(),
  487. 'ProposalThresholdSet',
  488. { oldProposalThreshold: '0', newProposalThreshold: '1000000000000000000' },
  489. );
  490. expect(await this.mock.proposalThreshold()).to.be.bignumber.equal('1000000000000000000');
  491. });
  492. });
  493. describe('safe receive', function () {
  494. describe('ERC721', function () {
  495. const name = 'Non Fungible Token';
  496. const symbol = 'NFT';
  497. const tokenId = new BN(1);
  498. beforeEach(async function () {
  499. this.token = await ERC721Mock.new(name, symbol);
  500. await this.token.mint(owner, tokenId);
  501. });
  502. it('can receive an ERC721 safeTransfer', async function () {
  503. await this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner });
  504. });
  505. });
  506. describe('ERC1155', function () {
  507. const uri = 'https://token-cdn-domain/{id}.json';
  508. const tokenIds = {
  509. 1: new BN(1000),
  510. 2: new BN(2000),
  511. 3: new BN(3000),
  512. };
  513. beforeEach(async function () {
  514. this.token = await ERC1155Mock.new(uri);
  515. await this.token.mintBatch(owner, Object.keys(tokenIds), Object.values(tokenIds), '0x');
  516. });
  517. it('can receive ERC1155 safeTransfer', async function () {
  518. await this.token.safeTransferFrom(
  519. owner,
  520. this.mock.address,
  521. ...Object.entries(tokenIds)[0], // id + amount
  522. '0x',
  523. { from: owner },
  524. );
  525. });
  526. it('can receive ERC1155 safeBatchTransfer', async function () {
  527. await this.token.safeBatchTransferFrom(
  528. owner,
  529. this.mock.address,
  530. Object.keys(tokenIds),
  531. Object.values(tokenIds),
  532. '0x',
  533. { from: owner },
  534. );
  535. });
  536. });
  537. });
  538. });