ERC721Votes.test.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* eslint-disable */
  2. const { expectEvent, time } = require('@openzeppelin/test-helpers');
  3. const { expect } = require('chai');
  4. const ERC721VotesMock = artifacts.require('ERC721VotesMock');
  5. const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior');
  6. contract('ERC721Votes', function (accounts) {
  7. const [ account1, account2, account1Delegatee, other1, other2 ] = accounts;
  8. const name = 'My Vote';
  9. const symbol = 'MTKN';
  10. const tokens = [
  11. '10000000000000000000000000',
  12. '10',
  13. '20',
  14. '30',
  15. ].map(n => web3.utils.toBN(n));
  16. beforeEach(async function () {
  17. this.votes = await ERC721VotesMock.new(name, symbol);
  18. // We get the chain id from the contract because Ganache (used for coverage) does not return the same chain id
  19. // from within the EVM as from the JSON RPC interface.
  20. // See https://github.com/trufflesuite/ganache-core/issues/515
  21. this.chainId = await this.votes.getChainId();
  22. });
  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, previousBalance: '1', newBalance: '0' });
  50. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  51. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  52. this.account1Votes = '0';
  53. this.account2Votes = '0';
  54. });
  55. it('receiver delegation', async function () {
  56. await this.votes.delegate(account2, { from: account2 });
  57. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  58. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] });
  59. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousBalance: '0', newBalance: '1' });
  60. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  61. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  62. this.account1Votes = '0';
  63. this.account2Votes = '1';
  64. });
  65. it('full delegation', async function () {
  66. await this.votes.delegate(account1, { from: account1 });
  67. await this.votes.delegate(account2, { from: account2 });
  68. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  69. expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] });
  70. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0'});
  71. expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousBalance: '0', newBalance: '1' });
  72. const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
  73. expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
  74. this.account1Votes = '0';
  75. this.account2Votes = '1';
  76. });
  77. it('returns the same total supply on transfers', async function () {
  78. await this.votes.delegate(account1, { from: account1 });
  79. const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 });
  80. await time.advanceBlock();
  81. await time.advanceBlock();
  82. expect(await this.votes.getPastTotalSupply(receipt.blockNumber - 1)).to.be.bignumber.equal('1');
  83. expect(await this.votes.getPastTotalSupply(receipt.blockNumber + 1)).to.be.bignumber.equal('1');
  84. this.account1Votes = '0';
  85. this.account2Votes = '0';
  86. });
  87. it('generally returns the voting balance at the appropriate checkpoint', async function () {
  88. await this.votes.mint(account1, tokens[1]);
  89. await this.votes.mint(account1, tokens[2]);
  90. await this.votes.mint(account1, tokens[3]);
  91. const total = await this.votes.balanceOf(account1);
  92. const t1 = await this.votes.delegate(other1, { from: account1 });
  93. await time.advanceBlock();
  94. await time.advanceBlock();
  95. const t2 = await this.votes.transferFrom(account1, other2, tokens[0], { from: account1 });
  96. await time.advanceBlock();
  97. await time.advanceBlock();
  98. const t3 = await this.votes.transferFrom(account1, other2, tokens[2], { from: account1 });
  99. await time.advanceBlock();
  100. await time.advanceBlock();
  101. const t4 = await this.votes.transferFrom(other2, account1, tokens[2], { from: other2 });
  102. await time.advanceBlock();
  103. await time.advanceBlock();
  104. expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0');
  105. expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal(total);
  106. expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal(total);
  107. expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('3');
  108. expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal('3');
  109. expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('2');
  110. expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal('2');
  111. expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('3');
  112. expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal('3');
  113. this.account1Votes = '0';
  114. this.account2Votes = '0';
  115. });
  116. afterEach(async function () {
  117. expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes);
  118. expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes);
  119. // need to advance 2 blocks to see the effect of a transfer on "getPastVotes"
  120. const blockNumber = await time.latestBlock();
  121. await time.advanceBlock();
  122. expect(await this.votes.getPastVotes(account1, blockNumber)).to.be.bignumber.equal(this.account1Votes);
  123. expect(await this.votes.getPastVotes(account2, blockNumber)).to.be.bignumber.equal(this.account2Votes);
  124. });
  125. });
  126. describe('Voting workflow', function () {
  127. beforeEach(async function () {
  128. this.name = name;
  129. });
  130. shouldBehaveLikeVotes(accounts, tokens, false);
  131. });
  132. });