ERC721Votes.test.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /* eslint-disable */
  2. const { expectEvent, time } = require('@openzeppelin/test-helpers');
  3. const { expect } = require('chai');
  4. const { clock, clockFromReceipt } = require('../../../helpers/time');
  5. const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior');
  6. const MODES = {
  7. blocknumber: artifacts.require('$ERC721Votes'),
  8. // no timestamp mode for ERC721Votes yet
  9. };
  10. contract('ERC721Votes', function (accounts) {
  11. const [account1, account2, other1, other2] = accounts;
  12. const name = 'My Vote';
  13. const symbol = 'MTKN';
  14. const version = '1';
  15. const tokens = ['10000000000000000000000000', '10', '20', '30'].map(n => web3.utils.toBN(n));
  16. for (const [mode, artifact] of Object.entries(MODES)) {
  17. describe(`vote with ${mode}`, function () {
  18. beforeEach(async function () {
  19. this.votes = await artifact.new(name, symbol, name, version);
  20. });
  21. // includes ERC6372 behavior check
  22. shouldBehaveLikeVotes(accounts, tokens, { mode, fungible: false });
  23. describe('balanceOf', function () {
  24. beforeEach(async function () {
  25. await this.votes.$_mint(account1, tokens[0]);
  26. await this.votes.$_mint(account1, tokens[1]);
  27. await this.votes.$_mint(account1, tokens[2]);
  28. await this.votes.$_mint(account1, tokens[3]);
  29. });
  30. it('grants to initial account', async function () {
  31. expect(await this.votes.balanceOf(account1)).to.be.bignumber.equal('4');
  32. });
  33. });
  34. describe('transfers', function () {
  35. beforeEach(async function () {
  36. await this.votes.$_mint(account1, tokens[0]);
  37. });
  38. it('no delegation', async function () {
  39. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  40. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] });
  41. expectEvent.notEmitted(receipt, 'DelegateVotesChanged');
  42. this.account1Votes = '0';
  43. this.account2Votes = '0';
  44. });
  45. it('sender delegation', async function () {
  46. await this.votes.delegate(account1, { from: account1 });
  47. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  48. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] });
  49. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' });
  50. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  51. expect(
  52. receipt.logs
  53. .filter(({ event }) => event == 'DelegateVotesChanged')
  54. .every(({ logIndex }) => transferLogIndex < logIndex),
  55. ).to.be.equal(true);
  56. this.account1Votes = '0';
  57. this.account2Votes = '0';
  58. });
  59. it('receiver delegation', async function () {
  60. await this.votes.delegate(account2, { from: account2 });
  61. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  62. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] });
  63. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '1' });
  64. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  65. expect(
  66. receipt.logs
  67. .filter(({ event }) => event == 'DelegateVotesChanged')
  68. .every(({ logIndex }) => transferLogIndex < logIndex),
  69. ).to.be.equal(true);
  70. this.account1Votes = '0';
  71. this.account2Votes = '1';
  72. });
  73. it('full delegation', async function () {
  74. await this.votes.delegate(account1, { from: account1 });
  75. await this.votes.delegate(account2, { from: account2 });
  76. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  77. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] });
  78. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' });
  79. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '1' });
  80. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  81. expect(
  82. receipt.logs
  83. .filter(({ event }) => event == 'DelegateVotesChanged')
  84. .every(({ logIndex }) => transferLogIndex < logIndex),
  85. ).to.be.equal(true);
  86. this.account1Votes = '0';
  87. this.account2Votes = '1';
  88. });
  89. it('returns the same total supply on transfers', async function () {
  90. await this.votes.delegate(account1, { from: account1 });
  91. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  92. const timepoint = await clockFromReceipt[mode](receipt);
  93. await time.advanceBlock();
  94. await time.advanceBlock();
  95. expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('1');
  96. expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1');
  97. this.account1Votes = '0';
  98. this.account2Votes = '0';
  99. });
  100. it('generally returns the voting balance at the appropriate checkpoint', async function () {
  101. await this.votes.$_mint(account1, tokens[1]);
  102. await this.votes.$_mint(account1, tokens[2]);
  103. await this.votes.$_mint(account1, tokens[3]);
  104. const total = await this.votes.balanceOf(account1);
  105. const t1 = await this.votes.delegate(other1, { from: account1 });
  106. await time.advanceBlock();
  107. await time.advanceBlock();
  108. const t2 = await this.votes.transferFrom(account1, other2, tokens[0], { from: account1 });
  109. await time.advanceBlock();
  110. await time.advanceBlock();
  111. const t3 = await this.votes.transferFrom(account1, other2, tokens[2], { from: account1 });
  112. await time.advanceBlock();
  113. await time.advanceBlock();
  114. const t4 = await this.votes.transferFrom(other2, account1, tokens[2], { from: other2 });
  115. await time.advanceBlock();
  116. await time.advanceBlock();
  117. t1.timepoint = await clockFromReceipt[mode](t1.receipt);
  118. t2.timepoint = await clockFromReceipt[mode](t2.receipt);
  119. t3.timepoint = await clockFromReceipt[mode](t3.receipt);
  120. t4.timepoint = await clockFromReceipt[mode](t4.receipt);
  121. expect(await this.votes.getPastVotes(other1, t1.timepoint - 1)).to.be.bignumber.equal('0');
  122. expect(await this.votes.getPastVotes(other1, t1.timepoint)).to.be.bignumber.equal(total);
  123. expect(await this.votes.getPastVotes(other1, t1.timepoint + 1)).to.be.bignumber.equal(total);
  124. expect(await this.votes.getPastVotes(other1, t2.timepoint)).to.be.bignumber.equal('3');
  125. expect(await this.votes.getPastVotes(other1, t2.timepoint + 1)).to.be.bignumber.equal('3');
  126. expect(await this.votes.getPastVotes(other1, t3.timepoint)).to.be.bignumber.equal('2');
  127. expect(await this.votes.getPastVotes(other1, t3.timepoint + 1)).to.be.bignumber.equal('2');
  128. expect(await this.votes.getPastVotes(other1, t4.timepoint)).to.be.bignumber.equal('3');
  129. expect(await this.votes.getPastVotes(other1, t4.timepoint + 1)).to.be.bignumber.equal('3');
  130. this.account1Votes = '0';
  131. this.account2Votes = '0';
  132. });
  133. afterEach(async function () {
  134. expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes);
  135. expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes);
  136. // need to advance 2 blocks to see the effect of a transfer on "getPastVotes"
  137. const timepoint = await clock[mode]();
  138. await time.advanceBlock();
  139. expect(await this.votes.getPastVotes(account1, timepoint)).to.be.bignumber.equal(this.account1Votes);
  140. expect(await this.votes.getPastVotes(account2, timepoint)).to.be.bignumber.equal(this.account2Votes);
  141. });
  142. });
  143. });
  144. }
  145. });