ERC721Votes.test.js 7.5 KB

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