Governor.test.js 23 KB

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